第75回ブログ|MCP 2026-07-28 仕様、ついに正式リリースへ ― 「ステートレス化」がもたらす実務インパクトを技術者向けに整理する

MCP 2026-07-28 ステートレス化の実務インパクト

対象読者: MCPサーバ/クライアントを実装・運用しているエンジニア、AIエージェント基盤を設計している人

前提知識: HTTP、ロードバランサ、OAuth 2.0 の基本的な理解


0. この記事の要約(3行)


1. 前提用語の整理

本題に入る前に、この記事で頻出する用語を先に定義しておきます。既知の方は読み飛ばしてください。

MCP(Model Context Protocol)

AIモデル(LLM)と外部のツール・データソースを接続するための通信プロトコル。Anthropicが2024年に公開し、現在はLinux Foundation傘下のプロジェクトとして運営されています。「AIツールとサービスを接続するための事実上の業界標準」という位置づけになっています。

平たく言えば、「LLMから叩ける外部API」を記述・実行するための共通規格です。ファイル検索、GitHubリポジトリ参照、社内DBクエリなどを、モデル側から統一的な作法で呼び出せるようにします。

JSON-RPC

MCPの土台になっているRPC(遠隔手続き呼び出し)の規格。{"jsonrpc":"2.0", "id":1, "method":"...", "params":{...}} という形のJSONをやりとりするだけの、非常に薄いプロトコルです。MCPはこの上に「ツール一覧を返す tools/list」「ツールを実行する tools/call」といったメソッド体系を載せています。

Streamable HTTP

MCPのリモート接続用トランスポート(通信方式)。HTTP POSTでリクエストを送り、必要に応じてSSE(Server-Sent Events: サーバからクライアントへ一方向にイベントを流し続けるHTTPの仕組み)でストリーミング応答を返す、というハイブリッドな方式です。

ステートフル / ステートレス

この違いは、後述するスケーラビリティに直結します。

スティッキーセッション(セッションアフィニティ)

ロードバランサが「同じクライアントからのリクエストは、必ず同じバックエンドサーバに転送する」ように設定すること。ステートフルなサーバでは、状態を持っているインスタンスに戻さないと会話が続かないため必須でした。

裏を返すと、スティッキーセッションはスケールアウトの敵です。負荷が偏る、インスタンス障害時にセッションが飛ぶ、デプロイのたびに接続が切れる、といった運用上の負債を生みます。

SEP(Specification Enhancement Proposal)

MCPの仕様改善提案。PythonのPEP、RustのRFCに相当する仕組みで、GitHub上のPull Requestとして議論・採択されます。本記事では SEP-2575 のような形で番号を参照します。

Tier 1 SDK

MCPが導入したSDKの階層制度で、全プロトコル実装を含む完全サポートのSDKを指します。TypeScript、Python、Goなどの公式SDKがこれにあたります。後述する適合性テストスイート(conformance suite)でスコアリングされます。


2. 何が起きるのか ― リリースの時系列

日付できごと
2025-11-25現行の最新仕様「MCP 2025-11-25」公開
2026-05-21次期仕様のリリース候補(RC)が確定・凍結
2026-05-21 〜 07-2810週間の検証期間。Tier 1 SDKはこの間に対応版を出すことが期待される
2026-07-28仕様「MCP 2026-07-28」正式公開

RCが凍結されてから正式公開まで10週間の猶予が置かれているのがポイントです。これは「SDKメンテナとクライアント実装者が、実ワークロードに対して変更を検証するための期間」と明示されています。つまり7月28日時点で主要SDKは既に対応済みという前提で設計されたスケジュールです。

なお、この仕様には破壊的変更(breaking changes)が含まれます。公式も「これを常態にするつもりはない」と断ったうえで、今回は基盤的な変更ゆえのクリーンブレイクだと説明しています。


3. 本丸: プロトコルのステートレス化

3.1 これまで(2025-11-25まで)はどうだったか

Streamable HTTPでツールを1回呼ぶだけでも、以下の手順が必要でした。

  1. クライアントが initialize メソッドを送り、プロトコルバージョン・クライアント情報・ケイパビリティ(対応機能)を申告する
  2. サーバが Mcp-Session-Id ヘッダでセッションIDを払い出す
  3. 以降のすべてのリクエストにそのセッションIDを載せる
  4. サーバ側はセッションIDから状態を復元して処理する
POST /mcp HTTP/1.1
Content-Type: application/json

