プロダクト発表 · 小互解読

Anthropic、MCPの新仕様を発表――MCPサーバーをクラウドにデプロイ可能に

MCP発表以来で最大級の変更ですが、7月28日は一斉切り替えの日ではありません。既存の実装は今まで通り相互接続できます。
1分でわかる要点
  • これまでMCPサーバーには弱点がありました。クライアントは最初にハンドシェイクをしてセッションIDを受け取り、以降のリクエストは必ず同じマシンに戻らなければなりませんでした。マシンを増やしても意味がなく、サーバーレスでも動かせなかったのです。
  • 新仕様はこのルールを廃止しました。ハンドシェイクとセッションIDをまるごと削除し、各リクエストが自分で身元情報を持つようにしたことで、どのマシンでも受け付けられます。ごく普通のロードバランサーを立てるだけで済みます。
  • サーバーが処理の途中でユーザーに一言確認したい場合(たとえば「この操作は課金が発生しますが、よろしいですか」など)、今は2往復が必要です。まず「情報が足りません」と返し、クライアントがユーザーに確認してから、元のリクエストを丸ごと再送します。
  • 状態管理そのものが消えたわけではなく、表舞台に移っただけです。サーバーがハンドルを発行し、モデルがそれをパラメータとして渡し返します。
  • いくつかの機能は削除、あるいは猶予期間付きで廃止予定になりました。ハンドシェイク、セッションID、SSEの再接続はすでに削除。Roots、Sampling、Loggingと旧HTTP+SSEトランスポートは、少なくとも12か月は引き続き使えます。
  • 第三者によるセキュリティ分析では、この仕様がセッションハイジャックのような旧来の脆弱性を消し去った一方、開発者に新たなセキュリティ責任を負わせている点が指摘されています。たとえば、1回のリクエストでサーバーに重い処理を起動させ、すぐに離脱するといった攻撃です。
  • 最も実用的なポイント: 7月28日は一斉切り替えの日ではありません。今使っているサーバーとクライアントは壊れず、新しいクライアントが古いサーバーに接続した場合は自動的に旧来のハンドシェイクにフォールバックします。
⚑ 主な材料はMCP公式発表ブログと同日のAnthropic公式アナウンスです。プロトコルの詳細は仕様本文とchangelogに基づいています。本文中のエコシステム企業による性能・効果の数値は各社の発表によるものです。セキュリティの節は第三者情報源によるもので、出典は文末に記載しています。
出発点

旧MCPのボトルネック――セッションがサーバーを1台のマシンに縛りつけていた

2026年7月28日、MCP公式が第5版仕様2026-07-28を発表し、プロトコルの中核をステートフルな双方向接続からステートレスなリクエスト/レスポンス方式に転換すると同時に、正式な拡張フレームワークと廃止ポリシーを導入しました。Anthropicも同日、Claudeの全製品ラインでこれに追随すると発表しています。

