最近はエンジニアにとどまらず多くの人が AI ツールを使い、MCP(Model Context Protocol)サーバーと接続して仕事などをしている人が多いと思います。
MCP サーバーが登場した頃はローカルマシンで稼働させるのが基本でした。
であるが故にマシンスペック次第では重たくなったり、技術的な面でエンジニアではない人がMCPサーバーを使うことが難しいものもありました。
MCP サーバーを使うためにマシンに uvx
が入っていることが前提になっていることもしばしばありました。
ただ最近では Remote MCP サーバーも登場し、多くの AI ツールがそれに対応し始めたので、今回 AWS Lambda で MCP サーバーを構築することに挑戦しました。
この記事では FastMCP ライブラリを利用し、AWS Lambda上でスケーラブルかつ低コストな MCP サーバーを構築する方法を紹介します。
FastMCP で実装したMCPサーバーを Lambda にデプロイする
クライアントからのリクエストは、ストリーミングが有効化された Function URL を通じて Lambda に送られ、コンテナ内で FastAPI ベースのアプリケーションがリクエストを処理します。
主な使用技術スタック
- アプリケーション: FastMCP (jlowin/fastmcp)
- Webサーバー: Uvicorn
- デプロイ: AWS SAM + Docker
- 実行環境: AWS Lambda (コンテナイメージ)
- 連携: aws-lambda-adapter
- パッケージ管理: uv
多くの開発者にとっては特別準備するものはないとは思いますが、 AWS SAM CLI は開発マシンにインストールしておくと便利です。
ディレクトリ構成
最終的なディレクトリ構成は下記のようになる想定です。
my-lambda-mcp/
├── Dockerfile
├── pyproject.toml
├── README.md
├── src/
│ └── app.py
└── template.yaml
ステップ1: プロジェクトのセットアップ
まず、プロジェクト用のディレクトリを作成し、必要なライブラリを定義します。
uv init --lib my-lambda-mcp
プロジェクトを作成した、ディレクトリ移動して必要なライブラリの追加をします。
cd my-lambda-mcp
最低限必要なライブラリは下記です。
fastmcp
uvicorn
uv add
を使って追加していきます。
uv add fastmcp uvicorn
セットアップは以上です。
ステップ2: アプリケーションの作成 (app.py
)
次に、アプリケーションの心臓部となるコードを作成します。プロジェクトルートに app.py
という名前でファイルを作成します。
FastMCP をステートレスモードで初期化することが、Lambda で正しく動作させるための最重要ポイントです。
from fastmcp import FastMCP
mcp = FastMCP("Demo 🚀")
@mcp.tool
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
# ⚠️⚠️ ここで stateless_http=True にすることが重要 ⚠️⚠️
app = mcp.http_app(
stateless_http=True,
)
ステップ3: コンテナの定義 (Dockerfile)
aws-lambda-adapter
を組み込み、Uvicorn
を起動するための Dockerfile
をプロジェクトルートに作成します。
FROM ghcr.io/astral-sh/uv:python3.13-bookworm
# aws-lambda-adapterをコンテナにコピー
COPY --from=public.ecr.aws/awsguru/aws-lambda-adapter:0.9.1 /lambda-adapter /opt/extensions/lambda-adapter
WORKDIR /app
COPY pyproject.toml README.md /app/
RUN uv sync
COPY src/ ./src/
ENV UV_CACHE_DIR=/tmp/uv-cache
ENV UV_NO_SYNC=1 # uv のビルド速度を上げる
ENV AWS_LAMBDA_ADAPTER_BUFFER_OFF=1
ENV AWS_LAMBDA_ADAPTER_CALLBACK_PATH="/callback"
ENV AWS_LAMBDA_ADAPTER_HTTP_PROXY_BUFFERING="off"
ENV PYTHONPATH=/app
ENV PATH="/app/.venv/bin:$PATH"
CMD ["uvicorn", "src.app:app", "--host", "0.0.0.0", "--port", "8080"]
補足 – uv関連の環境変数
環境変数の設定の目的に一応触れておきます。興味ない人は飛ばしてください。
uv関連の環境変数
UV_CACHE_DIR=/tmp/uv-cache
uv
のキャッシュディレクトリを /tmp/uv-cache
に指定しています。
- Docker コンテナ内でuvがパッケージをキャッシュする際の保存場所を明示的に設定
/tmp
を使うことで、コンテナの一時的な領域にキャッシュを配置- ビルド時のパフォーマンス向上とディスク使用量の最適化を図る
UV_NO_SYNC=1
uv
の自動同期機能を無効化します。
- 通常uvは依存関係の変更を検出して自動的に同期を行う
- Docker ビルド時や Lambda 実行時には不要な処理となるため無効化
- 起動時間の短縮とパフォーマンスの向上を実現
AWS Lambda Adapter関連の環境変数
AWS_LAMBDA_ADAPTER_BUFFER_OFF=1
AWS Lambda Web Adapter のバッファリング機能を無効化します。
- レスポンスのバッファリングを行わず、ストリーミングでレスポンスを返す
- リアルタイム性を重視したアプリケーションに適用
- メモリ使用量の削減効果も期待できる
AWS_LAMBDA_ADAPTER_CALLBACK_PATH="/callback"
Lambda Web Adapter がコールバック用に使用するパスを /callback
に設定します。
- Lambda の実行完了を通知するためのエンドポイントを指定
- アダプター内部での処理フローを制御する重要な設定
AWS_LAMBDA_ADAPTER_HTTP_PROXY_BUFFERING="off"
HTTP プロキシのバッファリング機能を無効化します。
- リアルタイムでのデータ転送を優先する設定
- 大きなレスポンスや長時間の処理において効果的
- Lambda 関数のタイムアウト制限を考慮した最適化
Python関連の環境変数
PYTHONPATH=/app
Pythonのモジュール検索パスに /app
を追加します。
- アプリケーションのルートディレクトリからモジュールをインポート可能にする
- 相対インポートの問題を解決
- コンテナ内での Python アプリケーションの実行を安定化
PATH="/app/.venv/bin:$PATH"
システムの PATH 環境変数に仮想環境の bin ディレクトリを追加します。
- uv で作成した仮想環境内の Python やパッケージのコマンドを直接実行可能にする
- 仮想環境を明示的にアクティベートせずに Python スクリプトを実行
- コンテナ起動時の利便性を向上
ステップ4: サーバーレスインフラの定義 (template.yaml
)
AWS SAM を使い、Lambda 関数や Function URL をコードで定義します。プロジェクトルートに template.yaml
を作成してください。
AWSTemplateFormatVersion:'2010-09-09'
Transform:AWS::Serverless-2016-10-31
Description:A serverless MCP server using FastMCP on AWS Lambda.
Globals:
Function:
Timeout:120
MemorySize:256
Resources:
MyLambdaMcpFunction:# 任意の名前でOK
Type:AWS::Serverless::Function
Properties:
FunctionName:MyLambdaMcpFunction# 任意の名前でOK
PackageType:Image
FunctionUrlConfig:
AuthType:NONE# 本番運用するときは必ず認証を有効にしてください
InvokeMode:RESPONSE_STREAM# ストリーミング応答を有効化(重要)
Cors:
AllowOrigins:
-'*'
AllowHeaders:
-Content-Type
-Authorization
AllowMethods:
-POST
Metadata:
DockerTag:my-lambda-mcp-v1# 任意の名前でOK
Dockerfile:Dockerfile
DockerContext:.
Outputs:
MyLambdaMcpFunctionUrl:
Description:"The URL for the MCP Server Lambda function"
Value:!GetAttMyLambdaMcpFunctionUrl.FunctionUrl
これは最小限の設定です。
⚠️ 認証認可に関してもガバガバなので、本番運用する時は必ず然るべき設定に変更してください。
ステップ5: デプロイ
準備が整いました。以下のコマンドで AWS にデプロイします。
まずはビルドをします。
sam build --use-container
ビルドができたらデプロイをします。
sam deploy \
--capabilities CAPABILITY_IAM \
--stack-name my-mcp-server \
--image-repository ${{ secrets.AWS_ACCOUNT_ID }}.dkr.ecr.ap-northeast-1.amazonaws.com/my-app \
--no-confirm-changeset
Docker レジストリーの設定などは各個人の環境に合わせて設定してください。
また AWS CLI の設定次第では profile の指定が必要だったりしますが、ここの詳細は割愛します。
ステップ6: 動作確認
デプロイが完了すると、Outputs に Lambda Function URL が表示されます。その URL を使って MCP サーバーの設定をします。
おそらくこのような感じで表示されると思います。
CloudFormation outputs from deployed stack
----------------------------------------------------------------
Outputs
----------------------------------------------------------------
Key MyLambdaMcpFunctionUrl
Description The URL for the MCP Server Lambda function
Value https://xxxxxxxxxxxxxxxxxxxxxxxx
----------------------------------------------------------------
Value が関数 URL になります。今回は Cursor を例に紹介します。
Cursor の場合、mcp.json
に下記を追加するだけです。
{
"mcpServers": {
"my-lambda-mcp": { # 任意の名前でOKです。
"url": "https://xxxxxxxxxxxxxxxxxxxxxxxx/mcp/" # ⚠️ /mcp/ が必要です
}
}
}
⚠️ 注意点としては URL の最後に /mcp/
が必要なことです。末尾のスラッシュも必要なので注意です。
おわりに
これで、サーバー管理不要で、利用した分だけ課金されるスケーラブルな MCP サーバーが完成しました。この構成をベースに、ツール登録ロジックを充実させたり、認証を強化したりと、自由にカスタマイズしてみてください。
ステートレスモードで起動することが肝だと思います。
みなさまの役に立ちますと幸いです。