Draft: AWSでリモートMCPサーバーをホストする際の構成パターン雑まとめ
まだ下書きレベルですが、一旦公開しちゃいます
TL; DR
新たにMCPサーバーを実装する?
→YES: AgentCore Runtime or Lambda with Lamdba Web Adapter or API Gateway+Lamdba
既存のAPI GatewayはパブリックエンドポイントのREST APIタイプ?
→YES: AgentCore Gateway+API Gateway
Streamable HTTP形式でレスポンスを返したい?
→YES: AgentCore Runtime or Lambda with Lambda Web Adapter or API Gateway+Lambda
AgentCore Gateway自体はStreamable HTTPにできても、そこから繋ぐLambdaなどによる制約で同期的にしか返却できない
AgentCore Gateway+AgentCore Runtimeでは可能かもしれない
EFSを使う?
→YES: AgentCore Gateway+Lambda or Lambda with Lambda Web Adapter or API Gateway+Lambda
AgentCore RuntimeにはEFSをマウントできない
ALBのセキュリティグループなどでIPアドレスの制限をかけたい?
→YES: Lambda with Lambda Web Adapter or API Gateway+Lambda
AgentCore GatewayはVPC内に配置できず、強制的にパブリックなURLが発行されるため、IPアドレス制限をかけたい場合は利用できない
Lambda Web Adapterを利用した既存のAPIをMCPサーバー化したい?
→YES: FastMCPを用いてMCPのエンドポイントを追加する
AgentCoreを利用する場合
AgentCore Runtime
- 公式チュートリアルを見ての通り、環境構築から実装、デプロイまでめちゃくちゃ簡単
- 認証認可周りはAgentCore Identityに任せられる
- VPC内に配置可能
まだ試せてはいないが、AgentCore RuntimeはVPC内に配置可能なため、VPC -> ALB(セキュリティグループによるIPアドレス制限) -> プライベートサブネット -> AgentCore Runtime というフローでアクセスさせることは可能かもしれないインバウンド通信には制限かけられなさそう……(Protecting your data using VPC and AWS PrivateLink - Amazon Bedrock AgentCore)
- 詳しくは計算していないが、Lambdaとほとんど料金は変わらなさそう
- ただし、2026年1月現在、EFSをマウントすることはできないようなので、EFS経由で大規模データを読み込むツールなどは素直にLambdaを使うしかなさそう
AgentCore Gateway+sth
+MCP
- 外部のMCPサーバーとの統合はもちろん、AgentCore Runtimeとの連携も可能
- 既存のMCPサーバーをAgentCore Gatewayと連携することで、エージェントがツール群と繋ぐための窓口をここに1本化できる
+Lambda
- 認証周り含めると一番簡単そうな選択肢
- ただし、Lambdaに置くコードの実装が微妙
- AWS Lambda function targetsページ最下部のサンプルコードを見てみてほしい
- Tool名の文字列ごとにif-elseで条件分岐させて各Toolの処理を実行する形
- (FastMCP使わせてくれ…!)
- ターゲットスキーマを自前で定義してあげる必要がある
- FastMCPなどを利用していれば内部で自動で取り回してくれる存在
- アウトバウンド認証は「IAMロール」のみ
- つまり、AgentCore Gatewayから対象のLambdaが叩けるようなIAMロールを設定しておけばよい
+API Gateway
- API Gatewayを利用している既存REST APIをMCPサーバー化したい場合の選択肢
- アウトバウンド認証は「IAMロール」「APIキー」「No authorization」の三択
- Key considerations and limitationsに記載されている通り、制約が多い
- REST APIタイプのみサポートしている
- REST APIにIAM認証を使用しAPIキーを必要とするメソッドがある場合、そのメソッドは除外される
- パブリックエンドポイントタイプである必要がある
+REST API
- API Gateway以外の既存REST APIをMCPサーバー化したい場合の選択肢
- アウトバウンド認証は「OAuthクライアント」と「APIキー」の二択
AgentCoreを利用しない場合
Lambda with Lambda Web Adapter(コードはFastMCPで実装)
- 認証認可周りもFastMCPで実装
- ただしLambda単体でOAuthを使うのは実は失敗しやすい(Lambdaは進行中の認可リクエストの状態を保持できないため、DynamoDBなどと組み合わせるべき
- (Lambdaの暖化を仕組んでおけばある程度成功しやすくなるらしい)
- Lambda単体で頑張ってる方の記事: AWS上に「パスキー認証付きMCPサーバー」を作る【Cognito + Lambda + FastMCP】
きちんと認証認可を実装する場合
まずインフラの構成は以下の記事の通り OAuthの認可リクエスト情報を保持しておくために、DynamoDBを利用する
Amazon Cognito と AWS Lambda を使って OAuth 2.0 デバイスフローを実装する | Amazon Web Services ブログ
認証部分は以下のリンクに記載されているサンプルコードをベースに実装する
https://github.com/modelcontextprotocol/python-sdk?tab=readme-ov-file#authentication
そして、認可リクエスト情報の取り回しは自前でコードを書く必要があるため、FastMCPでなくMCP Python SDKを利用する形になる
以下のリンクに記載されているサンプルコードをベースに実装する
https://github.com/modelcontextprotocol/python-sdk?tab=readme-ov-file#oauth-authentication-for-clients
以下のようになるイメージ(実際に動くかは試してない)
from mcp import ClientSession
from mcp.client.auth import OAuthClientProvider, TokenStorage
from mcp.client.streamable_http import streamable_http_client
from mcp.shared.auth import OAuthClientInformationFull, OAuthClientMetadata, OAuthToken
class DynamoDBTokenStorage(TokenStorage):
"""ここにDynamoDBとの連携処理を実装する"""
def __init__(self):
self.tokens: OAuthToken | None = None
self.client_info: OAuthClientInformationFull | None = None
async def get_tokens(self) -> OAuthToken | None:
"""Get stored tokens."""
return self.tokens
async def set_tokens(self, tokens: OAuthToken) -> None:
"""Store tokens."""
self.tokens = tokens
async def get_client_info(self) -> OAuthClientInformationFull | None:
"""Get stored client information."""
return self.client_info
async def set_client_info(self, client_info: OAuthClientInformationFull) -> None:
"""Store client information."""
self.client_info = client_info
# === 省略 ===
async def main():
"""Run the OAuth client example."""
oauth_auth = OAuthClientProvider(
server_url="http://localhost:8001",
client_metadata=OAuthClientMetadata(
client_name="Example MCP Client",
redirect_uris=[AnyUrl("http://localhost:3000/callback")],
grant_types=["authorization_code", "refresh_token"],
response_types=["code"],
scope="user",
),
storage=DynamoDBTokenStorage(),
redirect_handler=handle_redirect,
callback_handler=handle_callback,
)API Gateway+Lambda
あまり詳しく調べれてないけど、これはこれで認証認可周りが大変そう
ref. AWSのAPI GatewayとCognitoを使ってOAuth認可付きリモートMCPサーバーをつくる
おわりに
基本的に、AgentCoreに乗っかっておくのが楽
AgentCore使わずに認証認可やろうとした途端にクッソ面倒になる印象