MCPはAIアシスタントを外部のツールやデータに接続するためのプロトコルで、Anthropicが2024年末にオープンソース化して以降、業界全体で広く使われています。主要な4つのSDK(TypeScript、Python、Go、C#)の月間ダウンロード数は合計で約5億回に達し、うちTypeScriptとPythonはそれぞれ累計ダウンロード数が10億回を超えています。

約5億第一線の4つのSDKの月間ダウンロード数合計
950以上Claudeコネクタディレクトリに登録済みのMCPサーバー数
約20%honeycomb.ioの月間インタラクティブクエリのうちAgent発のもの

今回の改訂が解決しようとしているのは、非常に具体的なエンジニアリング上の行き詰まりです。MCPサーバーをクラウドにデプロイして大勢に使ってもらうのが難しい、という問題です。

たとえるなら

旧MCPは電話をかけるようなものでした。まずダイヤルして(initializeハンドシェイク)、オペレーターから内線番号(Mcp-Session-Id)をもらいます。以降はその内線番号で本人確認をします。オペレーターを変えたいですか?残念ながら、あなたがさっき何を話したか覚えているのは元のオペレーターだけです。

新MCPは宅配便のようなものです。荷物ひとつひとつに送り主・受取人・内容の説明が完全に書かれたラベルが貼られていて、誰が受け取っても処理できます。事前に誰かと打ち合わせる必要はありません。

「電話をかける」というこの設計は、3つの連鎖的な問題を引き起こしていました。

第一に、マシンを増やしても効果がありません。2台目のマシンはあなたの内線番号を知らないので、リクエストが届いてもそのまま固まります。スケールさせるには、ロードバランサーに「誰がどのマシンに行くべきか」を覚えさせる(これをスティッキーセッションと呼びます)か、全マシンでRedisのような共有ストレージからセッションを参照するしかありません。

第二に、サーバーレスやエッジノードでは動きません。こうした環境は「呼び出しのたびに完全に新規で、終わったら忘れる」ことを前提に設計されており、「セッションを覚えておく」という性質と根本的に相性が悪いのです。

第三に、間に立つゲートウェイがあなたの操作内容を理解できません。リクエストの内容はすべてJSONのリクエストボディに入っているため、経路上のロードバランサーや制限機構、ファイアウォールが「今回はどのツールを呼んでいるか」に基づいてルーティングやレート制限をかけようとすると、そのJSONを解析するコストが高く、多くのゲートウェイはそもそもそこまでやっていません。

以前 · セッションあり
ロードバランサー
(誰がどのマシンか覚える必要)
インスタンス1
アイドル
インスタンス2
ここだけ
インスタンス3
アイドル
このクライアントの全リクエストは
必ずインスタンス2に戻る必要がある
現在 · ステートレス
ロードバランサー
(ラウンドロビンでOK)
インスタンス1
インスタンス2
インスタンス3
どのインスタンスでも
どのリクエストでも受けられる
本サイト作成の図解: 同一クライアントのリクエストが新旧の仕様でどこに落ち着くかの違い
仕組み

ステートレスな中核は具体的にどう実現されているか

では、新仕様はどうやってこの行き詰まりを解決したのでしょうか。3つのポイントがあります。

ハンドシェイクが消えた

initializenotifications/initializedという一連の開始儀式は完全に削除され、Mcp-Session-IdというHTTPヘッダーも削除されました。以前はハンドシェイク時にやり取りしていた情報――プロトコルバージョン、クライアントは誰か、クライアントがどの能力をサポートしているか――は、今では各リクエストが自分で持ち、_metaフィールドに入れて送ります。サーバー側も、返す結果ごとの_metaに自身の身元を報告することが推奨されています。

HTTPヘッダー · ゲートウェイはこれだけ読めば十分
POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search
リクエストボディの _meta · 各リクエストが自ら身元を名乗る
io.modelcontextprotocol/protocolVersion
必須
今回のリクエストがどのバージョンのプロトコルに基づくか
io.modelcontextprotocol/clientCapabilities
必須
クライアントがサポートする能力。サーバーはクライアントが宣言していない能力を使ってはならず、使った場合は能力不足エラー(-32021)を返す
io.modelcontextprotocol/clientInfo
推奨
クライアントの名前とバージョン。仕様には、これは自己申告であり、プロトコル側では検証しない、表示・ログ・デバッグのみに使うべきで、これをセキュリティ判断に使ってはならないと明記されている
io.modelcontextprotocol/logLevel
任意
このリクエストについてサーバーがどのくらい詳細なログを出すべきか。このフィールドを含まないリクエストに対して、サーバーはログメッセージを送ってはならない
2026-07-28リクエストの見た目: 身元情報が「ハンドシェイク時に一度だけ言う」から「毎回言う」に変わった
公式発表ブログの完全なサンプル
POST /mcp HTTP/1.1
MCP-Protocol-Version: 2026-07-28
Mcp-Method: tools/call
Mcp-Name: search

{"jsonrpc":"2.0","id":1,"method":"tools/call",
 "params":{"name":"search","arguments":{"q":"otters"},
 "_meta":{"io.modelcontextprotocol/clientInfo":{"name":"my-app","version":"1.0"}}}}
「otters」というパラメータでsearchツールを呼び出す1回のリクエスト。パッケージ全体にコンテキストが自己完結しているため、どのマシンに落ちても単独で処理を完了できます。

サーバーの機能を事前に確認する新しい方法

新たにserver/discoverが追加され、サーバーがサポートするプロトコルバージョン、どんな能力を持つか、自分は何者かを確認できるようになりました。ここでの役割分担は明確です。サーバーは必ずこれを実装しなければならず、クライアントは使わなくても構いません。クライアントが望めば、何かを始める前に一度これを問い合わせることができますが、問い合わせずに直接リクエストを送っても完全に合法です。これは必須の開始儀式だった旧来のinitializeとは本質的に異なり、あくまで一回限りの通常のクエリです。

仕様が明言していること――接続とセッションはイコールではない

仕様本文の要求

サーバーは、同一接続上の以前のリクエストからコンテキスト(能力、プロトコルバージョン、クライアントの身元を含む)を推測することに依存してはならない。各リクエストは_metaでこれらの情報を自ら提供する。

開いたままの接続――たとえばずっと動き続けるローカルのstdioプロセスのようなもの――であっても、それは会話ではない。クライアントは同一のパイプの中にまったく無関係なリクエストを詰め込んでも構わず、サーバーは「接続の身元」を「セッションの身元」として扱ってはならない。

ちなみに、subscriptions/listenのような長時間接続もステートレス性を壊しません。それ自体は依然として通常のリクエスト/レスポンスであり、ただその「レスポンス」が開いたままの通知ストリームであるというだけです。その状態はそのリクエストに属するものであり、下層の接続には属しません。

公式発表ブログに掲載されたステートレスコアのデモ動画(オリジナル動画、出典: MCP公式ブログ)
誤解しやすいポイント

重要な点: 状態は消えたのではなく、暗がりから明るい場所へ移っただけ

ここで最も誤解されやすいポイントがあります。プロトコル層にセッションがなくなったからといって、あなたのアプリケーションがステートレスでなければならないわけではありません。

もしサーバーが複数回の呼び出しをまたいで何かを覚えておく必要があるなら、公式が示している方法はこうです。ツールから明確な「ハンドル」を発行し、モデルがそれを普通のパラメータとして扱い、以降の呼び出しで渡し返す、というものです。

以前 · 状態はトランスポート層に隠れていた
  • セッションIDはトランスポート層が管理し、モデルからは見えない
  • 状態は接続に付随し、接続が切れると状態も消える
  • 別のマシンで処理すると迷子になる
  • 問題が起きても調査しづらい。状態がビジネスコードの中にないため
現在 · ハンドルが表舞台に
  • サーバーがツールからハンドルを返す。これは普通の戻り値にすぎない
  • モデルからそれが見え、自分でツール間を連携させられる
  • ツールのパラメータとして渡され、接続とは無関係
  • 状態はビジネス層が管理し、参照も調整もできる

公式は発表ブログでこの方式を選んだ理由として、モデルがこの状態を見られる点がトランスポート層に隠れたセッション状態より優れていると述べています。

これはトランスポート層にセッション状態を隠すよりも扱いやすいことがわかりました。モデルにはこのハンドルが見えるため、自分でツール間をまたいで連携させられます。

MCP公式発表ブログ、2026-07-28(訳文)

ここには指摘しておくべきトレードオフがあります。状態管理という仕事自体が消えたわけではなく、「トランスポート層がこっそり代行してくれる」から「あなた自身がビジネス層で明示的に管理する」に変わったのです。メリットは透明性・追跡可能性・水平スケーラビリティ。代償は、それが今やあなたのビジネス層の仕事になったことです。

核心機能

MRTR: サーバーがユーザーに一言確認したいときは、今は2往復必要

サーバーがもう能動的に話しかけられないなら、途中でユーザーに確認したいときはどうするのでしょうか。

まずどんな場面かを説明します。あるツールが処理の途中で、ユーザーに何かの確認を求める必要があるケースです。SupabaseのMCPサーバーが新しいプロジェクトを作成する際、まず「これは課金が発生しますが、よろしいですか」と一言確認したい。あるいはデータを削除するSQLの場合、先にユーザーにOKをもらう必要がある、といったケースです。

以前のやり方は、サーバーが開いたままの双方向ストリームから逆方向にクライアントへリクエストを送り、一言尋ねる(elicitation/create)、クライアント側のモデルを借りて計算する(sampling/createMessage)、あるいはファイルディレクトリの場所を尋ねる(roots/list)というものでした。前提として、そのストリームがずっと開いている必要があり、これはまさにステートレス化が取り払おうとしているものです。

新しいやり方はMRTR(Multi Round-Trip Requests、複数往復リクエスト)と呼ばれます。サーバーはもうリクエストを送らず、代わりに「まだ完了していない結果」を返し、尋ねたい質問をその中に入れます。クライアントがユーザーに確認したあと、答えを添えて元のリクエストを丸ごと再送します。以下の5ステップをクリックしてその流れを確認できます。

クライアント
(Claudeなど)
MCPサーバー
第1段階 · クライアント → サーバー
{"id":1, "method":"tools/call",
 "params":{"name":"create_project", …}}

クライアントはいつも通りツール呼び出しを開始し、リクエストIDは1です。この段階は以前と変わりません。

第2段階 · サーバー → クライアント
{"result":{
  "resultType":"input_required",
  "inputRequests":{"confirm":{…}},
  "requestState":"署名付きの不透明データ"}}

サーバーは情報が足りないことに気づき、結果を返します(リクエストを送るのではない点に注意)。resultTypeinput_requiredとし、inputRequestsに尋ねたい質問を入れます。

requestStateはサーバーがクライアントに預ける不透明なデータで、「自分がどこまで処理を進めたか」を記憶するためのものです。これによりサーバー自身は何も保存しなくて済みます。

第3段階 · クライアントのローカル処理

クライアントはユーザーに質問を提示します。「この新規プロジェクトの作成には課金が発生しますが、よろしいですか?」ユーザーは確認をクリックします。

この段階にサーバーは一切関与しません。この間にサーバーが回収されて別のマシンに切り替わっても構いません。規約により、クライアントはrequestStateの中身を閲覧・解析・改変してはならず、それについていかなる想定もしてはならず、そのまま保管するだけです。

第4段階 · クライアント → サーバー(別のマシンの可能性あり)
{"id":2, "method":"tools/call",
 "params":{"name":"create_project", …,
  "inputResponses":{"confirm":{…}},
  "requestState":"そのまま持ち帰る"}}

クライアントは回答をinputResponsesに入れ、元のリクエスト全体を再送し、requestStateもそのまま持ち帰ります。

リクエストIDは必ず新しいものにしなければなりません(ここでは2)。仕様が明確に要求しており、これはプロトコル上では2つの独立したリクエストとみなされるためです。

第5段階 · サーバー → クライアント
{"result":{"resultType":"complete", …}}

サーバーは今度は情報が十分にそろい、処理を実行して最終結果を返します。

この一連のやり取りは、どの段階も「同一マシン」や「同一接続」に依存していません。

本サイト作成の図解: MRTRの5ステップの往復。仕様本文「基本フロー」の節に基づいて作成

Supabaseのプロダクト責任者は、このパターンが長年やりたかったことを実現させたと語っています。

ユーザーへの確認をサポートすることは、以前からロードマップに載っていましたが、Supabase MCPがステートレスで動作していたため、なかなか実現できませんでした。MRTRがそれを変えたのです。おかげで、私たちのツールは実行前にユーザーへ確認を取れるようになりました。たとえば新規プロジェクト作成の課金や、データを削除するクエリについてです。

Inian Parameshwaran、Supabaseプロダクト責任者(訳文)

代償は2か所にある

第一に、元のリクエストを丸ごと再送する必要があります。サーバーは、中間結果をrequestStateにエンコードしておかない限り、前回の処理をやり直す羽目になる可能性があります。

第二に、requestStateは慎重に扱うべき手榴弾のような存在です。これはクライアントの手元を一巡してから戻ってくるため、仕様の要求はかなり厳格です。

requestStateに関する仕様の要求

サーバーはrequestState攻撃者が制御可能な入力として扱わなければならない。これが認可・リソースアクセス・ビジネスロジックに影響する場合、サーバーはHMACやAEADなどの手段で完全性を保護しなければならない(誰にも偽造できない封印を押すようなもの)。検証に失敗したものは直ちに拒否する。この保護を省略できるのは、改ざんされてもせいぜい今回のリクエストが失敗するだけで、それ以上悪い結果にならない場合のみである。

リプレイ防止についてはこの仕様は「すべき」レベルにとどまっており、具体的にはこの保護されたデータの中に3つの要素を入れて逐一チェックすることが挙げられている。誰のものか(別人が流用した場合は拒否)、いつまで有効か(タイムアウトしたら拒否)、元はどのリクエストか(メソッド名と主要パラメータのダイジェストが一致しなければ拒否)。

仕様はさらに率直にこう補足している。これらの対策はリプレイ可能な時間枠を縮小し、ユーザー横断・リクエスト横断の再利用を防ぐだけであり、「一度きりの使用」を保証するものではない。本当に一度きりが必要な場面(たとえばワンタイムの引き換えコードなど)は、サーバー側で別途保証する必要がある。

サーバーが不要になった共有ストレージの代わりに、正しい暗号署名を自分で書く必要が出てきたわけです。

もう一点、MRTRには適用範囲があります。prompts/getresources/readtools/callの3つのメソッドでのみ使用可能で、それ以外のリクエストではサーバーはinput_requiredを返してはなりません。

ルーティング

ゲートウェイがようやくMCPを理解できるようになった(発表ブログに載っていないセキュリティ機構つき)

状態の問題は解決しました。残るはもう一つの古い問題です。中間のゲートウェイは、これまで何が呼び出されているのか把握できませんでした。

新仕様は、各POSTリクエストに必須のHTTPヘッダーを追加しました。Mcp-Methodは各リクエストが必ず持ち、今回呼び出しているのがどのメソッドかを示します。Mcp-Nameは具体的な対象を指定する場合、すなわちtools/callresources/readprompts/getの3種類のリクエストのときだけ付き、呼び出し対象のツール・リソース・プロンプトを示します。もともと常に付いていたMCP-Protocol-Versionと合わせて、ゲートウェイ・レート制限機構・ファイアウォールはこの数行を読むだけで済むようになりました。

以前 · ゲートウェイはボディを解析する必要があった
{"jsonrpc":"2.0","id":1,"method":"tools/call","params":{"name":"execute_sql","arguments":{"query":"SELECT * FROM …","region":"us-east-1"},"_meta":{…}}}

どのツールが呼ばれているかを知るには、JSONリクエストボディ全体を解析するしかありません。高スループットのゲートウェイにとってこのコストは割に合わず、多くのゲートウェイはそもそもこれをやっていません。

現在 · ヘッダー2行を読むだけ
Mcp-Method: tools/call
Mcp-Name: execute_sql

メソッドとツール名によるルーティング・レート制限・計測・認可を、すべてヘッダー層で完結できます。リクエストボディに触れる必要はありません。

純粋な利便性機能のように聞こえますが、これには厳格な検証が1つ紐づいています。これは発表ブログには書かれていません。

サーバーはヘッダーとボディの一致を検証しなければならない

サーバーはMcp-MethodMcp-Nameなどのヘッダー値がリクエストボディ内の対応する値と一致するかを検証しなければならず、一致しない場合はHeaderMismatchエラー(エラーコード-32020)を返す。

なぜこれが必須なのか。検証しなければ、攻撃者はヘッダーに無害なツール名を書いてゲートウェイを通過させつつ、リクエストボディでは別の危険なツールを呼び出すことができてしまいます。ゲートウェイはヘッダーを見て通過させ、サーバーはボディを見て実行する――その間に穴が空くのです。

仕様は中間層にも特に念を押しています。プロトコルバージョンが古すぎる場合、あるいはヘッダーがそもそも付いていない場合は、検証されていないヘッダーを信用するより、いっそ拒否すべきだと。

もう一つ、新しくx-mcp-headerという仕組みもあります。サーバーはツールのパラメータ定義で「このパラメータをHTTPヘッダーに複製する」と指定でき、ヘッダー名はMcp-Param-{名前}となり、テナントなどの軸でのルーティングに便利です。この機能はサーバー側では任意ですが、クライアントは対応が必須です。これを覚えておいてください。あとでセキュリティの話でまた登場します。

節約条項

ツール一覧がついにキャッシュ可能に(上流のプロンプトキャッシュも守られる)

ステートレス化にはもう一つ副産物があります。一覧結果が接続に依存して変化しなくなったため、キャッシュできるようになったのです。

tools/listprompts/listresources/listresources/readresources/templates/listの5つのメソッドの戻り値には、今後2つのフィールドを必ず含めなければなりません。

ttlMs
このデータが何ミリ秒以内なら新鮮とみなせるか。クライアントはこれに従ってキャッシュし、毎回問い合わせずに済みます。
cacheScope
publicprivateかで、経路上の共有プロキシがみんなのために一括キャッシュできるかどうかが決まります。

もう一つ、要求レベルはやや低いものの、価値ははるかに大きい項目があります。サーバーはツール一覧を確定した順序で返すべきである。

これがなぜ価値があるのか説明が必要です。ツール一覧はモデルのプロンプトに組み込まれるものであり、プロンプトのキャッシュは先頭から逐字マッチングされます。冒頭が一文字でも変わると、それ以降のキャッシュはすべて無効になり、再計算・再課金されます。ツール一覧の返却順序が毎回バラバラだと、上流のキャッシュは永遠にヒットしません。

順序が安定
search
create_file
run_query
✓ プロンプトのプレフィックスが変わらず、キャッシュヒット
順序がランダム
run_query
search
create_file
✗ プレフィックスが変わり、丸ごと再課金
本サイト作成の図解: ツール一覧の順序が上流のプロンプトキャッシュに与える影響。ツール自体は一つも変わっておらず、並び順が違うだけ

「順序を安定させる」という小さな要求が、実際に浮かせる金額は無視できません。

セルフチェックリスト

何が削除され、何が猶予期間付きになったか

次は最も入念にチェックすべき部分です。手元のものがどれくらい壊れるか。今回のchangelogは合計で重大な変更9件、軽微な変更12件、廃止4件です。以下の2つのリストは特に注視すべきものです。

完全削除
新バージョンにはもう存在しない
  • initialize / notifications/initialized ハンドシェイク
  • Mcp-Session-Idヘッダーとプロトコルレベルのセッション
  • HTTP GETエンドポイント、resources/subscriberesources/unsubscribe統一されたsubscriptions/listen長時間ストリームに置き換え。クライアントは通知タイプごとに個別に購読する
  • pinglogging/setLevelnotifications/roots/list_changedログレベルは各リクエストの_metalogLevelを含める方式に変更
  • SSEの再接続Last-Event-IDヘッダーとSSEイベントID)ストリームが切れると、進行中のリクエストはそこで失われる。クライアントは新しいリクエストIDに切り替えて丸ごと再送する必要がある
  • tasks/resulttasks/listtasks/getによるポーリングに変更
  • notifications/elicitation/completeとURLパターンによる確認のelicitationId
  • サーバーが能動的にリクエストを送るというパターンそのものすべてMRTRに置き換え
