はい、できました🎉🎉🎉
API GatewayとLambdaでMCPサーバーを構築できました🎉🎉🎉
概要図はこんな感じになります。
MCPのTransports仕様について
MCPの2025-03-26版仕様ではTransportsとしてstdio
とStreamable HTTP
があります。
- stdio: 標準入出力を使用し、MCPクライアントがMCPサーバーをサブプロセスとして起動。標準入出力を使用するため、MCPクライアントとMCPサーバーは同一の環境(パソコン)
- Streamable HTTP: HTTP POSTとGETで構成された通信仕様。HTTPでの通信のためMCPクライアントとMCPサーバーが別の環境(パソコン)として実現か可能に
一つ前の2024-11-05版仕様ではHTTP+SSEという仕様がありましたが、Streamable HTTPに置き換わりました。(後方互換としてオプションとしては残っています)
今回はStreamable HTTPを使用します。
ステートフル or ステートレス
MCPはセッション管理を行うステートフルなプロトコルとして設計されています。(と、私は理解してます)
例えば、ブラウザ操作をするPlaywrightのMCPサーバーの場合、
- Webサイトを開いて
- リンクをクリックして画面遷移して
- ページをスクロールして
- スクリーンショットを取得する
のように、複数ステップにわたる操作を実施させたい場合があります。しかも、4つのステップを一度に依頼するのではなく、一つのステップごとにユーザーの応答をうけ、チャット形式でやり取りすることも考えられます。
そのため、MCPではセッション管理をしてステートフルな仕様となっていますが、これが AWS Lambdaと相性が良くありません 。
MCP仕様のシーケンス図に表現されているのですが、クライアントとサーバーとのコネクションを維持したまま複数のやり取りを行う仕様となっています。
下図の上の赤矢印のところでPOSTリクエストを受けたままコネクションは維持しつつ、下の赤矢印のGETリクエストでツール実行とかのリクエストが来ます。(たぶん)
LambdaでMCPサーバーを実現するとどうなるかというと、POSTを受けるLambdaのインスタンスとGETを受けるLambdaのインスタンスが「 必ず 」別のインスタンスになり、セッション情報を共有できません。
なのですが、セッション管理は必須ではないみたいでして、MCPのTypeScript SDKにはセッション管理をしない「ステートレス」での利用方法が存在します。
要はセッションIDをリクエストごとに新しくするような動作をしてそうですが、これであればLambdaでも実現できることがわかりました。
API Gateway + LambdaとMCP公式SDKは相性が悪い?
MCPの公式SDKを使い、Streamable HTTP方式のMCPサーバーを作成する場合、SDKがいい感じにWebサーバー機能を提供しており、API Gateway + Lambda環境では使いづらいです。(使えるかもしれませんが)
ということで、API Gateway + LambdaでMCPサーバーを構築するライブラリーを作りました
前置きが長くなりましたが、API Gateway + Lambdaの環境でMCPサーバーを構築するライブラリーを作成し、公開しました🎉🎉🎉
MCPサーバーをどうコーディングするかの具体例の解説ではなく、ライブラリーの形になっているのには理由がありまして。。
白状すると、Amazon Q Developer CLIが全部作ってくれたので、細かな実装は私も把握してません🙊
ライブラリーの内容が知りたい方はDeepWikiを御覧ください。
https://deepwiki.com/moritalous/lambda-mcp-adaptor
ライブラリーの使い方を解説
ライブラリーの使い方を手順を追って解説します。
-
SAMプロジェクトを作成
Node.js22とTypeScriptの環境をベースにしますsam init --name sam-app \ --runtime nodejs22.x \ --dependency-manager npm \ --app-template hello-world-typescript
不格好ですが、
hello-world
のまま進めます。 -
ライブラリーをインストール
cd sam-app/hello-world/ npm add github:moritalous/lambda-mcp-adaptor
-
Lambdaハンドラーを実装
手順としては、-
createMCPServer
でMCPサーバーを生成 - MCPツールを定義。(ツール以外にプロンプト、リソースも対応しており、複数指定可能)
-
createLambdaHandler
でLambdaハンドラーを生成
以上です。
以下のコードが、1つのツールを持ったMCPサーバーLambdaのハンドラーです。全量がこれです。
結構隠蔽しまくりましたので、ほぼMCPツールを定義するだけです
sam-app/hello-world/app.ts
import { createMCPServer, createLambdaHandler } from 'lambda-mcp-adaptor'; import { z } from 'zod'; // MCPサーバーを定義 const server = createMCPServer({ name: 'My MCP Server', version: '1.0.0', description: 'A powerful MCP server with authentication', }); // MCPのツールを定義 server.tool( 'calculate', { operation: z.enum(['add', 'subtract', 'multiply', 'divide']), a: z.number(), b: z.number(), }, async ({ operation, a, b }) => { let result; switch (operation) { case 'add': result = a + b; break; case 'subtract': result = a - b; break; case 'multiply': result = a * b; break; case 'divide': result = a / b; break; } return { content: [{ type: 'text', text: `${a} ${operation} ${b} = ${result}` }], }; }, ); // Lambdaハンドラーを作成 export const lambdaHandler = createLambdaHandler(server);
-
-
template.yaml
を修正/mcp
のエンドポイントでPOST
を受けるように設定しますtemplate.yaml(HelloWorldFunctionのEvents部分のみ抜粋)
Events: MCPPost: Type: Api Properties: Path: /mcp Method: post
Outputsは
Prod/mcp
に変更しましょうHelloWorldApi: Description: "API Gateway endpoint URL for Prod stage for Hello World function" Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/mcp"
-
SAMビルドとデプロイ
これで完成です。
VSCodeから接続確認
VSCodeをMCPホストとして、接続確認を行います。
- [表示] -> [コマンドパレット] を選択
- 「MCP: サーバーの追加」を選択
- 「HTTP (HTTP またはサーバー送信イベント)」を選択
- デプロイしたAPI Gatewayのエンドポイント(
https://9999999999.execute-api.{リージョン}.amazonaws.com/Prod/mcp
)を入力 - 任意の名前(calculate など)を入力
- 設定を保存する場所を選択
これで設定完了です。
GitHub Copilot Chatをエージェントモードにし、「calculateツールを使って、 2足す3を実行して」と質問します。
うまく動作していますね!
認証機能もあるよ
認証はAmazon Cognitoでの実現を検討したのですが、MCPの仕様で必須となっているOAuth 2.0 Dynamic Client Registration Protocol
に未対応のため、採用できませんでした。
代わりに固定のAPIキーを使った認証はできるようにしています。
認証機能を使ったサンプルはこちらに格納していますので参考にしてください。
ぜひ使ってみてください!
気に入っていただけた方はGitHubのスター、Qittaのいいね、いただけると私がニヤニヤします。
Views: 0