MCPがステートレスになった — 2026-07-28仕様でセッションが消え、何が壊れるのか
はじめに
MCP(Model Context Protocol)は、2024年11月に Anthropic が公開して以来、「エージェントにツールを生やす」ためのデファクト標準として広まってきた。だがサーバを実際に書いて本番に置いた人ほど、ある一点で足を止められていたはずだ。セッションがある。initialize でハンドシェイクし、Mcp-Session-Id をヘッダで持ち回り、そのセッションIDに紐づいた状態をサーバ側インスタンスが抱える。つまり、素直に水平スケールできない。
2026年7月28日にリリースされた MCP の新仕様は、そこに手を入れた。プロトコルレイヤからセッションを丸ごと削除し、1リクエスト完結のステートレスなプロトコルに作り替えたのである。Simon Willison がこの変更を受けて「MCP への興味が戻ってきた」と書いた記事は Hacker News で361ポイントを集め、同じ日に議論スレッドも立って賛否が飛び交った。
本記事では、2026-07-28 仕様で具体的に何が消え、代わりに何が入り、既存の MCP サーバを持っている側が何を書き直すことになるのかを整理する。
何が消えたか — ハンドシェイクとセッションIDの廃止
破壊的変更の中核は2つの SEP に集約されている。
SEP-2567: Mcp-Session-Id ヘッダとプロトコルレベルのセッションの削除。 Streamable HTTP トランスポートからセッションの概念そのものが消えた。副次的な効果として、tools/list / resources/list / prompts/list といった一覧系エンドポイントが接続ごとに違う結果を返さなくなった。呼び出しをまたいで状態を持ちたいサーバは、プロトコルに頼らず「サーバが発行したハンドルを、ただのツール引数として受け渡す」という明示的な方式を取ることになる。
SEP-2575: initialize / notifications/initialized ハンドシェイクの削除。 従来は「セッションを開く」ためのラウンドトリップが必ず1回必要だった。新仕様では各リクエストが自己記述的になり、プロトコルバージョンとクライアント能力を _meta に載せて毎回運ぶ。具体的には io.modelcontextprotocol/protocolVersion、io.modelcontextprotocol/clientCapabilities、io.modelcontextprotocol/clientInfo といった名前付きキーだ。サーバ側も結果の _meta に io.modelcontextprotocol/serverInfo を載せて自己申告する。バージョンが噛み合わなければ UnsupportedProtocolVersionError が返る。
Simon Willison がこの差を最も端的に言い表している。レガシー MCP はセッション初期化と実行で 2リクエスト、ステートレス仕様なら 1リクエストで終わる。
This is so much cleaner from both a client- and server-side implementation perspective (クライアント側から見てもサーバ側から見ても、実装がはるかに素直になった)
— Simon Willison, “Stateless MCP has recaptured my interest”
公式ブログ側の説明も同じ方向を向いている。開発者からの信頼性・スケーラビリティ要求が強かったため双方向ステートフル型からリクエスト/レスポンス型へ転換した、という経緯であり、その結果として各リクエストは「プレーンなラウンドロビンロードバランサーの背後にある任意のインスタンスに到達可能」になった。
ステートを捨てた穴を、何で埋めたのか
セッションを消せば当然、セッション前提だった機能が宙に浮く。仕様はそれぞれに代替を用意している。
server/discover の新設。 ハンドシェイクを消した以上、事前のバージョン交渉の場が要る。サーバはこの RPC の実装が MUST で、対応プロトコルバージョン・能力・自己識別情報を広告する。クライアントは他のリクエストの前に呼んでもよいし、STDIO では後方互換のプローブとしても使える。
subscriptions/listen への一本化。 HTTP GET エンドポイントと resources/subscribe / unsubscribe が廃止され、単一の長寿命 POST レスポンスストリームに統合された。クライアントは toolsListChanged などの通知種別をオプトインし、サーバは io.modelcontextprotocol/subscriptionId でタグ付けして返す。一方 notifications/progress や notifications/message のようなリクエストスコープの通知は、従来通りそのリクエスト自身のレスポンスストリームを流れる。
Multi Round-Trip Requests(MRTR、SEP-2322)。 これが設計上いちばん面白い。従来はサーバからクライアントへ sampling/createMessage や elicitation/create を送り返す「サーバ起点リクエスト」で対話していた。双方向ストリームが前提の設計であり、ステートレス化とは相容れない。新方式では、サーバは resultType: "input_required" の InputRequiredResult を返し、inputRequests フィールドに必要な追加情報の要求を詰める。クライアントは元のリクエストをリトライし、そこに inputResponses を添えて応答する。ユーザー確認フローが、双方向接続なしに普通の HTTP リクエストの繰り返しで表現できるようになった。
これに伴い、すべての結果に resultType フィールドが必須になった("complete" または "input_required")。旧プロトコルのサーバがこのフィールドを省いた場合、クライアントは "complete" として扱う MUST がある。
Tasks は拡張へ昇格(SEP-2663)。 実験的にコアへ入っていた長時間タスクは io.modelcontextprotocol/tasks 拡張に移された。ブロッキングな tasks/result はポーリング型の tasks/get に置き換わり、クライアントからの入力用に tasks/update が加わり、tasks/list は削除された。
キャッシュ可能性の明文化(SEP-2549)。 tools/list などの結果に ttlMs(鮮度ヒント)と cacheScope("public" / "private")が必須になった。加えて tools/list は決定的な順序で返すことが SHOULD とされている。理由が実に現代的で、クライアント側キャッシュを効かせるためであると同時に、LLM のプロンプトキャッシュのヒット率を上げるためだ。さらに Streamable HTTP の POST には Mcp-Method / Mcp-Name ヘッダが必須化され、ゲートウェイが JSON ボディを解析せずヘッダだけでルーティングできるようになった。
エンジニアへの影響 — 得るものと、書き直すもの
デプロイ先の選択肢が一気に広がる。 sticky routing も共有セッションストアも要らないので、Cloud Run、Workers、Lambda、App Service のようなオートスケール前提の実行環境に MCP サーバをそのまま載せられる。インスタンスが増えても減っても、リクエストがどこに着地しても構わない。自作 MCP サーバのために常駐プロセスを1つ抱える必要が消えるのは、個人開発の運用コストとしてかなり大きい。
一方で、既存サーバは素直には動かない。 Hacker News のスレッドで最も冷静な指摘がここだった。オープンソースの MCP サーバは6万件を超える規模まで増えており、そのうち活発にメンテされているのは3割程度と見られる。そしてワイヤプロトコルは双方向に非互換だ。つまり「新クライアント×旧サーバ」も「旧クライアント×新サーバ」も自動では噛み合わない。数ヶ月前に独自にステートレス HTTP へ移行済みだった実装者は、信頼性向上と認証の簡素化という果実を報告する一方で、「対応していないクライアント側を説得するのが難しい」という現実的な壁も挙げている。
Sampling・Roots・Logging の非推奨は、設計の作り直しを迫る(SEP-2577)。 特に Sampling —— サーバがクライアント側の LLM を借りて推論する仕組み —— の非推奨は影響が大きい。公式の推奨移行先は「LLM プロバイダの API に直接統合する」であり、要するにサーバが自分の API キーとコストを持てということだ。Roots はツール引数・リソース URI・サーバ設定でディレクトリを渡す方式へ、Logging は stdio なら stderr、あるいは OpenTelemetry へ寄せる。ping と logging/setLevel も削除され、ログレベルは _meta の io.modelcontextprotocol/logLevel でリクエスト単位に指定する形になった。
地味に効くのが SSE 再開の廃止だ。 Last-Event-ID によるストリーム再開とメッセージ再送が削除されたため、レスポンスストリームが切れたら実行中のリクエストは失われ、クライアントは新しいリクエストIDで発行し直す MUST となる。長時間走るツール呼び出しを不安定な回線越しに叩く構成は、素の呼び出しではなく Tasks 拡張に寄せるべき、というのが仕様の含意だろう。
なお救いとして、廃止機能には最低12ヶ月の非推奨ウィンドウを保証する feature lifecycle ポリシーが同時に制定された(SEP-2596)。HTTP+SSE トランスポートもここに載る。SDK は TypeScript / Python / Go / C# が即日対応、Rust はベータだ。
今日のその他のニュース
Cloudflare OS が発表(HN 344pt)。Workers / Durable Objects / R2 の上位レイヤーとして、エージェント・アプリ・業務ワークフローを載せるオープンプラットフォーム構想。ステートレス MCP と組み合わせると、エッジ上にツールサーバを置く構成の現実味が増す。
Atlassian Rovo からのデータ持ち出し。AI エージェント Rovo が本来のアクセス制御を迂回してデータを外部に出せる問題が PromptArmor から報告された。プロンプトインジェクション経由で権限外コンテンツを引き出す典型例で、社内向けエージェント導入時の必読ケース。
GKE の surge upgrade 上限が緩和(2026-08-01 更新)。Standard クラスタで maxSurge + maxUnavailable の合計が100まで指定可能に。ネットワーク最適化の C4N マシンシリーズも 1.36.0-gke.3009002 以降で Standard / Autopilot 両対応になった。
まとめ
- MCP 2026-07-28 は、
initializeハンドシェイクとMcp-Session-Idを削除し、プロトコルレイヤをステートレス化した。 - 各リクエストが
_metaにバージョン・能力・識別情報を載せて自己記述するため、ロードバランサの後ろの任意のインスタンスに着地できる。 - 穴埋めとして
server/discover、subscriptions/listen、Multi Round-Trip Requests、Tasks 拡張、ttlMs/cacheScopeによるキャッシュ規定が入った。 - 代償は互換性だ。ワイヤプロトコルは双方向に非互換で、Sampling・Roots・Logging・SSE 再開が非推奨に落ちた。既存サーバの多くは書き直しが要る。
「セッションを持てるプロトコル」から「HTTP らしいプロトコル」への転換は、MCP がエージェント実験の道具からインフラ部品へ移る通過儀礼に見える。12ヶ月の猶予は、旧仕様に依存した6万件のサーバ群がどれだけ移行できるかを測る期間でもある。
ソース
- Stateless MCP has recaptured my interest — Simon Willison
- Key Changes — Model Context Protocol 2026-07-28
- The 2026-07-28 Specification — Model Context Protocol Blog
- MCP 2026-07-28 Specification: transport going stateless — Hacker News
- Cloudflare OS: an open platform for agents, apps, and work
- Atlassian Rovo Exfiltrates Data, Bypassing Controls — PromptArmor
- Google Kubernetes Engine リリースノート