MCPで学ぶAWS開発入門 - アイデアから実装までの最短距離
AWS、Stripeといったクラウドサービスを使いこなすのは、初心者にとって大きなハードルです。ドキュメントは膨大で、正しい実装方法を見つけるだけでも時間がかかります。「実際に動くものを作りながら学びたい」と思っても、どこから手をつければいいのか迷ってしまうことでしょう。
Model Context Protocol (MCP)は、そんな初心者の強い味方になります。MCPを使えば、AIがドキュメントを参照しながら実装を進めてくれるため、動くシステムを短時間で作りながら学習できます。この記事では、StripeとAWSを組み合わせた決済システムを例に、MCPを活用した学習方法と実装のポイントを紹介します。
MCPとは - 動かしながら学ぶための新しいツール
MCPは、AIがサービスの公式ドキュメントを参照しながらコードを生成してくれる開発支援ツールです。例えば、AWS MCPやStripe MCPを使えば、それぞれのサービスの最新APIや機能を活用したコードを、AIが自動的に作成してくれます。
特に初心者にとってのMCPの魅力は、以下の点にあります:
- 実際に動くコードから学べる: 理論だけでなく、動作するコードを見ながら学習できる
- 最新の情報に基づいた実装: 公式ドキュメントを参照するため、古い情報に惑わされない
- 全体像の把握: システム設計から実装まで、一連の流れを体験できる
- 試行錯誤の容易さ: 指示を変えるだけで、異なる実装方法を簡単に試せる
MCPは本番環境で長期運用するコードを作るというよりも、「アイデアを形にする」「学習のために実装を進める」という目的に最適なツールなのです。
実例:Stripe決済システムを作りながらAWSを学ぶ
具体的な例として、StripeとAWS Lambdaを組み合わせたシンプルな決済システムを実装してみましょう。このプロジェクトを通じて、以下のようなAWSの基本概念を学ぶことができます:
- サーバーレスアーキテクチャの基本
- AWS Lambda関数の作成と実行
- Lambda Function URLの設定
- DynamoDBによるデータ保存
- AWS CDKを使ったインフラのコード化
ステップ1: 環境準備とMCPの設定
まずは、MCPを使うための環境を整えましょう。今回は以下の2つが事前に必要となります。
- uv: Pythonパッケージマネージャー
- nvm: Node.jsパッケージマネージャー
uvのインストール
AWSが提供するMCPは、Pythonパッケージマネージャーの「uv」を使用します。まずはこちらをインストールしましょう。
curl -LsSf https://astral.sh/uv/install.sh | sh
source $HOME/.local/bin/env
インストールが完了したら、バージョンを確認してみます:
uv --version
# 出力例: uv 0.6.13 (a0f5c7250 2025-04-07)
続いてuv
を使ってPythonをインストールします:
uv python install 3.10
# 出力例: Installed Python 3.10.16 in 1.53s
# + cpython-3.10.16-macos-aarch64-none
nvmのインストール
Node.jsの環境管理には、nvmを使います。
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.2/install.sh | bash
Node.jsのバージョンを指定してインストールしましょう。
nvm use 20
次に、Claude DesktopアプリにMCPサーバーを設定します。MCPの設定はmacOSでは~/Library/Application\ Support/Claude/claude_desktop_config.json
にあります。
エディタでclaude_desktop_config.json
を開き、以下の内容を記述します:
{
"mcpServers": {
"awslabs.aws-documentation-mcp-server": {
"command": "uvx",
"args": ["awslabs.aws-documentation-mcp-server@latest"],
"env": {
"FASTMCP_LOG_LEVEL": "ERROR"
},
"disabled": false,
"autoApprove": []
},
"stripe": {
"command": "npx",
"args": [
"-y",
"@stripe/mcp",
"--tools=documentation.read",
"--api-key=sk_dummy"
]
}
}
}
この設定で、AWS公式ドキュメント、Stripeドキュメントを活用できるようになります。Claude Desktopアプリを再起動すると、2つのMCPが提供する機能(ツール)が追加されます。
ステップ2: シンプルなプロンプトで実装を開始
初心者にとって重要なのは、「まずは動くものを作る」ということです。以下のようなシンプルなプロンプトから始めましょう:
AWS Lambdaを使って、Stripe Checkout SessionのURLを発行するGET APIを追加したい。CDKで構成を管理する前提で設計をしてください。
最新情報を確認したいので、AWSもStripeも必ずドキュメントをチェックしてから作業してください。
MCPの設定ができていれば、Stripeやのツールを使う許可を求めてきます。「このチャットで許可する」をクリックして作業を始めさせましょう。
このプロンプトに対して、MCPは以下のようなステップでコードを生成します:
- AWS LambdaとStripe APIのドキュメントを検索
- Stripe Checkout Sessionを作成するLambda関数の基本コードを生成
- CDKによるインフラ構成コードを生成
ステップ3: 生成されたコードから学ぶ
MCPが生成した基本的なLambda関数のコードを見てみましょう:
const AWS = require('aws-sdk');
const stripe = require('stripe');
const secretsManager = new AWS.SecretsManager();
exports.handler = async (event) => {
console.log('Event received:', JSON.stringify(event, null, 2));
try {
// Stripe APIキーの取得
const secretData = await getSecret(process.env.STRIPE_SECRET_KEY_ARN);
const stripeClient = stripe(secretData.stripeSecretKey);
// クエリパラメータの取得
const queryParams = event.queryStringParameters || {};
const productId = queryParams.productId;
const priceId = queryParams.priceId;
const quantity = parseInt(queryParams.quantity || '1', 10);
const mode = queryParams.mode || 'payment';
// 必須パラメータのバリデーション
if (!priceId && !productId) {
return formatResponse(400, {
error: 'Bad Request',
message: 'Either productId or priceId is required',
});
}
// Stripe Checkout Sessionの設定
const sessionParams = {
payment_method_types: ['card'],
line_items: [],
mode: mode, // 'payment', 'subscription', or 'setup'
success_url: process.env.SUCCESS_URL,
cancel_url: process.env.CANCEL_URL,
};
// 商品情報の設定
if (priceId) {
// priceIdが提供されている場合は直接使用
sessionParams.line_items.push({
price: priceId,
quantity: quantity,
});
} else if (productId) {
// productIdが提供されている場合、最初に商品の価格を取得
const productDetails = await stripeClient.products.retrieve(productId);
const prices = await stripeClient.prices.list({
product: productId,
limit: 1,
active: true,
});
if (prices.data.length === 0) {
return formatResponse(400, {
error: 'Bad Request',
message: 'No active price found for the provided productId',
});
}
sessionParams.line_items.push({
price: prices.data[0].id,
quantity: quantity,
});
}
// Checkoutセッションの作成
const session = await stripeClient.checkout.sessions.create(sessionParams);
// 成功レスポンスの返却
return formatResponse(200, {
success: true,
checkoutUrl: session.url,
sessionId: session.id,
});
} catch (error) {
console.error('Error:', error);
return formatResponse(500, {
error: 'Internal Server Error',
message: error.message,
});
}
};
// Secrets Managerからシークレットを取得する関数
async function getSecret(secretArn) {
const data = await secretsManager.getSecretValue({ SecretId: secretArn }).promise();
if ('SecretString' in data) {
return JSON.parse(data.SecretString);
}
throw new Error('Secret not found in the expected format');
}
// API Gatewayのレスポンス形式に整形する関数
function formatResponse(statusCode, body) {
return {
statusCode: statusCode,
headers: {
'Content-Type': 'application/json',
'Access-Control-Allow-Origin': '*', // CORS設定
'Access-Control-Allow-Credentials': true,
},
body: JSON.stringify(body),
};
}
このコードから、以下のような重要な概念を学ぶことができます:
-
Lambda関数の基本構造:
exports.handler
がエントリーポイントとなる関数 - AWS SDKの使い方: Secrets Managerの呼び出し方法
- StripeのAPI利用法: Checkout Sessionの作成方法
- エラーハンドリング: try-catchによる例外処理
- レスポンス形式: API GatewayやLambda Function URLに適したレスポンス形式
ステップ4: 機能拡張で学習を深める
基本的な実装ができたら、さらに要件を追加して学習を深めましょう。例えば:
API Gatewayを使わずに、Lambda functions URLでやれないか?
DynamoDBを利用して、在庫の仮押さえ・確保・開放の仕組みも追加して
このような追加指示により、MCPは機能拡張したアーキテクチャを提案してくれます:
- Lambda Function URL: API Gatewayを使わないシンプルなエンドポイント
- Lambda関数: Stripe APIを呼び出すメイン処理
- DynamoDB: 在庫情報や予約状態を管理するデータベース
- Webhook Lambda: 支払い完了・キャンセル時の在庫処理を担当
- CDK: これらのリソースをコードで管理
このアーキテクチャを通じて、Lambda Function URLやDynamoDBといった追加サービスの使い方も学べます。
ステップ5: CDKで学ぶインフラのコード化
AWS CDK(Cloud Development Kit)は、TypeScriptやPythonなどのプログラミング言語でAWSリソースを定義できるツールです。ここでは、AWS CDK MCP Serverを追加することで、より確実なリソース定義を作成できます。
エディタでclaude_desktop_config.json
を開き、AWS CDK MCP Serverの定義を追加しましょう:
{
"mcpServers": {
"awslabs.aws-documentation-mcp-server": {
"command": "uvx",
"args": ["awslabs.aws-documentation-mcp-server@latest"],
"env": {
"FASTMCP_LOG_LEVEL": "ERROR"
},
"disabled": false,
"autoApprove": []
},
"awslabs.cdk-mcp-server": {
"command": "uvx",
"args": ["awslabs.cdk-mcp-server@latest"],
"env": {
"FASTMCP_LOG_LEVEL": "ERROR"
},
"disabled": false,
"autoApprove": []
},
"stripe": {
"command": "npx",
"args": [
"-y",
"@stripe/mcp",
"--tools=documentation.read",
"--api-key=sk_dummy"
]
}
}
}
MCPが生成したCDKコードを見てみましょう:
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import * as dynamodb from 'aws-cdk-lib/aws-dynamodb';
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as path from 'path';
export class StripeCheckoutStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// DynamoDBテーブルの作成 - 在庫管理用
const inventoryTable = new dynamodb.Table(this, 'InventoryTable', {
partitionKey: { name: 'productId', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY, // 開発環境用
pointInTimeRecovery: true,
});
// 在庫予約情報を保存するテーブル
const reservationsTable = new dynamodb.Table(this, 'ReservationsTable', {
partitionKey: { name: 'sessionId', type: dynamodb.AttributeType.STRING },
billingMode: dynamodb.BillingMode.PAY_PER_REQUEST,
removalPolicy: cdk.RemovalPolicy.DESTROY, // 開発環境用
timeToLiveAttribute: 'expiresAt', // TTLを有効化 (自動削除)
});
// GSIを追加して、productIdでの検索を可能に
reservationsTable.addGlobalSecondaryIndex({
indexName: 'productId-index',
partitionKey: { name: 'productId', type: dynamodb.AttributeType.STRING },
projectionType: dynamodb.ProjectionType.ALL
});
// Stripe APIキーをSecrets Managerで管理
const stripeSecret = new secretsmanager.Secret(this, 'StripeApiKey', {
secretName: 'stripe/api-key',
description: 'Stripe API Key for Checkout',
});
// チェックアウトLambda関数
const checkoutLambda = new lambda.Function(this, 'StripeCheckoutFunction', {
runtime: lambda.Runtime.NODEJS_18_X,
handler: 'index.handler',
code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/checkout')),
environment: {
STRIPE_SECRET_KEY_ARN: stripeSecret.secretArn,
SUCCESS_URL: 'https://example.com/success',
CANCEL_URL: 'https://example.com/cancel',
INVENTORY_TABLE_NAME: inventoryTable.tableName,
RESERVATIONS_TABLE_NAME: reservationsTable.tableName,
},
timeout: cdk.Duration.seconds(30),
memorySize: 256,
});
// Lambda Function URLの設定
const checkoutFunctionUrl = checkoutLambda.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.NONE, // 認証なし (公開API)
cors: {
allowedOrigins: ['*'], // 全てのオリジンからのアクセスを許可 (本番環境では制限する)
allowedMethods: [lambda.HttpMethod.GET],
allowedHeaders: ['*'],
},
});
// Lambda関数にDynamoDBへのアクセス権限を付与
inventoryTable.grantReadWriteData(checkoutLambda);
reservationsTable.grantReadWriteData(checkoutLambda);
// Secrets Managerへのアクセス権限を付与
stripeSecret.grantRead(checkoutLambda);
// Webhookを処理するLambda関数
const webhookLambda = new lambda.Function(this, 'StripeWebhookFunction', {
runtime: lambda.Runtime.NODEJS_18_X,
handler: 'index.handler',
code: lambda.Code.fromAsset(path.join(__dirname, '../lambda/webhook')),
environment: {
STRIPE_SECRET_KEY_ARN: stripeSecret.secretArn,
INVENTORY_TABLE_NAME: inventoryTable.tableName,
RESERVATIONS_TABLE_NAME: reservationsTable.tableName,
},
timeout: cdk.Duration.seconds(30),
memorySize: 256,
});
// Webhook Lambda Function URLの設定
const webhookFunctionUrl = webhookLambda.addFunctionUrl({
authType: lambda.FunctionUrlAuthType.NONE, // 認証なし (Stripeからのコールバック用)
cors: {
allowedOrigins: ['*'],
allowedMethods: [lambda.HttpMethod.POST],
allowedHeaders: ['*'],
},
});
// Webhook LambdaにもDynamoDBへのアクセス権限を付与
inventoryTable.grantReadWriteData(webhookLambda);
reservationsTable.grantReadWriteData(webhookLambda);
// Secrets Managerへのアクセス権限を付与
stripeSecret.grantRead(webhookLambda);
// 出力値の設定
new cdk.CfnOutput(this, 'CheckoutApiUrl', {
value: checkoutFunctionUrl.url,
description: 'URL for the Stripe Checkout API',
});
new cdk.CfnOutput(this, 'WebhookUrl', {
value: webhookFunctionUrl.url,
description: 'URL for Stripe webhook callbacks',
});
}
}
このCDKコードから学べる重要な概念:
- スタックの構造: AWSリソースをどのように組み合わせるか
- Lambda関数の設定: ランタイム、タイムアウト、メモリサイズなど
- DynamoDBテーブルの設計: パーティションキー、TTL、インデックスなど
- セキュリティ設定: IAMポリシー、シークレット管理
- リソース間の関連付け: 権限付与、環境変数によるリンク
ステップ6: 実装から実行へ
設計と実装が完了したら、実際にコードを実行してみましょう。Claude Desktopアプリで作業を行い、実際のプロジェクト構造を作成し、コードを生成できます。これにより、設計から実装、そして実行までの一連のプロセスを体験できます。
MCPを使った学習のメリットと注意点
メリット
- 実践的な学習: 理論だけでなく、実際に動くコードから学べる
- 全体像の把握: システム設計から実装まで一貫して体験できる
- 最新情報の活用: 常に最新のドキュメントを参照するため、古い情報に惑わされない
- 迅速なプロトタイピング: アイデアを素早く形にして検証できる
注意点
- 本番運用の考慮: MCPで生成したコードをそのまま長期運用することには課題があるかも
- 深い理解の必要性: 生成されたコードの意味を理解することが重要
- セキュリティの考慮: 特に決済システムでは、セキュリティ面の十分な確認が必要
- コスト管理: 実際にAWSリソースをデプロイする際はコスト管理に注意
次のステップ: プロトタイプから本格開発へ
MCPで学習やプロトタイピングを進めた後、次のステップとして以下のようなアプローチがおすすめです:
- 生成されたコードの詳細分析: 各部分がなぜそのように実装されているのか理解を深める
- セキュリティ強化: 認証・認可の追加、APIキー管理の改善など
- テストの充実: 単体テスト、統合テストの追加
- CI/CDパイプラインの構築: 継続的な開発・デプロイ環境の整備
- モニタリングとログ管理: CloudWatchなどを使った運用監視体制の確立
まとめ: MCPを活用した効果的な学習
MCPは、AWS、Stripeなどの複雑なクラウドサービスを学ぶための強力なツールです。特に初心者にとって、「動かしながら学ぶ」という体験は非常に価値があります。
実際に動くシステムを作りながらAWSの基本概念を学び、自分のアイデアを形にする過程で、クラウド開発の本質を理解できるでしょう。MCPは長期運用コードの生成というよりも、学習ツール・プロトタイピングツールとして最大の価値を発揮します。
あなたのアイデアをMCPで形にして、クラウド開発の可能性を体験してみてください。そして、その経験を足がかりに、より本格的なAWS開発スキルを身につけていきましょう。
Discussion