{"jsonrpc":"2.0","id":1,"method":"initialize","params":{...}}

↓ サーバがセッションIDを返す ↓

POST /mcp HTTP/1.1
Mcp-Session-Id: <払い出されたID>
Content-Type: application/json

{"jsonrpc":"2.0","id":2,"method":"tools/call","params":{...}}

この設計の運用上の問題が、今回の改訂の動機です。

セッションIDを払い出したインスタンスにクライアントがピン留めされるため、水平スケールする構成では以下が必須になっていました。

つまり、普通のHTTP APIなら不要なインフラ装備を、MCPのためだけに用意する必要があったわけです。

3.2 これから(2026-07-28)はどうなるか

同じツール呼び出しが、1本の自己完結したリクエストになります。

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

{"jsonrpc":"2.0","id":1,"method":"tools/call",
 "params":{"name":"search","arguments":{...},
           "_meta":{"io.modelcontextprotocol/clientInfo":{...}}}}

変わった点を分解します。

(a) initialize / initialized ハンドシェイクの廃止(SEP-2575)

接続時に1回だけ交換していたプロトコルバージョン・クライアント情報・クライアントケイパビリティは、毎リクエストの _meta フィールドに載せて運ぶ方式に変わりました。

「毎回送るのは冗長では?」と思うかもしれませんが、これは典型的なステートレス設計のトレードオフです。わずかなペイロード増加と引き換えに、サーバ側の状態管理が丸ごと消えます。HTTPがCookieやトークンを毎回送るのと同じ発想ですね。

サーバ側のケイパビリティを事前に知りたい場合のために、server/discover という新メソッドが用意されています。必要なときに取りに行く(pull型)に変わった、と理解するとよいでしょう。

(b) Mcp-Session-Id ヘッダとプロトコルレベルのセッションの廃止(SEP-2567)

これにより、任意のMCPリクエストが任意のサーバインスタンスに着地できるようになりました。スティッキールーティングも共有セッションストアも、プロトコル層としては不要になります。

図式的に言えば:

【Before】
 Client ──> LB(スティッキー) ──> Server A ─┐
                                Server B ─┼─> 共有セッションストア(Redis等)
                                Server C ─┘

【After】
 Client ──> LB(ラウンドロビン) ──> Server A
                                 Server B    ※セッションストア不要
                                 Server C

(c) 「ステートレスなプロトコル、ステートフルなアプリケーション」

ここは誤解しやすいので強調しておきます。プロトコルがステートレスになった=アプリケーションが状態を持てなくなった、ではありません。

状態を持ちたいサーバは、HTTP APIが昔からやってきたことをやればよい、というのが公式の回答です。すなわち 明示的ハンドル(explicit handle)パターン:

  1. ツールが basket_idbrowser_id のような識別子を発行して返す
  2. モデルはそれを普通の引数として次のツール呼び出しに渡す
model ──> create_basket()        ──> { basket_id: "..." }
model ──> add_item(basket_id, …) ──> { ok: true }

公式は、これを単なる代替手段ではなくむしろ優れた方式だと述べています。理由は、状態がトランスポートのメタデータに隠蔽されるのではなく、モデルから見える形で表に出るためです。モデルはハンドルを複数ツール間で組み合わせたり、それについて推論したり、ステップ間で受け渡したりできます。

エージェント設計をやっている人には響く話だと思います。「見えない状態」はモデルにとってデバッグ不能なブラックボックスですが、引数として明示されていれば推論の対象になります。

(d) サーバ→クライアント方向のリクエストの再設計

ステートレスにしても、サーバが処理の途中でクライアントに問い合わせたい場面はあります。典型は elicitation(エリシテーション)、つまり「この3ファイルを削除していいですか?」のようにユーザへ確認を求める仕組みです。

これが2つのSEPで作り直されました。

SEP-2260: サーバ起点リクエストのタイミング制約

サーバからのリクエストは、サーバがクライアントのリクエストを能動的に処理している最中にのみ発行可能になりました。従来は推奨(RECOMMENDED)でしたが、必須(REQUIRED)に格上げされています。

セキュリティ的な意味は明快です。ユーザが何もしていないのに、突然プロンプトが飛んでくることがなくなる。すべてのelicitationが、ユーザ(またはそのエージェント)が開始した何かに紐づいてトレースできます。

SEP-2322: Multi Round-Trip Requests(複数ラウンドトリップ・リクエスト)

