asopi tech
asopi techIndie Developer
MCPプロトコルが分離した責務(前編)— セッションに閉じた状態を解く

【2026年7月版】

MCPプロトコルが分離した責務(前編)— セッションに閉じた状態を解く

公開日: 2026/07/30
読了時間: 約 11分

MCPは、Claudeなどのエージェント(内部にMCPクライアントを持つ)と業務システムの間でツールを公開するMCPサーバーとの通信規約であり、MCP仕様 v2026-07-28 のリリース候補で、その通信の扱いが大きく変わりました。

エージェントは、MCPサーバーが公開するツールを選び、必要な操作を呼び出します。MCPサーバーはDBや既存の業務システムにアクセスして結果を返します。たとえば「買い物かごを作る」ツールがかごを返した後、エージェントは次の「かごへ商品を追加する」呼び出しで、そのかごを指定します。

クラウド上のMCPサーバーでは、その呼び出しをロードバランサーの後ろにある複数のInstanceで処理します。以前は、次のリクエストに含まれるセッションIDから、そのセッションの状態を持つInstanceを特定して送る必要がありました。MCP仕様 v2026-07-28 は、この制約を外し、どのInstanceでも同じ呼び出しを処理できるようにした変更です。ツールで扱う業務データはサーバー側に残し、エージェントは次の呼び出しに必要なIDを渡します。

従来のMCPでは、ハンドシェイク後もセッションを保持する

2025-11-25までのStreamable HTTPでは、エージェントとMCPサーバーは最初に initialize / notifications/initialized のハンドシェイクを行います。このやり取りで、エージェントの情報・能力と使用するプロトコルバージョンをすり合わせ、サーバーは Mcp-Session-Id を返します。

以後の tools/call を含むすべてのリクエストに、エージェントはこの Mcp-Session-Id を付けます。受信したMCPサーバーは、IDに対応するエージェント情報、ネゴシエーション済みの能力、選択済みのプロトコルバージョンを参照してリクエストを処理します。従来のMCPでは、最初のハンドシェイクで作ったセッションを、その後の呼び出しでも継続する構成でした。この見直しの背景は、MCPをステートレスにする提案にまとまっています。

この構成は、ローカルPCで単一プロセスのMCPサーバーを動かすかぎり分かりやすいものです。一方、顧客情報、在庫、社内文書、分析基盤のような業務データを扱うと、MCPサーバーをロードバランサーの後ろに複数置く必要があります。次のリクエストが別のInstanceに届いた場合、そのInstanceには該当セッションの状態がありません。ルーターは Mcp-Session-Id から状態を持つInstanceを特定するか、セッション情報を共有ストアから読めるようにする必要がありました。

ここで保持しているのは、買い物かごやジョブのような業務データではなく、MCPの通信を処理するための状態です。業務データはDBや業務サービスに残り、エージェントが受け取った basket_idtask_id を次のツール呼び出しに渡して参照できます。

次の図は、二つの構成を常に並べたまま、リクエストの通る経路だけを繰り返し動かしています。左のピンクの点で表されるリクエストにはセッションIDが付き、ルーターはそのIDに対応する状態を持つ Instance A を特定して送ります。図では、その選別の結果としてピンクの点が A にだけ届きます。右の水色の点で表されるリクエストは、A、B、C のどれにも送れます。ルーターがセッション状態を手掛かりに到達先を選ぶ必要があるかが、水平スケールのしやすさを分けます。

MCP仕様 v2026-07-28 では、リクエストが必要な情報を持つ

新しい設計では initialize / initialized がなくなり、Mcp-Session-Id もプロトコルから外れます。MCP仕様 v2026-07-28では、リクエスト自身が処理に必要な情報を持ちます。HTTPの MCP-Protocol-Version は仕様バージョンを、Mcp-MethodMcp-Name は呼び出す操作と対象を示します。JSON-RPC本文の _meta には、エージェント情報とエージェントの能力が入ります。

買い物かごやジョブのような業務データは、これらとは別です。basket_idtask_id はツールの引数として渡し、MCPサーバーがDBやキャッシュから対象データを取得します。受信したInstanceは、前の通信を調べずに、この一つのリクエストと業務データを使って処理できます。

