😎

CDKで始めるLambda MCP

に公開

TL;DR

AWS CDKを使ってMCP(Model Context Protocol)サーバーをLambdaにデプロイし、CursorのAIエージェントから独自のツールを呼び出せるようにする方法を解説します。
簡単な数値計算ツールを例に、一から環境構築からクリーンアップまでを説明します。

はじめに

今回は、AWS Lambda上でMCPサーバーを動かし、CursorのAIエージェントから利用する方法を実装していきます。

https://github.com/awslabs/mcp/tree/8d90be5c403af4829a45d8f03093f830ffed6285/src/mcp-lambda-handler

前提条件

以下の環境が整っていることを確認してください:

  • AWS CLI設定済み: AWSアカウントの設定とクレデンシャルの設定
  • Node.js: CDKの実行に必要
  • Python 3.12: Lambdaのランタイム
  • AWS CDK: Infrastructure as Codeツール

CDKの詳細なセットアップはAWS CDK公式ガイドを参照してください。

プロジェクト構成

今回作成するプロジェクトの構成は以下の通りです:

mcp-lambda-project/
├── lambda/           # MCPサーバーのPythonコード
│   ├── main.py
│   └── requirements.txt
└── infra/           # CDKのインフラコード
    ├── bin/
    ├── lib/
    └── package.json

MCPサーバーの準備

まず、プロジェクトのルートディレクトリを作成し、Lambdaのコードを準備します。

mkdir mcp-lambda-project
cd mcp-lambda-project
mkdir lambda
cd lambda

依存関係の定義

まず、Pythonの依存関係を定義します。

touch requirements.txt

requirements.txtに以下を追加:

lambda/requirements.txt
awslabs.mcp-lambda-handler

MCPサーバーのコード作成

main.pyを作成し、以下のコードを記述します:

lambda/main.py
from awslabs.mcp_lambda_handler import MCPLambdaHandler

# MCPハンドラーのインスタンスを作成
mcp = MCPLambdaHandler(name="mcp-lambda-server", version="1.0.0")

@mcp.tool()
def add_two_numbers(a: int, b: int) -> int:
    """Add two numbers together."""
    return a + b

def lambda_handler(event, context):
    """AWS Lambda handler function."""
    return mcp.handle_request(event, context)

このコードの説明:

  • MCPLambdaHandler: AWS Lambdaで動作するMCPサーバーのハンドラー
  • @mcp.tool(): デコレータを使ってAIエージェントが利用できるツールを定義
  • add_two_numbers: 2つの数値を足し算する簡単なツール関数
  • lambda_handler: LambdaのエントリーポイントでMCPリクエストを処理

インフラの準備

次に、CDKを使ってAWSのインフラストラクチャを定義します。

cd ..  # プロジェクトルートに戻る
mkdir infra
cd infra
npx cdk init app --language=typescript

CDKスタックの定義

infra/lib/infra-stack.tsを以下の内容に置き換えます:

infra/lib/infra-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as lambda from 'aws-cdk-lib/aws-lambda';

export class InfraStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    // Lambda関数の定義
    const func = new lambda.Function(this, 'McpLambdaFunction', {
      runtime: lambda.Runtime.PYTHON_3_12,
      handler: 'main.lambda_handler',
      code: lambda.Code.fromAsset('../lambda'),
      architecture: lambda.Architecture.ARM_64,
      timeout: cdk.Duration.seconds(10),
      description: 'MCP Lambda server function exposed via Function URL',
    });

    // Function URLの作成(認証なしでパブリックアクセス可能)
    const functionUrl = func.addFunctionUrl({
      authType: lambda.FunctionUrlAuthType.NONE,
    });

    // デプロイ後にURLを出力
    new cdk.CfnOutput(this, 'McpLambdaFunctionUrl', {
      value: functionUrl.url,
      description: 'Public Function URL for the MCP Lambda function',
    });
  }
}

このCDKスタックの構成要素:

  • Lambda関数: Python 3.12ランタイムでMCPサーバーを実行
  • Function URL: HTTPSエンドポイントを提供(認証なし)
  • ARM64アーキテクチャ: コスト効率とパフォーマンスの最適化
  • 10秒タイムアウト: 短時間での応答を前提とした設定
  • 出力: デプロイ後にFunction URLを表示

デプロイの実行

CDKスタックをAWSにデプロイします:

npx cdk deploy

デプロイ時に以下のような確認画面が表示されます:

IAM Statement Changes
┌───┬──────────────────────────────────────┬────────┬──────────────────────────┬──────────────────────────────┬───────────┐
│   │ Resource                             │ Effect │ Action                   │ Principal                    │ Condition │
├───┼──────────────────────────────────────┼────────┼──────────────────────────┼──────────────────────────────┼───────────┤
│ + │ ${McpLambdaFunction.Arn}             │ Allow  │ lambda:InvokeFunctionUrl │ *                            │           │
├───┼──────────────────────────────────────┼────────┼──────────────────────────┼──────────────────────────────┼───────────┤
│ + │ ${McpLambdaFunction/ServiceRole.Arn} │ Allow  │ sts:AssumeRole           │ Service:lambda.amazonaws.com │           │
└───┴──────────────────────────────────────┴────────┴──────────────────────────┴──────────────────────────────┴───────────┘
IAM Policy Changes
┌───┬──────────────────────────────────┬────────────────────────────────────────────────────────────────────────────────┐
│   │ Resource                         │ Managed Policy ARN                                                             │
├───┼──────────────────────────────────┼────────────────────────────────────────────────────────────────────────────────┤
│ + │ ${McpLambdaFunction/ServiceRole} │ arn:${AWS::Partition}:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole │
└───┴──────────────────────────────────┴────────────────────────────────────────────────────────────────────────────────┘