従来はSSEストリームを開きっぱなしにして確認を送っていましたが、新方式ではサーバがいったん InputRequiredResult を返して処理を打ち切ります

{
  "resultType": "inputRequired",
  "inputRequests": {
    "confirm": {
      "type": "elicitation",
      "message": "…",
      "schema": { "type": "boolean" }
    }
  },
  "requestState": "<Base64エンコードされた継続情報>"
}

クライアントはユーザから回答を集め、元の呼び出しを inputResponses と、そのまま返す requestState を付けて再送します。

requestState に処理の続行に必要な情報がすべて入っているので、再送先はどのインスタンスでも構いません。継続(continuation)をペイロードに載せて外出しする、という古典的なテクニックです。JWTでセッションを外出しするのと同じ発想と考えるとイメージしやすいでしょう。

GitHubのChangelogでは、この変更によって「リモートサーバでもelicitationのような機能をサポートしやすくなる」と述べられています。長時間SSEを維持できない環境でも実装できるようになったためです。

(e) ルーティング・キャッシュ・トレースの改善

運用面での地味に効く3点です。

Mcp-Method / Mcp-Name ヘッダの必須化(SEP-2243)

Streamable HTTPで、呼び出すメソッド名とツール名をHTTPヘッダに出すことが必須になりました。

これにより、ロードバランサ・APIゲートウェイ・レートリミッタが、ボディを解析せずに操作単位でルーティングや制限をかけられます。前述のDPIが不要になる、という話です。

なお、ヘッダとボディの内容が食い違うリクエストはサーバが拒否することになっています(ヘッダだけ書き換えて制限を回避する攻撃への対策)。

ttlMs / cacheScope の導入(SEP-2549)

リスト系(tools/list 等)とリソース読み取りの結果に、キャッシュ制御用のフィールドが追加されました。HTTPの Cache-Control をモデルにしています。

従来は「ツール一覧が変わったこと」を知るために長寿命のSSEストリームを維持するしかありませんでしたが、その必要がなくなりました。

W3C Trace Contextの伝播を明文化(SEP-414)

分散トレーシングの標準規格である W3C Trace Contexttraceparent / tracestate / baggage というHTTPヘッダで、複数サービスをまたぐ1つの処理を追跡するための仕様)のキー名が、_meta 内で正式に固定されました。

すでに一部のSDKやツールが独自に実装していたものを、仕様として名前を確定させた形です。これによって、ホストアプリケーション → クライアントSDK → MCPサーバ → その先の下流サービス、という一連の流れが、OpenTelemetry互換のバックエンドで1つのスパンツリーとして可視化できます。

OpenTelemetry(OTel): トレース・メトリクス・ログを収集するためのベンダー中立な観測(オブザーバビリティ)標準。CNCFプロジェクト。

エージェントのデバッグは「どのツール呼び出しが遅いのか/失敗しているのか」の特定が難しいので、これは実運用でかなり効いてくるはずです。


4. Extensions(拡張機能)が一級市民に

拡張の仕組み自体は 2025-11-25 にも存在しましたが、正式なプロセスがありませんでした。SEP-2133がこれを整備しています。

今回のリリースには2つの公式拡張が含まれます。

4.1 MCP Apps ― サーバがレンダリングするUI(SEP-1865)

サーバがインタラクティブなHTMLインターフェースを提供し、ホスト(Claude DesktopやVS Codeのようなクライアントアプリ)がサンドボックス化されたiframe内でレンダリングする仕組みです。

設計上のポイントが2つあります。

  1. ツールはUIテンプレートを事前に宣言する。これによりホスト側は、実行前にプリフェッチ・キャッシュ・セキュリティレビューができます。「実行時に任意のHTMLが降ってくる」わけではない、というのが重要です。
  2. レンダリングされたUIからホストへの通信は、MCP標準のJSON-RPCベースプロトコルを使う。つまり、UI起点のアクションも、直接のツール呼び出しとまったく同じ監査・同意(consent)のパスを通ります。

「AIが表示したボタンを押したら、承認フローを迂回して何かが実行された」という事故を構造的に防ぐ設計です。

GitHubのChangelogによれば、MCP AppsはVS Codeで既にサポート済みとのことです。

4.2 Tasks が拡張へ「降格」

Tasks(長時間かかる処理を非同期に扱う仕組み)は 2025-11-25実験的なコア機能として出荷されましたが、本番利用で再設計が必要なことが判明し、仕様本体ではなく拡張が適切な置き場所と判断されました。

