MCP 2026-07-28:セッションを消し、プロトコルを再びステートレスに

MCP の新リビジョンは initialize ハンドシェイクと Mcp-Session-Id ヘッダを削除し、呼び出しをまたぐ状態を明示的なサーバ発行ハンドルに変えた。何が変わり、なぜか、既存のサーバ実装にとって何を意味するか。

MCP の新しいリビジョン(2026-07-28)は引き算です。前の版は 2025-11-25 で、最大の違いは一文で言えます。

プロトコル層にセッションがなくなった。

削除されたもの:

  • Streamable HTTP トランスポートのプロトコルレベルセッションと Mcp-Session-Id ヘッダ
  • initialize / notifications/initialized ハンドシェイク
  • ping、logging/setLevel、notifications/roots/list_changed
  • 従来の HTTP GET エンドポイント、および resources/subscribe / resources/unsubscribe

なぜ削除したか

セッションは状態であり、HTTP 上のステートフルなプロトコルには古くからの問題があります。リクエストが別のマシンに届いた瞬間、文脈は失われます。スティッキーセッションか共有ストレージか。どちらも高くつき、どちらも「水平スケール」をスローガンに変えてしまいます。

以前の方式は接続ごとに Mcp-Session-Id を発行し、以後の全リクエストに載せていました。開発機では何の問題もなく、本番では惨めです。

新リビジョンは状態をデータに降格します:

  • 各リクエストがプロトコルバージョンとクライアント能力を _meta に載せる(io.modelcontextprotocol/protocolVersion、io.modelcontextprotocol/clientCapabilities)
  • クライアントは各リクエストで自己を識別すべき(io.modelcontextprotocol/clientInfo)、サーバは各結果の _meta で自己を識別すべき(io.modelcontextprotocol/serverInfo)
  • 呼び出しをまたぐ状態が必要なら、サーバが発行する明示的なハンドルを通常のツール引数として渡す(SEP-2567)

最後の点がこの変更の核心です。状態は消されたのではなく、「プロトコルが黙って覚えているもの」から「目に見え、保存でき、失効させられ、取り消せる文字列」へ移りました。

バージョン交渉も移動した

従来はハンドシェイク時に一度だけ交渉していました。交渉するハンドシェイクがもう無いので:

  • バージョン不一致は UnsupportedProtocolVersionError を返す(SEP-2575)
  • 新しい server/discover RPC が追加され、サーバはこれを実装しなければならない。対応するプロトコルバージョン、能力、身元を告知する
  • クライアントは他のどのリクエストよりも前に呼んで事前のバージョン選択に使えるし、STDIO では後方互換の探査にも使える

購読は一つのストリームになった

以前、サーバからクライアントへの変更通知は HTTP GET エンドポイント(長命接続)と resources/subscribe を経由していました。今は subscriptions/listen に一本化され、長命な POST-response ストリーム一つになります。クライアントは関心のある種別(toolsListChanged、promptsListChanged、resourcesListChanged、resourceSubscriptions)を明示的に購読し、サーバは確認して各通知に io.modelcontextprotocol/subscriptionId を付けます。

見落としやすい点が一つ。notifications/progress や notifications/message のようなリクエストスコープの通知は、今もそれが属するリクエストのレスポンスストリームを流れ、subscriptions/listen には乗りません。両者を混ぜると「この進捗は誰のものか」が答えられなくなります。

ログも同じ理屈です。レベルはリクエストごと(_meta の io.modelcontextprotocol/logLevel)になり、このフィールドを含まないリクエストに対してサーバは notifications/message を出してはならない。この一つの制約が「静かなクライアントがログに溺れる」問題を仕様レベルで潰しています。

もう一つ:tasks はコアを出た

実験的な tasks は公式拡張 io.modelcontextprotocol/tasks に移りました。健全なことです。コアプロトコルが実験的機能をいつまでも抱えるべきではなく、拡張は独自に進化し独自に廃止できます。

すでにサーバを書いた人にとって

2025-11-25 に合わせて実装したなら:

  1. セッションストアを削除する。 最大の利益であり、今回の改版の主な動機です。
  2. server/discover を実装する。 MUST です。無いと新しいクライアントがバージョン選択をできません。
  3. 呼び出しをまたぐ状態をハンドルに変える。 セッションに置いていたもの(ユーザー身元、一時的な文脈、ページングカーソル)はすべて明示的なツール引数になります。
  4. ログを見直す。 logging/setLevel はかつて全体スイッチでした。今はリクエスト単位で、付けなければ「黙れ」を意味します。

私の結論

この改版は便利に見える設計を冗長に見える設計と交換し、その見返りは具体的です。どのマシンでもどのリクエストを処理できる。スティッキーセッションも共有セッションストアも要りません。

代価はリクエストごとに数十バイトの _meta です。HTTP においてこの取引はほぼ常に割に合います。ステートレス性こそ HTTP が今も生きている理由であり、MCP はその肩に乗りながら横にもう一つ車輪を付けていたのでした。

← 記事一覧に戻る

コメント

…