猶予期間付き
まだ使えるが、最低12か月保証
  • Roots(サーバーにどのディレクトリを見るべきか伝える)ツールのパラメータ、リソースURI、サーバー設定で伝える方式に変更
  • Sampling(サーバーがクライアントのモデルを借用する)大手モデルベンダーのAPIに直接接続する方式に変更
  • Logging(プロトコル層のログ)stderrへの出力、あるいはOpenTelemetryの利用に変更
  • HTTP+SSEトランスポート2025-03-26の時点ですでにソフトに廃止予定だったが、今回正式に廃止状態に組み入れ、Streamable HTTPへの移行を求める
  • includeContextthisServerallServersの2つの値指定しないか、noneを使う
  • 動的クライアント登録(DCR)CIMDへの移行を推奨。互換性のためまだ残っているが、将来のバージョンで削除予定

エラーコードも変わった

リソースが見つからない場合のエラーコードは-32002から標準の-32602(無効なパラメータ)に変更され、JSON-RPC仕様と整合させました。さらに3つの新しいエラーコードが割り振られています。-32020はヘッダーとボディの不一致、-32021は必須能力の欠如、-32022はプロトコルバージョン非対応です。仕様は領分もはっきりさせています。-32000から-32019はレガシー領域で、これらの番号はポリシー導入前に各社が独自に占有していたものであり、今後はこの範囲に新しい番号を割り当ててはならず、新規実装もこれらを使うべきではありません。-32020から-32099は仕様専用です。