新しいTasks拡張は、ステートレスモデルに合わせてライフサイクルが作り直されています。

⚠️ 移行が必要: 2025-11-25 の実験的Tasks APIに対して実装した人は、新しいライフサイクルへの移行が必要です。


5. 認可(Authorization)の堅牢化

6本のSEPで、OAuth 2.0 / OpenID Connect の実運用での使われ方に近づける修正が入りました。主なものを挙げます。

iss パラメータの検証を必須化(SEP-2468 / RFC 9207)

認可レスポンスに含まれる iss(issuer: 発行元の認可サーバ識別子)を、クライアントが検証しなければならなくなりました。

これは mix-up攻撃(複数の認可サーバを使う構成で、攻撃者が認可レスポンスをすり替え、正規サーバ向けの認可コードを別のサーバに渡させる攻撃)への対策です。

MCPは「1つのクライアントが多数のサーバに接続する」というデプロイパターンが支配的なため、この攻撃クラスのリスクが相対的に高い、と公式は説明しています。低コストな緩和策として導入されました。

将来のバージョンでは、iss を含まないレスポンスをクライアントが拒否することが期待されます。認可サーバ側は今のうちから iss を返すようにしておくべきです。

DCRでの application_type 宣言(SEP-837)

DCR(Dynamic Client Registration): クライアントが認可サーバに対して、事前の手動登録なしに自分自身を動的に登録する仕組み。

クライアントが OpenID Connect の application_type を登録時に宣言できるようになりました。

これが解決するのは、非常によくある実装上の詰まりです。従来は、デスクトップアプリやCLIクライアントを認可サーバが "web" としてデフォルト扱いしてしまい、localhost へのリダイレクトURIが拒否される、という事象が頻発していました。

その他


6. 非推奨(Deprecated)になった機能

新設された機能ライフサイクルポリシー(SEP-2577)に基づき、3つのコア機能が非推奨になりました。

機能何だったか代替
Rootsクライアントがサーバに「作業対象のディレクトリ範囲」を伝える仕組みツールのパラメータ、リソースURI、サーバ側の設定
Samplingサーバがクライアント経由でLLM推論を要求する仕組みLLMプロバイダAPIとの直接統合
Loggingサーバがクライアントに構造化ログを送る仕組みstdioトランスポートでは stderr、構造化された観測にはOpenTelemetry

重要なのは、これが アノテーションのみの非推奨(annotation-only deprecation) である点です。

つまり「今すぐ壊れる」話ではありません。ただし、新規実装でこれらに依存するのは避けるべきです。

Samplingの非推奨は個人的に象徴的だと感じます。「MCPサーバがクライアントのLLMを間借りする」という発想自体が、各サーバが自前でLLM APIを叩ける現在の状況では不要になった、ということでしょう。


7. ツールスキーマが JSON Schema 2020-12 に全面対応(SEP-2106)

ツールの inputSchema / outputSchema が、JSON Schema 2020-12 の全機能を使えるようになりました。

JSON Schema 2020-12: JSONデータの構造を宣言的に記述・検証するための仕様。2020年12月版がドラフトの最新安定版として広く使われています。

実装者向けの注意として、以下が明記されています。

地味だが実害のある変更: エラーコード

リソースが見つからない場合のエラーコードが、MCP独自の -32002 から、JSON-RPC標準の -32602(Invalid Params)に変更されます(SEP-2164)。

クライアント側で -32002 をリテラルにマッチしている実装は、必ず修正が必要です。 移行時のチェック対象として真っ先に挙がるポイントです。


8. 今後プロトコルはどう進化するのか

今回は破壊的変更を含みますが、公式は「これを常態にはしない」と明言しています。そのためのガバナンス系SEPが3本入りました。

  1. 機能ライフサイクルポリシー: すべての機能に *Active* → *Deprecated* → *Removed* のライフサイクルを定義。非推奨化から最短の削除時期まで、最低12ヶ月を確保する。
  2. Extensionsフレームワーク: 新機能はまずオプトインの拡張として出荷し、そこで安定化させてから(必要なら)仕様本体に取り込む。
  3. 適合性テストとの連動(SEP-2484): Standards Track のSEPは、適合性スイート(conformance suite)に対応するシナリオが入るまで Final にできない。このスイートは、SDK階層制度が公式SDKを採点するのと同じものです。

