MCP(Model Context Protocol)の仕様は、2026年7月28日に公開された2026-07-28版で、接続ごとのセッションを前提とする設計を捨てました。initializeによるハンドシェイクとMcp-Session-Idヘッダが廃止され、すべてのリクエストが版と機能の宣言を自分で運ぶ「1リクエスト完結」の形になっています。この記事では2026年10月時点の公式仕様とchangelogをもとに、新しいリクエストの組み立て方、MRTRによるユーザー確認の置き換え、リスト結果のキャッシュ、Roots・Sampling・Loggingなどの非推奨化を整理し、2025-11-25版で作ったサーバーとクライアントの移行手順をJSONとcurlの実例付きで示します。
まとめ:2026-07-28版MCP仕様はセッションを捨てて1リクエストで完結する設計へ
最大の変更は、サーバーが接続の状態を覚えなくてよくなった点です。プロトコル版・クライアント情報・クライアントの機能は毎回_metaに載り、サーバーの対応版はserver/discoverで問い合わせます。ロードバランサの背後で、どのインスタンスがどのリクエストに答えても動きます。
サーバーからクライアントへの問い合わせ(elicitation・sampling・roots)は、MRTRという「結果として入力を要求し、クライアントに再送させる」方式に置き換わりました。Roots・Sampling・Logging・動的クライアント登録(DCR)は非推奨になり、削除が可能になるのは2027年7月28日以降に出る版からです。
移行を急ぐべきなのは、水平分散したいリモートのMCPサーバーと、セッションIDに状態を持たせていたサーバーです。社内でstdio接続だけで使うローカルサーバーは、SDKを新旧両対応の版に上げておけば、急いで作り替える必要はありません。
MCP仕様2026-07-28版の位置づけと2025-11-25版からの変更点の全体像
個々の変更に入る前に、今回の版がどの規模の改訂なのかをそろえます。
7月28日の正式公開とTier 1 SDK 4言語の同日対応という経緯
MCPの公式ブログの公開告知によると、2026-07-28版は2025-11-25版から約8か月ぶりの改訂で、TypeScript・Python・Go・C#の4つのTier 1 SDKが公開日から対応しました。
2026年5月ごろの解説記事にはリリース候補(RC)の段階で書かれたものが混ざり、エラーコードの番号などは正式版で変わっています。参照するときは2026-07-28版の仕様本体を正とします。
changelogの主要な変更9件と小変更12件を影響範囲で仕分けた一覧表
2026-07-28版のchangelogは、主要な変更を9件、小さな変更を12件、非推奨化を4件挙げています。影響を受ける側で仕分けると次のとおりです。
| 変更 | 区分 | 影響を受ける側 |
|---|---|---|
| initializeとセッションIDの廃止 | 主要 | 双方 |
| server/discoverの新設 | 主要 | サーバー |
| MRTRへの置き換え | 主要 | elicitation利用者 |
| resultTypeの必須化 | 主要 | クライアント |
| GETと再開機能の廃止 | 主要 | HTTPの実装 |
| pingとログ設定の削除 | 主要 | 監視の実装 |
| Tasksの拡張機能化 | 主要 | 長時間処理 |
| 必須ヘッダの追加 | 小 | ゲートウェイ |
| ttlMs・cacheScope | 小 | サーバー |
| エラーコードの変更 | 小 | エラー処理 |
必須ヘッダは「小」の区分ですが、HTTPで公開しているサーバーでは欠落がそのまま400 Bad Requestになります。区分の大小と移行の手間は一致しません。
initializeハンドシェイク廃止後の_metaの書き方と版の確認手順
新しい版でリクエストをどう組み立てるかを実例で見ます。
_metaに載せる版・クライアント情報・機能宣言の3項目と書き方
2025-11-25版までは、接続の最初にinitializeを1回送り、決めた版と機能をセッションの間使い続けました。2026-07-28版では、この情報をリクエストごとにparams._metaへ書きます。版と機能は必須、クライアント情報は推奨(SHOULD)です。
{
"jsonrpc": "2.0",
"id": 1,
"method": "tools/call",
"params": {
"name": "get_weather",
"arguments": { "location": "Tokyo" },
"_meta": {
"io.modelcontextprotocol/protocolVersion": "2026-07-28",
"io.modelcontextprotocol/clientInfo": { "name": "ExampleClient", "version": "1.0.0" },
"io.modelcontextprotocol/clientCapabilities": {}
}
}
}
ログの出力レベルもlogging/setLevelではなく、リクエストごとに_metaのlogLevelで指定する形に変わりました。この項目が無いリクエストに、サーバーはログ通知を送ってはいけません。
server/discoverで対応版と機能を1回で取得するcurlコマンド例
server/discoverの仕様によると、サーバーは実装が必須で、クライアントが呼ぶかは任意です。新しい版への対応は次のcurlで確かめられます(URLは自分のエンドポイントに置き換えます)。
# Streamable HTTP では MCP-Protocol-Version と Mcp-Method の2つのヘッダが必須
curl -s https://example.com/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-H "MCP-Protocol-Version: 2026-07-28" \
-H "Mcp-Method: server/discover" \
-d '{"jsonrpc":"2.0","id":"discover-1","method":"server/discover",
"params":{"_meta":{
"io.modelcontextprotocol/protocolVersion":"2026-07-28",
"io.modelcontextprotocol/clientInfo":{"name":"curl-check","version":"0.1.0"},
"io.modelcontextprotocol/clientCapabilities":{}}}}'
対応済みのサーバーはsupportedVersions・capabilities・instructionsを返します。結果の_metaに入るserverInfoは自己申告のため、仕様は認可や挙動の切り替えに使わないよう求めています。
版が合わないときの-32022エラーで対応版をそろえ直す手順
版の交渉は、失敗からの再送で行います。版と互換性の仕様では、未対応の版を要求されたサーバーは、対応版の一覧を付けたエラーを返します。
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32022,
"message": "Unsupported protocol version",
"data": { "supported": ["2026-07-28", "2025-11-25"], "requested": "1900-01-01" }
}
}
クライアントはsupportedから話せる版を選んで送り直します。HTTPではこのエラーが400で返るため、ステータスだけで「旧版のサーバー」と決めつけず、本文のJSONを読んでから分岐させます。
MRTRによるユーザー確認の置き換えとrequestStateの安全設計
ステートレス化と並ぶ柱が、MRTR(Multi Round-Trip Requests)です。
InputRequiredResultを返して元のリクエストを再送させる流れ
以前は、ツールの実行中にサーバーがクライアントへelicitation/createなどを送り、開いたままの通信路で応答を待ちました。MRTRの仕様では、サーバーは処理をいったん終え、「入力が必要」という結果を返します。
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"resultType": "input_required",
"inputRequests": {
"approver": {
"method": "elicitation/create",
"params": {
"mode": "form",
"message": "請求書を発行する担当者名を入力してください",
"requestedSchema": {
"type": "object",
"properties": { "name": { "type": "string" } },
"required": ["name"]
}
}
}
},
"requestState": "eyJzdWIiOi...(サーバーが署名した不透明な文字列)"
}
}
クライアントは利用者から入力を集め、inputResponsesに回答を入れ、requestStateをそのまま付けて、元のtools/callを新しいJSON-RPCのidで送り直します。この形で使えるのはtools/call・resources/read・prompts/getの3つだけで、クライアントが宣言していない種類の入力は要求できません。
requestStateを改ざん前提で扱うHMAC署名・有効期限・利用者の照合
MRTRの仕様は、クライアントを経由して戻るrequestStateを「攻撃者が操作できる入力」として扱うよう定めています。認可や業務ロジックに影響するならHMACかAEADで完全性を守り、認証済みの利用者・短い有効期限・元のリクエストの識別子を中に含めることが推奨されています。標準ライブラリだけで記述した実装例は次のとおりです。
import base64, hashlib, hmac, json, time
SECRET = b"replace-with-random-32-bytes-key" # 本番は環境変数やKMSから読み込む
def digest(method: str, arguments: dict) -> str:
# 元リクエストの識別子=メソッド名+引数のハッシュ
raw = json.dumps({"m": method, "a": arguments}, sort_keys=True, ensure_ascii=False)
return hashlib.sha256(raw.encode()).hexdigest()
def seal_state(principal: str, req_digest: str, data: dict, ttl_sec: int = 300) -> str:
payload = {"sub": principal, "req": req_digest, "exp": int(time.time()) + ttl_sec, "data": data}
body = base64.urlsafe_b64encode(json.dumps(payload, separators=(",", ":")).encode())
sig = base64.urlsafe_b64encode(hmac.new(SECRET, body, hashlib.sha256).digest())
return (body + b"." + sig).decode()
def open_state(token: str, principal: str, req_digest: str) -> dict:
body, _, sig = token.encode().partition(b".")
expected = base64.urlsafe_b64encode(hmac.new(SECRET, body, hashlib.sha256).digest())
if not hmac.compare_digest(sig, expected):
raise ValueError("requestState の署名が一致しません")
payload = json.loads(base64.urlsafe_b64decode(body))
if payload["exp"] < time.time():
raise ValueError("requestState の有効期限が切れています")
if payload["sub"] != principal or payload["req"] != req_digest:
raise ValueError("別の利用者・別のリクエストの requestState です")
return payload["data"]
HMACは改ざんを検出しますが、中身は隠しません。顧客情報や内部IDを入れるならAEAD(AES-GCMなど)で暗号化します。仕様の警告どおり、この方法でも1回限りの使用までは保証されないため、決済のように二重実行が許されない処理はサーバー側に使用済みの記録を持ちます。
リスト結果のキャッシュとエラーコード再割り当てで変わるクライアント実装
クライアントとゲートウェイの実装に直接効く変更が2つあります。
ttlMsとcacheScopeによるリスト結果のキャッシュと並び順
tools/listやresources/readなど5種類の結果に、ttlMsとcacheScopeが必須になりました。ttlMsはミリ秒単位の鮮度の目安で、cacheScopeが"public"なら共有の中継サーバーもキャッシュでき、"private"ならそのクライアントだけが持てます。
利用者ごとに見せるツールを変えるサーバーは"private"を返します。ここを"public"にすると、社内ゲートウェイが別の社員向けの一覧を返す事故につながるため注意が必要です。tools/listを決まった順序で返すことも推奨され、LLMのプロンプトキャッシュに当たりやすくなります。
HeaderMismatchなど3つのエラーコードの番号変更と-32602への統一
changelogは-32020〜-32099を仕様の予約枠とし、RC段階の番号を次のように振り直しました。
| エラー | RC段階 | 正式版 |
|---|---|---|
| HeaderMismatch | -32001 | -32020 |
| 必須機能の不足 | -32003 | -32021 |
| 未対応の版 | -32004 | -32022 |
| リソース不在 | -32002 | -32602 |
最終行は2025-11-25版の番号からの変更です。RC時点の記事を見て番号を直書きしたコードは分岐を外すため、SDKの定数に寄せます。
Roots・Sampling・Logging・DCRの非推奨化と削除時期
今回の版は、機能の寿命を管理する規則も導入しました。
登録簿に載る非推奨機能6件の移行先と削除が可能になる最短時期
機能のライフサイクル規則は、非推奨から削除までに最低12か月を置くと定めています。非推奨機能の登録簿に載る6件は次のとおりです。
| 機能 | 非推奨の版 | 移行先 | 削除が可能になる時期 |
|---|---|---|---|
| Roots | 2026-07-28 | ツール引数・リソースURI | 2027-07-28以降の版 |
| Sampling | 2026-07-28 | LLMのAPIを直接呼ぶ | 2027-07-28以降の版 |
| Logging | 2026-07-28 | stderr・OpenTelemetry | 2027-07-28以降の版 |
| DCR | 2026-07-28 | CIMD | 2027-07-28以降の版 |
| includeContextの2値 | 2025-11-25 | 省略または”none” | Samplingに従う |
| HTTP+SSE | 2025-03-26 | Streamable HTTP | SEP-2596確定の3か月後 |
表の時期は削除が可能になる時期で、実際に消すかどうかを判断するのは、版の準備時のコアメンテナです。新規実装でSamplingを採用する理由はもうなく、サーバーの中でLLMを呼びたいなら、サーバー自身がAPIキーを持つ構成に変えます。DCRからの移行はCIMD(Client ID Metadata Documents)の仕組みと実装で扱っています。
TasksとMCP Appsが拡張機能へ移った意味とextensionsでの宣言
クライアントとサーバーは、機能宣言のextensionsにio.modelcontextprotocol/tasksなどを書いて拡張機能への対応を伝え、相手が非対応なら中核の動作に戻すか拒否します。
実験機能だったTasksは拡張機能になり、待ち受け型のtasks/resultがtasks/getのポーリングへ変わりました(MCP Tasks拡張の解説)。対話型UIのMCP Appsも同じ枠組みです(MCP Appsの仕組みと採用判断)。
2025-11-25版のMCPサーバーとクライアントを新仕様へ移行する手順
移行で最初に決めるのは、新旧どちらの相手と話す必要があるかです。
新旧の組み合わせ7通りで決まる互換性マトリクスとフォールバック
版と互換性の仕様は、新しい版だけを話す実装を「Modern」、2025-11-25版以前を「Legacy」、両方を話す実装を「Dual-era」と呼び、組み合わせごとの結果を示しています。
| クライアント | サーバー | 結果 |
|---|---|---|
| Modern | Modern | 動く |
| Modern | Legacy | 動かない |
| Dual-era | Modern | 動く(新しい版で継続) |
| Dual-era | Legacy | 動く(initializeへ戻る) |
| Legacy | Modern | 動かない |
| Legacy | Dual-era | 動く |
| Legacy | Legacy | 旧版どおり動く |
結論は1つで、サーバーは当面Dual-eraにすることです。旧クライアントには新版へ進む手段がなく、Modernだけのサーバーにすると2025年版のクライアントがすべて接続できなくなります。
TypeScript・Python・Go・C#の現行版と新仕様の有効化
2026年10月11日にPyPI・npm・GitHub Releasesで確認した各SDKの版は次のとおりです。
| SDK | パッケージ | 新仕様の初版 | 10月11日時点 |
|---|---|---|---|
| TypeScript | server・client | 2.x系 | 2.3.1 |
| Python | mcp | 2.0.0 | 2.3.0 |
| Go | go-sdk | v1.7.0 | v1.8.0 |
| C# | ModelContextProtocol | 2.0.0 | 2.2.0 |
TypeScriptはv2で@modelcontextprotocol/serverとclientに分かれ、従来のsdkパッケージは1系(1.32.1)のまま残ります。2026-07-28対応ガイドのとおり、新しい版での応答は明示的な設定で有効にします(MCP TypeScript SDK v2の移行要点)。
Pythonはv2.0.0でFastMCPがMCPServerに改名され、v2の移行ガイドによると新旧両方の版に応じます。Goはv1.8.0、C#はv2.0.0のリリースノートが、ステートレスモードの設定を確認する参照先です。独立系のFastMCPはFastMCP 4のsessionless対応とFastMCPの使い方で比べられます。
セッションIDに状態を持たせていたサーバーを引数ハンドルへ移す4段階
移行の手間が最も大きいのは、Mcp-Session-Idをキーにログイン状態や作業中のデータをメモリに持っていたサーバーです。changelogが示す置き換え先は、サーバーが発行するハンドルをツールの引数で受け渡す方法です。
- セッションに紐づけていた状態を洗い出し、「認証の結果」と「作業の途中経過」に分ける
- 認証の結果は、毎回のリクエストに付くOAuthのアクセストークンから求め直す形にする
- 途中経過はRedisやDBに保存し、
create_cartのようなツールが返すIDを、後続のツールが引数で受け取る形にする - ユーザー確認の途中状態は、前章の
requestStateへ移し、サーバーのメモリから消す
3で返すIDは推測できない値にし、受け取ったときに呼び出し元の利用者と照合します。IDだけで他人の作業に触れられる設計は、セッションの乗っ取りと同じ危険性を持つ設計です。HTTPのヘッダやGETの変更は、Streamable HTTPの2026-07-28仕様の変更点にまとめています。
2026-07-28版への移行を急ぐべきMCPサーバーと2025年版に留まる判断
ここまでの仕様を踏まえて、移行の優先度を言い切ります。
ロードバランサ配下で水平分散したいリモートサーバーは即移行する
社外や全社に向けてHTTPで公開するMCPサーバーは、すぐに移行します。セッションがなくなれば、スティッキーセッションも共有のセッションストアも要らず、サーバーレスやコンテナの自動スケールにそのまま載ります。Mcp-MethodとMcp-Nameのヘッダで、WAFやゲートウェイが本文を開かずにツール単位のレート制限をかけられる点も利点です。
stdio接続のローカルサーバーや社内限定ツールは急がない条件
開発者のPCでstdio接続だけで動くローカルサーバーは、急ぐ理由がありません。接続が1対1で、水平分散の利点が効かないためです。SDKをDual-era対応の版へ上げ、新旧のクライアントから動くことを確かめれば十分です。
ただし、SamplingやRootsに頼った設計はこの段階で外します。既存の業務システムをMCPでAIエージェントにつなぐ設計や、移行範囲の見積もりに迷う場合は、AIエージェント開発で要件の整理から対応しています。MCPの基本から確認したい場合はMCP(Model Context Protocol)とはが入口です。
MCP仕様2026-07-28版の変更点と移行でよくある質問
出やすい質問に、2026年10月時点の公式仕様で答えます。
2025-11-25版で作ったMCPサーバーはもう使えませんか?
2025年版のクライアントからは今までどおり使えます。新しい版だけを話すクライアントとは接続できないため、利用者のクライアントが新版へ移るのに合わせて、サーバーを新旧両対応にします。TypeScriptとPythonのSDKは、同じエンドポイントで両方の版への対応が可能です。
セッションがなくなると会話の文脈はどこで保持しますか?
会話の文脈は、もともとクライアント(AIアプリ)側が持つものです。呼び出しをまたぐ状態が必要なら、サーバーが発行したIDをツールの戻り値で返し、モデルが次のツールの引数で渡します。ユーザー確認の途中状態は、MRTRのrequestStateに入れてクライアントに預けます。
server/discoverは毎回呼ぶ必要がありますか?
必要ありません。任意のメソッドをいきなり呼び、版が合わなければ-32022のエラーから再送しても動きます。stdioで新旧のサーバーが混在する環境ではHTTPのステータスが使えないため、最初にserver/discoverを送って旧版を見分ける使い方が推奨されています。
SamplingとRootsはいつ使えなくなりますか?
非推奨機能の登録簿は、削除が可能になる時期を「2027年7月28日以降に出る最初の版」としており、実際の日付は確定していません。期間中も機能は動きますが、新しく組み込むのは避け、Rootsはツール引数やリソースURIへ、SamplingはLLMのAPIを直接呼ぶ形へ移します。
MCPの仕様はどのくらいの頻度で改訂されますか?
版名は公開日で、2024-11-05、2025-03-26、2025-06-18、2025-11-25、2026-07-28と続いてきました。今回から非推奨機能に最低12か月の猶予を置く規則が入ったため、版が出てすぐに機能が消えることはありません。
関連記事
- MCP(Model Context Protocol)とは?AIと外部ツールをつなぐ標準規格の仕組みをわかりやすく解説:ホスト・クライアント・サーバーの役割など、MCPの基本の仕組み
- Streamable HTTPとは?MCPのトランスポートとSSEの違い、2026-07-28仕様の変更点:必須ヘッダ・GET廃止など、HTTP側の変更の詳細
- CIMD(Client ID Metadata Documents)とは?MCPでDCRに代わるOAuthクライアント登録の仕組みと実装【2026年9月時点】:非推奨になったDCRの移行先
- MCP TypeScript SDK v2とは?パッケージ分割とステートレス化の移行要点:TypeScriptで新仕様に対応する手順
- FastMCPとは|PythonでMCPサーバーを最速構築するフレームワークの使い方【2026年版】:PythonでMCPサーバーを作る基本