Do you wish to deploy these changes (y/n)? y
InfraStack: deploying... [1/1]
InfraStack: creating CloudFormation changeset...

 ✅  InfraStack

✨  Deployment time: 48.47s

Outputs:
InfraStack.McpLambdaFunctionUrl = https://xxxxxxx.lambda-url.ap-northeast-1.on.aws/
...

yを入力してデプロイを実行すると、数十秒後にデプロイが完了し、InfraStack.McpLambdaFunctionUrlとして表示されるURLが、今回作成したMCPサーバーのエンドポイントになります。

CursorでMCPサーバーを設定

作成したMCPサーバーをCursorのAIエージェントから利用できるように設定します。

MCP設定の開き方

  1. Cursorで Cmd + Shift + P(Windowsの場合は Ctrl + Shift + P)を押す
  2. Open MCP Settingsを選択
  3. New MCP Serverをクリック

設定ファイルの編集

mcp.jsonが開かれるので、以下の設定を追加します:

mcp.json
{
  "mcpServers": {
    "aws-mcp-lambda": {
      "type": "streamable-http",
      "url": "https://xxxxxxx.lambda-url.ap-northeast-1.on.aws/"  // デプロイ時に表示されたURLに置き換え
    }
  }
}

接続状況の確認

設定後、Cursorの画面下部にMCP接続インジケータが表示されます。インジケータが赤色になることがありますが、ログを確認するとツールは正常に認識されています。

2025-08-11 16:34:49.686 [error] Client error for command Streamable HTTP error: Failed to open SSE stream: Bad Request
2025-08-11 16:34:49.686 [error] Client error for command Streamable HTTP error: Failed to open SSE stream: Bad Request
2025-08-11 16:34:49.704 [info] Found 1 tools and 0 prompts
2025-08-11 23:09:39.219 [info] Handling CreateClient action
2025-08-11 23:09:39.222 [info] Connected to streamableHttp server, fetching offerings
2025-08-11 23:09:39.222 [info] Connected to streamableHttp server, fetching offerings

Found 1 tools and 0 promptsの表示で、1つのツールが認識されていることが確認できます。

動作テスト

CursorのAIチャットで実際にツールが使えるかテストしてみましょう:

59+21というリクエストに対して、作成したMCPツール(addTwoNumbers)が呼び出されて結果が返されます。

正常にMCPサーバーとの連携ができていることが確認できました。

トラブルシューティング:赤いインジケータについて

現象

MCP設定後、Cursorの画面下部のインジケータが赤色になることがあります。同様の現象について、Cursorフォーラムでも報告されています。

原因の詳細

  1. Cursor の streamable-http クライアントは接続時にまず SSE(Server-Sent Events) を試す仕様。
  2. AWS Lambda(Pythonランタイム + Function URL + BUFFERED) は SSE 非対応。
  3. そのため初回の SSE 接続が 400 Bad Request になり、
    Cursor ログにFailed to open SSE stream: Bad Requestが出る。
  4. その後 Cursor は通常 HTTP にフォールバックし、リクエストは成功する。

結論

この現象は特に問題はない:

  • MCP のツール実行自体は正常に動作
  • ログ上の SSE エラーは無害な仕様上のノイズ
  • 実際の機能に影響はなし

解決策(任意)

もしエラーログを完全に消したい場合は、以下のいずれかを検討してください:

  • Lambda のランタイムをNode.jsに変更し、InvokeMode.RESPONSE_STREAMを使用
    ただし、現状でも十分に動作するため、特に対応は不要。

環境のクリーンアップ

実験が完了したら、作成したAWSリソースを削除しましょう。

リソース削除ポリシーの設定

まず、infra/bin/infra.tsを開いて、リソースの強制削除を許可する設定を追加します:

infra/bin/infra.ts
import * as cdk from 'aws-cdk-lib';
import { InfraStack } from '../lib/infra-stack';

const app = new cdk.App();
new InfraStack(app, 'InfraStack', {});

// 全リソースの強制削除を許可
cdk.RemovalPolicies.of(app).destroy();

最終行にcdk.RemovalPolicies.of(app).destroy();を追加します。これにより、CloudWatchログなどの永続化リソースも含めて、全てのリソースを強制的に削除できるようになります。

スタックの削除

設定を変更したら、以下のコマンドでスタックを削除します:

npx cdk destroy

確認プロンプトでyを入力すると、作成した全てのAWSリソースが削除されます。

最後に

本記事では、AWS CDKを使ってLambda上でMCPサーバーを構築し、CursorのAIエージェントから利用する方法を実践的に学びました。

今回実現したこと

  • MCPサーバーの作成: Pythonで簡単な計算ツールを実装
  • AWS Lambdaへのデプロイ: CDKを使った自動化されたインフラ構築
  • Cursorとの連携: AIエージェントからMCPツールの呼び出し

この基盤を使ってデータベース操作、外部API連携、ファイル処理などの高度なツールを開発できます。Lambdaの無料枠(月100万リクエスト)内であれば、ほぼ無料でAIエージェントの機能を大幅に拡張可能です。

参考

GitHubで編集を提案

Discussion