AIエージェントと外部ツールをつなぐ標準規格「MCP(Model Context Protocol)」を使ったサーバーを、クラウド上で複数台稼働させる設計を検討している方に向けた内容です。
通貨換算やDB連携などのMCPサーバーを本番運用する段階になると、必ず突き当たるのがセッション設計の問題です。MCPサーバーを1台で動かしている間は気にならなくても、負荷分散のために複数インスタンスへ増やした途端、リクエストがどのサーバーに届いても正しく処理できるかどうかが運用の生命線になります。この判断を誤ると、オートスケーリングが機能しない、障害時に片方のサーバーだけ復旧すればよいはずが両方の状態を突き合わせる羽目になる、といった典型的なクラウド運用の落とし穴にはまります。
どんな場面でこの判断が必要になるか
MCPサーバーをオンプレの単一プロセスから、クラウドのコンテナ環境やサーバーレス環境へ移行するタイミングでこの判断が発生します。
具体的には、Kubernetesでレプリカ数を2以上に設定する、AWS LambdaやCloud Runのようなスケールアウト型の実行基盤に載せる、ロードバランサー配下に複数インスタンスを並べる、といった構成を組む場面です。
MCPの通信方式であるStreamable HTTP(HTTPの1コネクション上でリクエストとストリーミング応答をやり取りする方式)は、以前の仕様ではプロトコルレベルのセッションを持てる設計になっていました。クライアントが initialize リクエストを送るとサーバーが Mcp-Session-Id を発行し、以降のリクエストにそのIDを付けてやり取りするという流れです。この設計のまま複数インスタンスに展開すると、セッションを発行したサーバーとその後のリクエストを受け取るサーバーが一致しない限り処理が破綻します。
判断軸1: スケーラビリティ要件
1つ目の軸は、そのMCPサーバーを何台構成で動かす予定かです。
単一インスタンスで完結し、今後もスケールアウトの予定がないなら、セッションの有無は大きな問題になりません。一方、オートスケーリングでインスタンス数が動的に増減する構成では、特定のサーバーにリクエストを固定する「スティッキーセッション」の仕組みが必要になり、これがロードバランサーの設定を複雑にします。
MCPの最新仕様が目指す方向性は、どのリクエストもどのサーバーインスタンスに届いても処理できることです。スティッキールーティングや共有セッションストアを前提にしない設計が公式に推奨されています。
判断軸2: 障害時の切り離しやすさ
2つ目の軸は、1台のサーバーが落ちたときにどこまで影響が波及するかです。
セッションをサーバー側のメモリに持たせている場合、そのインスタンスが再起動やクラッシュを起こすとセッション情報が消え、クライアント側は原因不明のエラーに直面します。障害調査の際も「どのインスタンスがどのセッションを持っていたか」を追跡する必要が出てきて、根本原因分析の手間が増えます。
リクエストごとに必要な情報を含める設計であれば、1台が落ちてもロードバランサーが別のインスタンスに振り分けるだけで処理を継続できます。障害の影響範囲がそのリクエスト単位に閉じるため、原因の切り分けが単純になります。
判断軸3: アプリケーション状態の持ち方
3つ目の軸は、状態そのものをどこに持たせるかです。
ここで誤解しやすいのが、「ステートレス(状態を持たない)」という言葉が「アプリケーションが一切の状態を扱えない」という意味ではない点です。ショッピングカートのようなツールを考えると分かりやすく、create_cart() を呼んだサーバーが cart_id を返し、次のツール呼び出し側が明示的にその cart_id をパラメータとして渡す形にすれば、状態は保持しつつプロトコル層のセッションには依存しません。
つまり状態を「プロトコルが隠し持つセッション」ではなく「アプリケーションが扱うデータ」として表現し直すのが、この移行の核心です。状態をRedisのような外部ストアに置くか、リクエストのペイロードに含めるかは実装の選択肢ですが、少なくともサーバープロセスのメモリに閉じ込めない設計が前提になります。
判断軸4: 監視設計への影響
4つ目の軸は、監視・可観測性の設計をどう変える必要があるかです。
セッションベースの構成では「セッションIDごとの追跡」が監視の単位になりがちですが、ステートレス構成に移行すると、リクエスト単位のトレーシング(分散システムで1つのリクエストがどのサービスを経由したか追跡する仕組み)が中心になります。OpenTelemetryのようなトレーシング基盤を導入している場合、リクエストIDをスパンに紐付けておけば、どのインスタンスが処理したかに関係なく処理経路を追えます。
セッション単位のログを前提にダッシュボードやアラートを組んでいる場合、ステートレス移行時にはその監視設計自体も見直しが必要になる点は見落とされがちです。
選択肢の比較
| 観点 | セッションベース(旧方式) | ステートレス(新方式) |
|---|---|---|
| スケールアウト | スティッキーセッションや共有ストアが必要 | 任意のインスタンスで処理可能 |
| 障害時の影響範囲 | セッション保持インスタンスの障害で処理継続不能 | リクエスト単位で他インスタンスに退避可能 |
| 実装の複雑さ | セッション管理ロジックが必要 | 状態を明示的にペイロードへ含める設計が必要 |
| 監視の単位 | セッションIDベースの追跡 | リクエストID・トレーシングベース |
ケース別の推奨
複数インスタンスでのオートスケーリングを前提にクラウド運用するなら、ステートレス構成を選ぶのが妥当です。TypeScript SDKでは @modelcontextprotocol/server のような分割パッケージで新しい仕様に沿った実装がしやすくなっています。移行時は、まずツールのレスポンスに識別子(カートIDのような)を含める設計に変え、次のリクエストでその識別子をクライアント側から明示的に渡す形にツール定義を書き換えます。
小規模な検証環境やローカルでの単一プロセス運用にとどまるなら、無理にステートレス化する必要はありません。ステートレス化は主にスケールアウトと障害耐性のための設計であり、単一インスタンスでは恩恵が限定的です。
すでに稼働中のMCPサーバーがあり、セッションIDに依存したロジックが深く組み込まれている場合は、段階的な移行が現実的です。まず監視ダッシュボードでセッションIDをキーにしたクエリがどこにあるかを洗い出し、リクエストID・トレースIDベースに置き換えられる箇所から着手する進め方が負担を抑えられます。
あえて見送るべき条件
次のような条件では、ステートレス化を急ぐ必要はないと考えられます。
- サーバーが常に単一インスタンスで稼働し、今後もスケールアウトの計画がない場合
- 会話の文脈保持が本質的に必要で、外部ストアへの状態移行がレイテンシ増加を招く懸念が強い場合
- MCP SDKのバージョンアップに伴う破壊的変更のリスクを、現状の安定運用より優先したくない場合
これらに当てはまる場合は、まず現行のセッション管理方式を維持しつつ、SDKのマイグレーションガイドで互換性の変更点だけ把握しておくのが無難です。
移行前に確認すること
MCPサーバーのステートレス化は、クラウド運用における典型的な「アプリケーション状態をプロセス外に出す」設計変更の一種です。
判断の起点は、スケールアウトの予定があるか、障害時にリクエスト単位で切り離したいか、状態をどこに持たせるかの3点に集約されます。
まず着手すべきは、現行サーバーのツール定義がセッションIDに暗黙的に依存していないかを確認する作業です。依存箇所が見つかったら、レスポンスに識別子を含めてクライアントが次のリクエストで明示的に渡す形へ、1つずつ書き換えていく進め方が現実的です。