サーバーが先に対応バージョンや能力を返したい場合は、新しい server/discover を使います。これは「毎回必ず最初に通る接続儀式」ではなく、エージェントが必要なときに行う発見のための入口です。更新済みのエージェントが旧仕様のサーバーに当たった場合は、従来の initialize へフォールバックする移行経路もリリース候補の移行案内で想定されています。

たとえば、bsk_42 のかごへ商品を加える tools/call は次のようになります。

POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: add_item
Content-Type: application/json

{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "tools/call",
  "params": {
    "name": "add_item",
    "arguments": {
      "basket_id": "bsk_42",
      "item_id": "sku_9"
    },
    "_meta": {
      "io.modelcontextprotocol/protocolVersion": "2026-07-28",
      "io.modelcontextprotocol/clientInfo": {
        "name": "my-app",
        "version": "1.0"
      },
      "io.modelcontextprotocol/clientCapabilities": {}
    }
  }
}

ロードバランサーはこのリクエストを任意のインスタンスへ送れます。ゲートウェイやレートリミッターも、JSON-RPC本文を深く読まずに Mcp-MethodMcp-Name でルーティングや計測をしやすくなります。

状態を捨てたのではなく、見える場所へ出した

プロトコルセッションがなくなると、「複数のツール呼び出しをまたぐ処理はどうするのか」という疑問が出ます。ここで新仕様が選んだのは、状態を暗黙の接続情報として隠すのではなく、ツールの入出力へ出すことです。

たとえば create_basketbasket_id を返し、以後の add_itemcheckout がその basket_id を引数に取る形です。モデルは返ってきたIDを次のツール呼び出しで渡します。状態の保存先はデータベースでもキャッシュでもかまいませんが、どのリクエストからも参照可能にしておく必要があります。

この形には少し実務的な良さがあります。セッションIDはモデルから見えないヘッダーでしたが、明示的なハンドルはツールのスキーマと返り値に現れます。どの呼び出しが何に依存しているかを、ログ、テスト、再試行処理の側でも追いやすくなります。一方で、ハンドルの有効期限、利用者ごとの認可、削除、冪等性はアプリケーション側がきちんと設計する必要があります。

移行を成立させる三つの確認

Mcp-Session-Id を使わない経路では、どのInstanceがリクエストを受けても同じ業務処理を実行でき、既存のエージェントとの接続も維持する必要があります。次の三点は、その条件が実装と運用で成立しているかを確かめるためのものです。

  1. セッションに紐づく状態をコードが持っていないかMcp-Session-Id、接続コンテキスト、セッションIDをキーにしたメモリ上のMapを、ツールのハンドラーが読んだり書いたりしていないかを確認します。
  2. 別Instanceでも続きのツール呼び出しが成功するか — Instance Aで create_basket を実行し、返った basket_id を使う add_item をInstance Bへ強制的に送る結合テストを用意します。Aを再起動した後でも同じテストが通れば、業務状態の置き場所を確認できます。
  3. 接続してくるエージェントとSDKが新仕様を扱えるか — テスト環境で実際に接続し、v2026-07-28 を使うエージェントと、旧 initialize を使うエージェントを記録します。移行期間は、必要な経路だけを併存させます。

Claudeの更新というより、プロトコル状態を分離する更新

MCPはClaudeだけの機能ではありません。Claudeを含むホスト、SDK、MCPサーバーが共有するプロトコルです。今回の更新は、ツールの一覧や呼び出し方を少し増やした変更ではなく、クラウド上でどう運ぶかという土台を変えています。

その意味で「状態がなくなった」より、「接続に閉じていたプロトコル状態が分離された」と見るほうが正確です。プロトコルに必要な情報は各リクエストへ、業務に必要な情報は明示的なアプリケーション状態へ。この分離ができれば、MCPサーバーは一般的なHTTPサービスと同じように、オートスケールや再起動を前提に運用できます。

任意のInstanceへ送れるようになったリクエストを、誰の要求として受け取り、そのエージェントにどの業務データの操作を許すのか。次回は、認証と認可をこの経路へどう分けて置くかを扱います。

参考リンク