対象読者: MCPサーバ/クライアントを実装・運用しているエンジニア、AIエージェント基盤を設計している人
前提知識: HTTP、ロードバランサ、OAuth 2.0 の基本的な理解
2026-07-28 が正式公開される。ローンチ以来「最大の改訂」と公式が明言している。initialize ハンドシェイクと Mcp-Session-Id ヘッダが廃止され、リクエストが自己完結する。本題に入る前に、この記事で頻出する用語を先に定義しておきます。既知の方は読み飛ばしてください。
AIモデル(LLM)と外部のツール・データソースを接続するための通信プロトコル。Anthropicが2024年に公開し、現在はLinux Foundation傘下のプロジェクトとして運営されています。「AIツールとサービスを接続するための事実上の業界標準」という位置づけになっています。
平たく言えば、「LLMから叩ける外部API」を記述・実行するための共通規格です。ファイル検索、GitHubリポジトリ参照、社内DBクエリなどを、モデル側から統一的な作法で呼び出せるようにします。
MCPの土台になっているRPC(遠隔手続き呼び出し)の規格。{"jsonrpc":"2.0", "id":1, "method":"...", "params":{...}} という形のJSONをやりとりするだけの、非常に薄いプロトコルです。MCPはこの上に「ツール一覧を返す tools/list」「ツールを実行する tools/call」といったメソッド体系を載せています。
MCPのリモート接続用トランスポート(通信方式)。HTTP POSTでリクエストを送り、必要に応じてSSE(Server-Sent Events: サーバからクライアントへ一方向にイベントを流し続けるHTTPの仕組み)でストリーミング応答を返す、というハイブリッドな方式です。
この違いは、後述するスケーラビリティに直結します。
ロードバランサが「同じクライアントからのリクエストは、必ず同じバックエンドサーバに転送する」ように設定すること。ステートフルなサーバでは、状態を持っているインスタンスに戻さないと会話が続かないため必須でした。
裏を返すと、スティッキーセッションはスケールアウトの敵です。負荷が偏る、インスタンス障害時にセッションが飛ぶ、デプロイのたびに接続が切れる、といった運用上の負債を生みます。
MCPの仕様改善提案。PythonのPEP、RustのRFCに相当する仕組みで、GitHub上のPull Requestとして議論・採択されます。本記事では SEP-2575 のような形で番号を参照します。
MCPが導入したSDKの階層制度で、全プロトコル実装を含む完全サポートのSDKを指します。TypeScript、Python、Goなどの公式SDKがこれにあたります。後述する適合性テストスイート(conformance suite)でスコアリングされます。
| 日付 | できごと |
|---|---|
| 2025-11-25 | 現行の最新仕様「MCP 2025-11-25」公開 |
| 2026-05-21 | 次期仕様のリリース候補(RC)が確定・凍結 |
| 2026-05-21 〜 07-28 | 10週間の検証期間。Tier 1 SDKはこの間に対応版を出すことが期待される |
| 2026-07-28 | 仕様「MCP 2026-07-28」正式公開 |
RCが凍結されてから正式公開まで10週間の猶予が置かれているのがポイントです。これは「SDKメンテナとクライアント実装者が、実ワークロードに対して変更を検証するための期間」と明示されています。つまり7月28日時点で主要SDKは既に対応済みという前提で設計されたスケジュールです。
なお、この仕様には破壊的変更(breaking changes)が含まれます。公式も「これを常態にするつもりはない」と断ったうえで、今回は基盤的な変更ゆえのクリーンブレイクだと説明しています。
Streamable HTTPでツールを1回呼ぶだけでも、以下の手順が必要でした。
initialize メソッドを送り、プロトコルバージョン・クライアント情報・ケイパビリティ(対応機能)を申告するMcp-Session-Id ヘッダでセッション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のためだけに用意する必要があったわけです。
同じツール呼び出しが、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":{...}}}}
変わった点を分解します。
initialize / initialized ハンドシェイクの廃止(SEP-2575)接続時に1回だけ交換していたプロトコルバージョン・クライアント情報・クライアントケイパビリティは、毎リクエストの _meta フィールドに載せて運ぶ方式に変わりました。
「毎回送るのは冗長では?」と思うかもしれませんが、これは典型的なステートレス設計のトレードオフです。わずかなペイロード増加と引き換えに、サーバ側の状態管理が丸ごと消えます。HTTPがCookieやトークンを毎回送るのと同じ発想ですね。
サーバ側のケイパビリティを事前に知りたい場合のために、server/discover という新メソッドが用意されています。必要なときに取りに行く(pull型)に変わった、と理解するとよいでしょう。
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
ここは誤解しやすいので強調しておきます。プロトコルがステートレスになった=アプリケーションが状態を持てなくなった、ではありません。
状態を持ちたいサーバは、HTTP APIが昔からやってきたことをやればよい、というのが公式の回答です。すなわち 明示的ハンドル(explicit handle)パターン:
basket_id や browser_id のような識別子を発行して返すmodel ──> create_basket() ──> { basket_id: "..." }
model ──> add_item(basket_id, …) ──> { ok: true }
公式は、これを単なる代替手段ではなくむしろ優れた方式だと述べています。理由は、状態がトランスポートのメタデータに隠蔽されるのではなく、モデルから見える形で表に出るためです。モデルはハンドルを複数ツール間で組み合わせたり、それについて推論したり、ステップ間で受け渡したりできます。
エージェント設計をやっている人には響く話だと思います。「見えない状態」はモデルにとってデバッグ不能なブラックボックスですが、引数として明示されていれば推論の対象になります。
ステートレスにしても、サーバが処理の途中でクライアントに問い合わせたい場面はあります。典型は 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を維持できない環境でも実装できるようになったためです。
運用面での地味に効く3点です。
Mcp-Method / Mcp-Name ヘッダの必須化(SEP-2243)
Streamable HTTPで、呼び出すメソッド名とツール名をHTTPヘッダに出すことが必須になりました。
これにより、ロードバランサ・APIゲートウェイ・レートリミッタが、ボディを解析せずに操作単位でルーティングや制限をかけられます。前述のDPIが不要になる、という話です。
なお、ヘッダとボディの内容が食い違うリクエストはサーバが拒否することになっています(ヘッダだけ書き換えて制限を回避する攻撃への対策)。
ttlMs / cacheScope の導入(SEP-2549)
リスト系(tools/list 等)とリソース読み取りの結果に、キャッシュ制御用のフィールドが追加されました。HTTPの Cache-Control をモデルにしています。
ttlMs: このレスポンスが何ミリ秒間フレッシュかcacheScope: ユーザ間で共有してよいキャッシュか否か従来は「ツール一覧が変わったこと」を知るために長寿命のSSEストリームを維持するしかありませんでしたが、その必要がなくなりました。
W3C Trace Contextの伝播を明文化(SEP-414)
分散トレーシングの標準規格である W3C Trace Context(traceparent / tracestate / baggage というHTTPヘッダで、複数サービスをまたぐ1つの処理を追跡するための仕様)のキー名が、_meta 内で正式に固定されました。
すでに一部のSDKやツールが独自に実装していたものを、仕様として名前を確定させた形です。これによって、ホストアプリケーション → クライアントSDK → MCPサーバ → その先の下流サービス、という一連の流れが、OpenTelemetry互換のバックエンドで1つのスパンツリーとして可視化できます。
OpenTelemetry(OTel): トレース・メトリクス・ログを収集するためのベンダー中立な観測(オブザーバビリティ)標準。CNCFプロジェクト。
エージェントのデバッグは「どのツール呼び出しが遅いのか/失敗しているのか」の特定が難しいので、これは実運用でかなり効いてくるはずです。
拡張の仕組み自体は 2025-11-25 にも存在しましたが、正式なプロセスがありませんでした。SEP-2133がこれを整備しています。
io.modelcontextprotocol/...)extensions マップでネゴシエーションするext-* という独立リポジトリで、委任されたメンテナが管理する今回のリリースには2つの公式拡張が含まれます。
サーバがインタラクティブなHTMLインターフェースを提供し、ホスト(Claude DesktopやVS Codeのようなクライアントアプリ)がサンドボックス化されたiframe内でレンダリングする仕組みです。
設計上のポイントが2つあります。
「AIが表示したボタンを押したら、承認フローを迂回して何かが実行された」という事故を構造的に防ぐ設計です。
GitHubのChangelogによれば、MCP AppsはVS Codeで既にサポート済みとのことです。
Tasks(長時間かかる処理を非同期に扱う仕組み)は 2025-11-25 で実験的なコア機能として出荷されましたが、本番利用で再設計が必要なことが判明し、仕様本体ではなく拡張が適切な置き場所と判断されました。
新しいTasks拡張は、ステートレスモデルに合わせてライフサイクルが作り直されています。
tools/call に対してタスクハンドルを返せるtasks/get / tasks/update / tasks/cancel で駆動するtasks/list は削除。セッションがない以上、安全にスコープを切れないため⚠️ 移行が必要: 2025-11-25 の実験的Tasks APIに対して実装した人は、新しいライフサイクルへの移行が必要です。
6本のSEPで、OAuth 2.0 / OpenID Connect の実運用での使われ方に近づける修正が入りました。主なものを挙げます。
iss パラメータの検証を必須化(SEP-2468 / RFC 9207)認可レスポンスに含まれる iss(issuer: 発行元の認可サーバ識別子)を、クライアントが検証しなければならなくなりました。
これは mix-up攻撃(複数の認可サーバを使う構成で、攻撃者が認可レスポンスをすり替え、正規サーバ向けの認可コードを別のサーバに渡させる攻撃)への対策です。
MCPは「1つのクライアントが多数のサーバに接続する」というデプロイパターンが支配的なため、この攻撃クラスのリスクが相対的に高い、と公式は説明しています。低コストな緩和策として導入されました。
将来のバージョンでは、iss を含まないレスポンスをクライアントが拒否することが期待されます。認可サーバ側は今のうちから iss を返すようにしておくべきです。
application_type 宣言(SEP-837)DCR(Dynamic Client Registration): クライアントが認可サーバに対して、事前の手動登録なしに自分自身を動的に登録する仕組み。
クライアントが OpenID Connect の application_type を登録時に宣言できるようになりました。
これが解決するのは、非常によくある実装上の詰まりです。従来は、デスクトップアプリやCLIクライアントを認可サーバが "web" としてデフォルト扱いしてしまい、localhost へのリダイレクトURIが拒否される、という事象が頻発していました。
issuer にバインドし、リソースが別の認可サーバへ移行したら再登録する(SEP-2352).well-known ディスカバリのサフィックスの明確化(SEP-2351)新設された機能ライフサイクルポリシー(SEP-2577)に基づき、3つのコア機能が非推奨になりました。
| 機能 | 何だったか | 代替 |
|---|---|---|
| Roots | クライアントがサーバに「作業対象のディレクトリ範囲」を伝える仕組み | ツールのパラメータ、リソースURI、サーバ側の設定 |
| Sampling | サーバがクライアント経由でLLM推論を要求する仕組み | LLMプロバイダAPIとの直接統合 |
| Logging | サーバがクライアントに構造化ログを送る仕組み | stdioトランスポートでは stderr、構造化された観測にはOpenTelemetry |
重要なのは、これが アノテーションのみの非推奨(annotation-only deprecation) である点です。
つまり「今すぐ壊れる」話ではありません。ただし、新規実装でこれらに依存するのは避けるべきです。
Samplingの非推奨は個人的に象徴的だと感じます。「MCPサーバがクライアントのLLMを間借りする」という発想自体が、各サーバが自前でLLM APIを叩ける現在の状況では不要になった、ということでしょう。
ツールの inputSchema / outputSchema が、JSON Schema 2020-12 の全機能を使えるようになりました。
JSON Schema 2020-12: JSONデータの構造を宣言的に記述・検証するための仕様。2020年12月版がドラフトの最新安定版として広く使われています。
type: "object" である制約は維持。ただし、合成(oneOf / anyOf / allOf)、条件分岐、参照($ref / $defs)が使えるようになったstructuredContent はオブジェクトに限らず任意のJSON値を取れる実装者向けの注意として、以下が明記されています。
$ref URIを自動解決してはならない(SSRFなどのリスク)リソースが見つからない場合のエラーコードが、MCP独自の -32002 から、JSON-RPC標準の -32602(Invalid Params)に変更されます(SEP-2164)。
クライアント側で -32002 をリテラルにマッチしている実装は、必ず修正が必要です。 移行時のチェック対象として真っ先に挙がるポイントです。
今回は破壊的変更を含みますが、公式は「これを常態にはしない」と明言しています。そのためのガバナンス系SEPが3本入りました。
つまり、「仕様書に書いてあるが誰も実装を検証していない機能」が生まれにくい構造になりました。
公式の見通しとしては、2026-07-28 をターゲットに実装しておけば、今後の改訂ではトランスポート層やライフサイクル層のコードを書き直さずに追従できるはず、とされています。
GitHubは7月23日付のChangelogで、正式リリースに先行して最新仕様に対応済みであることを発表しました。
前提として、Tier 1 SDKはすべて後方互換性を維持しており、ベータ対応も出荷済みなので、「サポートを維持するために利用者側で何かする必要はない」とされています。GitHub MCPサーバ自身は公式のGo SDKを使っています。
そのうえでGitHubが行った変更は3つです。これが実装者にとって一番参考になる部分なので、詳しく見ます。
initialize 時のDB書き込みが消滅セッションIDを永続化・参照するためのRedisアクセスが、リクエストパスから丸ごと消えたわけです。「ユーザが何かを失うことなく、動作がキビキビする」と表現されています。
これはステートレス化の効果を最も端的に示す事例です。ツール呼び出し1回あたりのレイテンシから、ネットワークを1往復するストレージアクセスが消えるのですから、体感差は小さくないはずです。
GitHubは、ロギングとシークレットスキャン(トークンなどの機密情報の混入検知)のために、MCPリクエストからいくつかの値を読み取る必要があります。
従来はそのために、SDKが処理する前に、すべてのリクエストのペイロードを解析していました。新仕様では、必要な値が必ず存在するHTTPヘッダ(前述の Mcp-Method / Mcp-Name)から取得できるため、この事前解析が不要になりました。
エッジ・ゲートウェイ層を自作している人には、そのまま効く話です。
GitHubのstdio版MCPサーバは、ユーザログインを簡単にするために URL elicitation(ブラウザで開くURLをユーザに提示する形の確認)を使っています。
新プロトコルでは、前述のMulti Round-Trip Requestsにより各ステップが独立したHTTPリクエストになります。旧クライアントと新クライアントの両方で動かすため、Go SDKが両方式を吸収するラッパーを提供しているとのことです。
移行期のクライアント/サーバのバージョン混在を、SDK層で吸収する ― という実装パターンの好例です。
GitHubは、MCPに公式の適合性テストが追加されたことにも触れています。厳密な検証があると、エージェント自身が自分の実装を検証できるためです。
具体的な使い方として、Copilot(あるいは任意のコーディングエージェント)に対して以下へのアクセスを与えることを推奨しています。
github.com/modelcontextprotocol/conformanceAI支援でMCPサーバを実装するなら、「仕様書+SDK実装+テストスイート」の3点セットをコンテキストに入れる、というのは素直に有用なプラクティスだと思います。検証可能なテストがある領域では、エージェントのループが正しく閉じるためです。
自分のMCP実装を点検するときの観点を、影響度順にまとめます。
Mcp-Session-Id に依存したロジックがないか棚卸しするinitialize 時にしか実行していなかった初期化処理(DB書き込み、権限解決など)の置き場所を再設計するInputRequiredResult + requestState 方式への対応を確認するtools/list などに ttlMs / cacheScope を設定して、クライアント側のキャッシュを効かせる2025-11-25 の実験的Tasks APIを使っていた場合、新Tasks拡張のライフサイクルへ移行する-32002 をリテラルでマッチしている箇所を -32602 に対応させる(見落としやすい)iss 検証(RFC 9207)を実装するapplication_type を宣言する(特にデスクトップ/CLIクライアント)_meta に載せるプロトコルバージョン・クライアント情報の実装を確認するserver/discover を使うMcp-Method / Mcp-Name ヘッダベースに切り替えるiss を返すよう設定する今回の改訂を一言でまとめるなら、MCPが特殊なプロトコルであることをやめ、ごく普通のHTTP APIとして扱えるようになったということだと思います。
ステートフルなセッション、SSEの張りっぱなし、ボディを解析しないとルーティングできない構造 ― これらはすべて、既存のHTTPインフラ(LB、CDN、APIゲートウェイ、WAF、キャッシュ、トレーシング)の恩恵を受けられなくする要因でした。仕様がそれらを捨てたことで、この20年分のWebインフラの蓄積がそのまま使えるようになります。
同時に、「状態はプロトコルではなくアプリケーションが、モデルから見える形で持つ」という方針転換は、エージェント設計の思想としても筋が通っています。隠れた状態はモデルにとって推論不能ですが、引数として表に出ていれば、モデルが組み合わせ・受け渡し・検証の対象にできる。LLMを主役に据えたときに正しい設計はどちらかを考え抜いた結果に見えます。
破壊的変更は痛みを伴いますが、機能ライフサイクルポリシー・Extensionsフレームワーク・適合性テストという3点セットのガバナンスが同時に入ったことで、これが最後の大きな断絶になるという公式の主張には説得力があります。