もしあなたのクライアントコードに-32002という数値がハードコードされていれば、今回修正が必要です。ただし修正しすぎないよう注意してください。仕様は同時に、クライアントが旧バージョンのサーバーから送られてくる-32002を引き続き受け入れることを要求しています。自分から発行しなくなるだけです。

廃止ポリシー自体が今回の新しい取り組み

以前は廃止のタイミングは完全に暗黙の了解に頼っていましたが、今回明文化されました。仕様は機能の3つの状態と最短期間を定義しています。

Active
利用中。仕様どおりに実装すればよい
SEP提案が
承認される
Deprecated
まだ完全に使えるが、新規プロジェクトでは使うべきでない。代替手段を明記する必要がある
最低
12か月
Removed
仕様から削除。過去バージョンのドキュメントでは引き続き参照可能
本サイト作成の図解: 機能ライフサイクルの3状態。仕様の機能ライフサイクルと廃止ポリシーに基づいて作成

この12か月は「その機能が廃止マークされたバージョンの仕様が発表された時点」から起算され、提案が確定した時点からではありません。これに加えて2つの付随ルールがあります。1つは統一された「削除待ちリスト」ページが用意され、各バージョンのchangelogを自分でつなぎ合わせて確認する必要がなくなったこと。もう1つは、主要SDKには次のバージョンで各言語のネイティブな方式で廃止を明示することが求められている点です(TypeScriptの@deprecated、C#の[Obsolete]、Javaの@Deprecated、GoのDeprecated:コメントなど)。これができない場合は降格プロセスに入ります。

新しい役割分担

拡張機能が正式な入口になった

中核がスリムになった今、新機能はどこに追加すればいいのでしょうか。

以前は、MCPに機能を追加したければ中核プロトコルに詰め込むしかありませんでした。Tasksもかつては「実験的機能」として中核にぶら下がっていました。今回、正式な拡張フレームワークが確立されました。中核はスリムなまま保ち、新機能は拡張として実装し、クライアントとサーバーはそれぞれ能力の中でどの拡張をサポートしているかを宣言します。

Tasks
長時間実行するタスク。サーバーはブロックして待たず、まずタスク番号を返す。クライアントはtasks/getで進捗をポーリングする。
MCP Apps
サーバーは会話の中で直接インタラクティブなUIをレンダリングできる。サンドボックス化されたiframe内で動作し、ユーザーはタブを切り替える必要がない。
EMA(エンタープライズマネージド認可)
管理者が会社のID基盤(Entra、Oktaなど)を通じて組織全体に一括で開通させ、ユーザーは初回ログイン時に自動的に接続される。
中核プロトコル 2026-07-28
ステートレスなリクエスト/レスポンス。拡張機能はその上に構築され、中核は個別の機能のために変更されなくなる
本サイト作成の図解: 中核プロトコルと3つの公式拡張機能の役割分担

Tasksは AWS が貢献した最初期の公式拡張のひとつです。AWSによれば、新仕様とそのステートレスな中核は、すでにAmazon Bedrock AgentCoreで利用可能とのことです。Tasksの仕組みは詳しく触れておく価値があります。あるリクエストが長時間かかるとサーバーが判断すると、最終結果ではなくタスク番号を返します。このタスク番号は永続的なハンドルであり、クライアントが接続を切っても、再起動しても、同じ番号で引き続きポーリングできます。タスクには5つの状態があります。

working 処理中
input_required 情報の補足が必要
completed 完了
failed 失敗
cancelled キャンセル

濃い色の3つは終了状態で、そこに到達すると以後変化しません。途中でユーザーへの確認が必要になると、タスクはinput_requiredに移行し、クライアントは新設のtasks/updateで回答します。2本目の接続は不要で、サーバーが能動的にメッセージを送る必要もありません。

認可

認可まわりが4か所引き締められた

削除・追加の話は一通り終わりましたが、公式が単独で取り上げているポイントがまだあります。この1年で実装者が最も時間を費やしたのが認可の領域でした。今回、4か所が変更されました。

iss検証(RFC 9207)
認可サーバーはコールバックで「自分は誰か」を含めるべきである。この値が現れた場合、クライアントは自身が記録している発行者と一致するか必ず検証しなければならず、検証を通過して初めて認可コードをトークンと交換できる。ここで防いでいるのは「認可サーバー混同」といった攻撃で、あなたの認可コードを別の認可サーバーに騙し取られて使われることを防ぐ。
登録時にapplication_typeを指定
多くの人がはまってきた落とし穴を修正するものです。デスクトップアプリやコマンドラインツールがOAuthフローを使う際、認可サーバーはデフォルトでそれをWebアプリとみなしてしまい、localhostコールバックアドレスを拒否してredirect_uriエラーを返していました。
認証情報を発行者に紐付け
クライアントが保存する認証情報は発行者ごとに分けて保存しなければならず、別の認可サーバーで使い回すことは禁じられる。認可サーバーが変われば再登録が必要になる。
DCRの引退、CIMDを推奨
以前はアプリが認可サーバーに接続するには、まず動的登録(DCR)が必要でした。CIMD(Client ID Metadata Documents、クライアントID メタデータ文書)は、アプリが自分の身元情報を公開URLに掲載し、認可サーバー側がそれを自ら読み取る方式に変え、登録という手順を省きます。

コマンドラインクライアントのOAuthフローでredirect_uriエラーが出るのはなぜだろうと悩んだことがある人は、たいていこれが原因です。

MCP公式発表ブログ、application_typeの変更について(訳文)
もう一つの側面

第三者によるセキュリティ分析: 責任がプロトコルから開発者へ移った

ただし、ここまでは公式見解です。仕様の正式発表前、第三者がこの新仕様を攻撃対象として調査しており、Akamaiが6月に分析結果を発表し、その内容はSecurityWeekで報道されました。

彼らの見解はこうです。新仕様は確かにいくつかの脆弱性を排除した一方で、同時にいくつかの新しい攻撃対象領域を開いており、しかもこれらの新リスクは開発者がどう実装するかに大きく依存する、というものです。

プロトコル層が排除したもの
  • セッションハイジャック——セッションがなくなったので、ハイジャックする対象もなくなった
  • サーバーからの能動的なプロンプト表示——サーバーはもう能動的にリクエストを開始できず、クライアントが尋ねてくるのを受動的に待つのみ
  • より強固な認証基準——前節で触れた4か所の引き締め
新たに開かれたもの
  • 状態オブジェクトや追跡識別子が予測可能な場合: 他人が進行中のワークフローを乗っ取られたり、別のAgentのデータを取得されたり、テナントをまたぐ権限逸脱操作を引き起こされたりする
  • x-mcp-headerによる情報漏洩: 開発者がうっかりAPIキー、トークン、個人情報をHTTPヘッダーにマッピングしてしまうと、これらの秘密情報はそのままヘッダーに押し込まれ、経路上のあらゆるロードバランサー・プロキシ・ログシステムから丸見えになる
  • プロトコル混同(Desync): ヘッダーとリクエストボディの不一致により、ヘッダーベースのセキュリティ制御を回避する。これはまさに仕様上の強制検証が防ごうとしているものだが、実際に防げるかどうかはサーバー実装者が真面目に実装しているかどうかにかかっている
  • MCP Appsがブラウザの旧来の問題を持ち込んだ: 格納型クロスサイトスクリプティング(XSS)など
  • Tasksは「起動して逃げる」型のサービス拒否経路になりうる: タスクの作成はクライアント側にとっては安価だが、サーバー側にとっては高コストである。攻撃者は1回のリクエストだけで、サーバーにCPU・メモリ・データベースストレージを食う重いタスクを起動させ、直後に切断して立ち去ることができる

プロトコルがステートレスモデルに転換し、さらにリッチUIアプリと非同期タスクを導入した以上、重要なセキュリティ境界は今や完全に開発者の実装方法次第になっています。

Maxim Zavodchik氏、Akamai脅威リサーチ シニアディレクター、SecurityWeekの報道より(訳文)

彼らの結論は、これらの変更の重みは漸進的な改善を超えているというものです。それは安全に関する責任の所在を根本的に作り変えました。以前はプロトコルによって強制的に保証されていたセキュリティ上の判断が、今ではますますMCPサーバーの開発者とプラットフォーム運用者に委ねられるようになっています。

報道では、同じくらい重要な一言も補足されています。MCPプロトコル自体が脆弱になったわけではなく、新仕様の上に構築されたMCPサーバー群の攻撃対象領域が拡大したのです。

どうすべきか

今すぐ手を動かすべきか

これだけ破壊的変更の話をしてきたので、最後に最も実務的な質問に答えましょう。答えは「最大規模の破壊的アップデート」という印象とは裏腹のものです。

最も覚えておくべき一言

7月28日は一斉切り替えの日ではありません。既存のクライアントとサーバーは今日壊れませんし、7月28日にも壊れません。その日はあくまで仕様の正式文書が発表された日であって、旧プロトコルをオフにする日ではありません。

具体的な互換パスは3つあります。

1つ目、新しいクライアントは古いサーバーに出会うと自動的にフォールバックします。2026-07-28を名乗るクライアントが、2025-11-25以前しか話せないサーバーに出会うと、元のinitializeハンドシェイクにフォールバックし、新旧が問題なく相互接続します。逆に、古いサーバーはプロトコルバージョンヘッダーの付いていないリクエストを受け取った場合、2025-03-26として扱うことができます。

2つ目、SDKのメジャーバージョンアップは別の話です。PythonとTypeScriptはどちらもv2をリリースしており、それぞれ独自の破壊的メジャーバージョンです。いつアップグレードするかは自分で決めればよく、7月28日とは関係ありません。TypeScript SDKのv1.xは、v2正式リリース後も少なくとも6か月はバグ修正とセキュリティ対応を継続します。Pythonのv1.xブランチも重大バグ修正とセキュリティパッチを継続して受け付けます。

3つ目、SDKをアップグレードすること自体は、必ずしも回線上で何を話すかを変えるわけではありません。しかも4つのSDKで挙動が異なる点は要注意です。

TypeScript / Go
SDKをアップグレードしても、サーバーが対外的に話すプロトコルバージョンは自動的には変わりません。2026-07-28を話させるには、配線時に明示的に選択する必要があります。
Python / C#
アップグレードすればそのまま追随します。Python v2サーバーは同一エンドポイントで新旧両バージョンに応答し、C#プレビュー版のHTTPトランスポートはデフォルトで新しいステートレスモードになります。

主要な4つのSDK(TypeScript、Python、Go、C#)は発表当日から新仕様に対応し、Rust SDKはbeta対応です。実際に手を動かして修正すべきなのは以下のカテゴリです。一つずつ確認してください。

✅ MCP 2026-07-28 移行セルフチェック
🧰 スタートガイド · MCP 2026-07-28仕様とSDK
価格無料、オープンソース
導入ハードル対応言語の新バージョンSDKを導入する。TypeScriptとGoはアップグレード後も配線時に2026-07-28を話すよう明示的に選択する必要がある。Python v2サーバーは同一エンドポイントで新旧両バージョンに応答し、C#プレビュー版のHTTPトランスポートはデフォルトでステートレスモードになる
出典
The 2026-07-28 SpecificationModel Context Protocol 公式ブログ·blog.modelcontextprotocol.io·2026-07-28
本サイトからの注記
デモ動画は公式発表ブログのオリジナル素材です。図解(新旧の落ち着き先の対照、リクエスト構造、MRTRの5ステップ、ゲートウェイ比較、キャッシュ概略、ライフサイクル3状態、拡張機能のレイヤー構造)はすべて本サイトによる作成です。プロトコルの詳細は仕様本文とchangelogを優先し、発表ブログの記述と食い違う場合は仕様を正としています。セキュリティの節の内容はAkamaiの分析によるもので、SecurityWeekが2026-06-26に報じたものを経由しています。本サイトはAkamaiの原文を入手できておらず、二次引用となります。本文中のエコシステム企業による性能数値は各社の発表によるもので、独立検証は経ていません。