つまり、「仕様書に書いてあるが誰も実装を検証していない機能」が生まれにくい構造になりました。

公式の見通しとしては、2026-07-28 をターゲットに実装しておけば、今後の改訂ではトランスポート層やライフサイクル層のコードを書き直さずに追従できるはず、とされています。


9. GitHub MCPサーバは何をやったか ― 実装事例として読む

GitHubは7月23日付のChangelogで、正式リリースに先行して最新仕様に対応済みであることを発表しました。

前提として、Tier 1 SDKはすべて後方互換性を維持しており、ベータ対応も出荷済みなので、「サポートを維持するために利用者側で何かする必要はない」とされています。GitHub MCPサーバ自身は公式のGo SDKを使っています。

そのうえでGitHubが行った変更は3つです。これが実装者にとって一番参考になる部分なので、詳しく見ます。

(1) Redisセッションの削除

セッションIDを永続化・参照するためのRedisアクセスが、リクエストパスから丸ごと消えたわけです。「ユーザが何かを失うことなく、動作がキビキビする」と表現されています。

これはステートレス化の効果を最も端的に示す事例です。ツール呼び出し1回あたりのレイテンシから、ネットワークを1往復するストレージアクセスが消えるのですから、体感差は小さくないはずです。

(2) DPI(Deep Packet Inspection)の回避

GitHubは、ロギングとシークレットスキャン(トークンなどの機密情報の混入検知)のために、MCPリクエストからいくつかの値を読み取る必要があります。

従来はそのために、SDKが処理する前に、すべてのリクエストのペイロードを解析していました。新仕様では、必要な値が必ず存在するHTTPヘッダ(前述の Mcp-Method / Mcp-Name)から取得できるため、この事前解析が不要になりました。

エッジ・ゲートウェイ層を自作している人には、そのまま効く話です。

(3) elicitation実装のアップグレード

GitHubのstdio版MCPサーバは、ユーザログインを簡単にするために URL elicitation(ブラウザで開くURLをユーザに提示する形の確認)を使っています。

新プロトコルでは、前述のMulti Round-Trip Requestsにより各ステップが独立したHTTPリクエストになります。旧クライアントと新クライアントの両方で動かすため、Go SDKが両方式を吸収するラッパーを提供しているとのことです。

移行期のクライアント/サーバのバージョン混在を、SDK層で吸収する ― という実装パターンの好例です。

おまけ: 適合性テストとAI支援開発

GitHubは、MCPに公式の適合性テストが追加されたことにも触れています。厳密な検証があると、エージェント自身が自分の実装を検証できるためです。

具体的な使い方として、Copilot(あるいは任意のコーディングエージェント)に対して以下へのアクセスを与えることを推奨しています。

AI支援でMCPサーバを実装するなら、「仕様書+SDK実装+テストスイート」の3点セットをコンテキストに入れる、というのは素直に有用なプラクティスだと思います。検証可能なテストがある領域では、エージェントのループが正しく閉じるためです。


10. 移行チェックリスト

自分のMCP実装を点検するときの観点を、影響度順にまとめます。

サーバ実装者

クライアント実装者

インフラ/プラットフォーム担当


11. 所感 ― 「普通のHTTP API」に戻ってきた

今回の改訂を一言でまとめるなら、MCPが特殊なプロトコルであることをやめ、ごく普通のHTTP APIとして扱えるようになったということだと思います。

ステートフルなセッション、SSEの張りっぱなし、ボディを解析しないとルーティングできない構造 ― これらはすべて、既存のHTTPインフラ(LB、CDN、APIゲートウェイ、WAF、キャッシュ、トレーシング)の恩恵を受けられなくする要因でした。仕様がそれらを捨てたことで、この20年分のWebインフラの蓄積がそのまま使えるようになります。

同時に、「状態はプロトコルではなくアプリケーションが、モデルから見える形で持つ」という方針転換は、エージェント設計の思想としても筋が通っています。隠れた状態はモデルにとって推論不能ですが、引数として表に出ていれば、モデルが組み合わせ・受け渡し・検証の対象にできる。LLMを主役に据えたときに正しい設計はどちらかを考え抜いた結果に見えます。

破壊的変更は痛みを伴いますが、機能ライフサイクルポリシー・Extensionsフレームワーク・適合性テストという3点セットのガバナンスが同時に入ったことで、これが最後の大きな断絶になるという公式の主張には説得力があります。


参考リンク(一次情報)