MCP仕様の改訂ライフサイクル — 仕様書と機能で分かれる状態遷移
MCPの仕様書はDraft/Current/Final、個々の機能はActive/Deprecated/Removedと別々に動く。12ヶ月ルール、Tier 1 SDKの義務、旧版サーバーとの接続結果まで。
仕様書のライフサイクルと機能のライフサイクルは別物
MCPには2つの独立した状態遷移があります。仕様書という「文書そのもの」の段階と、その中に書かれた個々の「機能」の段階です。混同すると「非推奨の機能があるのに、なぜ仕様のバージョンは現行のままなのか」という疑問が出ます。答えは単純で、両者は別の軸だからです。
2つのライフサイクルの対応
仕様書(リビジョン)
1つのリビジョン全体が1つの状態を持ちます。見ているのは「どのリビジョンが今の標準か」です。
個々の機能
機能が1つずつ状態を持ちます。見ているのは「まだ使えるか、廃止予定か、消えたか」です。
機能の状態はCurrentなリビジョンの中に表れます。Activeな機能とDeprecatedな機能が、同じリビジョンに同居するわけです。2026-07-28は仕様書としてはCurrentですが、その中のRootsとSamplingはDeprecatedです。
もう1点、リビジョンの番号には決まりがあります。YYYY-MM-DD形式の文字列で、後方互換のない変更が入った最後の日付を表します。互換性を保つ変更ではバージョンが進まないので、Currentのまま中身が増えていくことがあります。
仕様書自体の3つの状態(Draft・Current・Final)
リビジョンは常にこの3つのどれかです。
- Draft: 作業中の仕様で、利用の準備ができていません。
modelcontextprotocol.io/specification/draftで先行公開されています - Current: 利用の準備ができた現行のリビジョンです。後方互換の範囲で今後も変更を受け付けます。2026-07-28がこれに当たります
- Final: 過去の完成した仕様で、今後変更されません。2025-11-25以前のリビジョンがこの状態です
Currentとして示されるのは、2026-07-28の1つです。
機能単位の3状態(Active・Deprecated・Removed)と12ヶ月ルール
機能のほうは、仕様書とは独立に1つずつ状態を持ちます。対象は仕様書のうちコア仕様の機能で、プロトコルメッセージ、ケイパビリティ、トランスポート、スキーマの型、規範的な振る舞いの要件を含みます。
| 状態 | 意味 | 実装者への期待 |
|---|---|---|
| Active | 意味Current仕様の一部として現役 | 実装者への期待規範的な要件どおりに実装する |
| Deprecated | 意味仕様には残るが廃止予定。移行先が書かれる | 実装者への期待新規実装は採用しない。既存実装は最短除去日までに移行する |
| Removed | 意味draftから削除済みで、次のCurrentには存在しない | 実装者への期待次のCurrentを対象にする実装は依存できない |
Removedになった機能も、最後に載っていたFinalのリビジョンには記録として残ります。
非推奨から削除までの流れ
- 1
SEPで非推奨を提案する
機能の名前と定義の場所を示し、理由と移行先(または「移行不要」)、12ヶ月以上の猶予期間を書きます。SEP(Specification Enhancement Proposal)を通す必要があります。
- 2
SEPがFinalになり、非推奨が予約される
schema.tsに@deprecatedのJSDocタグが付き、仕様文に非推奨の通知、changelogに「Deprecated」の項目、レジストリに行が加わります。 - 3
そのリビジョンがCurrentとしてリリースされる
ここで機能は正式にDeprecatedになり、猶予期間のカウントが始まります。起点はSEPがFinalになった日ではなく、このリリースです。
- 4
猶予期間が過ぎ、削除の対象になる
期間が過ぎたあとに最初にCurrentとしてリリースされるリビジョンが「最短除去日」になります。実際の削除は、リリース準備の段階でCore Maintainersが判断します。
最短除去日の見方で迷いやすいのは、日付ではなくリビジョンで決まる点です。Rootsの最短除去日が「2027-07-28以降に最初にリリースされるリビジョン」と書かれているのはそのためで、12ヶ月が過ぎた当日に消えるわけではありません。
12ヶ月は最短ラインです。公式ポリシーには、非推奨のまま12ヶ月をはるかに超えて仕様に残ってよいとも書かれています。
セキュリティが理由の場合だけ、期間を短縮できます(Expedited removal)。条件は、公開された脆弱性アドバイザリか実環境での悪用が報告されていて、仕様の内側で緩和策がないことです。Core Maintainersの承認が要り、それでも非推奨から最短除去日まで90日以上は空けます。
非推奨の提案が通る条件と、元に戻る道
非推奨にできる理由として、ポリシーは次の4つを挙げています。
- 同じ用途をカバーする別の機能に置き換わった
- セキュリティ、プライバシー、相互運用性のリスクがあり、その場で緩和できない
- エコシステムの利用状況やSDKメンテナーの合意から見て、維持コストに見合う採用がない
- そのほか、Core Maintainersが妥当と判断した理由
移行先に別の機能を挙げる場合、その機能は非推奨が発効するリビジョンの時点でActiveでなければなりません。置き換えと非推奨が同じリビジョンに入ることは認められています。
一方向の廃止だけでなく、戻る手続きもあります。Deprecatedの機能は、事情の変化を説明した新しいSEPが元のSEPを上書きする形で承認されれば、Activeへ復帰します。復帰後に再び非推奨になると、12ヶ月のカウントは新しい非推奨が発効したリビジョンから数え直しです。過去に消化した期間は引き継がれません。延長や短縮にも、同じようにSEPが要ります。
1つのCurrentと複数リビジョン対応は両立する — リクエストごとの宣言
Currentとして示されるのは1つですが、実装は複数のリビジョンに同時対応できます。2026-07-28のリビジョンにはネゴシエーションのハンドシェイクがありません。クライアントが各リクエストで使うバージョンを宣言し、サーバーはリクエストごとに受け入れるか拒否するかを決めます。
宣言の置き場所は、リクエストの_metaにあるio.modelcontextprotocol/protocolVersionというキーです。Streamable HTTPでは、同じ値をMCP-Protocol-Versionヘッダーにも載せます。サーバーが対応しないバージョンを受け取ると、UnsupportedProtocolVersionErrorで応答します。
{
"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を見れば、そのサーバーが対応するリビジョンが分かります。クライアントはここから互いに使えるバージョンを選んで再送し、無ければユーザーにエラーを返します。
事前に調べたいクライアント向けに、サーバーはserver/discoverの実装が必須です。対応バージョン、ケイパビリティ、サーバーの識別情報を1回のリクエストで返します。クライアントが呼ぶかどうかは任意で、いきなり通常のリクエストを送り、エラーが返ってから再送する使い方も認められています。
旧リビジョンのクライアントとサーバーをつなぐと何が起きるか
2026-07-28より前のリビジョン(2025-11-25以前)は、initializeのハンドシェイクでセッションを張る方式でした。仕様はこの2つの時代を次のように呼び分けます。
- Modern: バージョン、識別情報、ケイパビリティをリクエストごとのメタデータで運ぶリビジョン(2026-07-28以降)
- Legacy:
initializeでセッションを確立するリビジョン(2025-11-25以前) - Dual-era: 両方に対応する実装
どの組み合わせが動くかは、仕様の互換性マトリクスにまとまっています。
| クライアント | サーバー | 結果 |
|---|---|---|
| Modern | サーバーModern | 結果動く。server/discoverは任意 |
| Modern | サーバーLegacy | 結果失敗する。サーバーの応答は実装次第 |
| Dual-era | サーバーModern | 結果動く。Modernのまま接続する |
| Dual-era | サーバーLegacy | 結果動く。initializeにフォールバックする |
| Legacy | サーバーModern | 結果失敗する。旧クライアントには前進する手段がない |
| Legacy | サーバーDual-era | 結果動く。initializeに答え、旧リビジョンで応じる |
最も見落としやすいのはModernクライアントとLegacyサーバーの組み合わせです。サーバーはエラーを返すとは限らず、黙り込んだり、時代を区別できないメソッドを旧来の意味で処理したりすることもあります。stdioでは、先にserver/discoverを送って失敗を確定させる方法が仕様で想定されています。
両方の時代のサーバーに接続したいクライアントは、トランスポートごとに時代を見分けます。stdioはserver/discoverでプローブし、Modernとして認識できるエラー以外はinitializeへ落とします。Streamable HTTPは、Modernのリクエストを送って400 Bad Requestの本文を調べてから落とします。どちらの場合も、UnsupportedProtocolVersionErrorのようなModernのエラーが返ればModernサーバーと判定し、バージョンを変えて再送します。
時代の判定はリクエストごとではなく、サーバーの性質として扱います。クライアントはstdioならプロセスの存続中、HTTPならオリジンごとに結果をキャッシュするよう求められます。同じサーバー設定なら、再起動をまたいで保存してもかまいません。キャッシュした前提が外れたときは、再度プローブします。
Modernだけに対応するサーバーにも1点だけ作法があります。initializeへのエラーに、対応するバージョンを書いて返すことです。旧クライアントには先へ進む手段がなく、そのメッセージが利用者に見せられる唯一の手がかりになりえます。
拡張はどう扱われるか — ネゴシエーションの仕組み
リビジョンと機能の状態のほかに、オプションの拡張をつなぐ仕組みもあります。ケイパビリティのextensionsフィールドで、拡張の識別子を設定オブジェクトに対応づけて宣言する形です。識別子にはプレフィックスが必須で、MCP Appsはio.modelcontextprotocol/ui、Tasksはio.modelcontextprotocol/tasksです。
{
"capabilities": {
"tools": {},
"extensions": {
"io.modelcontextprotocol/tasks": {}
}
}
}空のオブジェクトは、追加設定なしで対応していることを表します。片方だけが拡張に対応している場合、対応側はコアの挙動に戻すか、適切なエラーでリクエストを拒否します。拡張はフォールバックの挙動を文書化するべきとされています。機能ライフサイクルのポリシーが対象とするのはコア仕様の機能なので、拡張にはActive/Deprecated/Removedの手続きは適用されません。
実例で見る — Roots・Sampling・HTTP+SSEの状態遷移
Deprecatedとして登録されている機能は、MCPの非推奨機能一覧から抜き出すと次のとおりです。
| 機能 | Deprecated化したリビジョン | 移行先 | 最短除去日 |
|---|---|---|---|
| Roots | Deprecated化したリビジョン2026-07-28 | 移行先ツールパラメータ・リソースURI・サーバー設定でのディレクトリ指定 | 最短除去日2027-07-28以降の最初のリビジョン |
| Sampling | Deprecated化したリビジョン2026-07-28 | 移行先LLMプロバイダーAPIへの直接統合 | 最短除去日2027-07-28以降の最初のリビジョン |
| Logging | Deprecated化したリビジョン2026-07-28 | 移行先stdioならstderr、それ以外はOpenTelemetry | 最短除去日2027-07-28以降の最初のリビジョン |
| Dynamic Client Registration | Deprecated化したリビジョン2026-07-28 | 移行先Client ID Metadata Documents | 最短除去日2027-07-28以降の最初のリビジョン |
| HTTP+SSEトランスポート | Deprecated化したリビジョン2025-03-26 | 移行先Streamable HTTP | 最短除去日SEP-2596がFinalになってから3ヶ月後 |
SamplingのincludeContext値"thisServer"/"allServers" | Deprecated化したリビジョン2025-11-25 | 移行先フィールドを省略するか"none"を使う | 最短除去日Samplingの最短除去日に追随 |
Removedの欄は空で、ポリシーの下で削除された機能はまだありません。削除が起きると、その行がRemovedの節に移り、削除を記録したchangelogへのリンクが付きます。
下の2行は、ポリシーより前から非推奨と呼ばれていた機能です。HTTP+SSEトランスポートとincludeContextの値は、SEP-2596によってポリシー下のDeprecatedに分類し直されました。HTTP+SSEの最短除去日が日付ではなく「SEP-2596がFinalになってから3ヶ月後」になっているのは、SEP-2596の移行措置で再分類されたためです。includeContextの行が示すように、機能全体ではなくフィールドの特定の値だけが対象になる場合もあります。
Deprecatedでも動き続ける — SDKの扱い
仕様から機能がRemovedになっても、各言語のSDKがその機能をリリースから落とす義務は生じません。SDKでの提供終了は、そのSDK自身のリビジョンサポートの方針に従います。
Tier 1のSDKには義務があります。ある機能がDeprecatedになったリビジョンがCurrentとしてリリースされたら、次のリリースで次の2点に対応します。
- その言語の標準的な仕組みで、対応するAPIをDeprecatedと表示する(Javaは
@Deprecated、.NETは[Obsolete]、TypeScriptは@deprecatedのJSDoc、GoはDeprecated:の慣習)。非推奨を決めたSEPと、可能なら最短除去日も参照する - 非推奨の機能が使われたときに、実行時の警告を出す(Pythonは
DeprecationWarning、Node.jsはprocess.emitWarningなど)。こちらは「推奨」の扱い
Tier 1 SDKが非推奨の機能を表示しない状態を続けると、Tierの格下げ手続きの対象になります。
誰が決めるのか — 提案から承認までの役割
非推奨化は1人では動きません。提案(非推奨・延長・復帰のどれも)は、コントリビューターなら誰でも出せますが、SEPにはMaintainerかCore Maintainerのスポンサーが要ります。
SEPの承認、削除の判断、延長や復帰の承認、セキュリティ理由での期間短縮の承認は、いずれもCore Maintainersがガバナンスの意思決定プロセスに従って行います。Lead Maintainersはこれらの承認すべてに拒否権を持ちます。
Deprecated Featuresレジストリの位置づけには、公式ページ同士で書き方の違いがあります。機能ライフサイクルのページは、レジストリを「何が廃止予定で、いつまでか」への正準な答えと呼びます。レジストリのページ自身は、機能ごとの非推奨通知とchangelogの項目を正典とし、自分はそれと整合させた派生ビューだと述べています。日付や移行先に食い違いを見つけたら、個別の通知とchangelogを優先する読み方になります。
まとめ
移行を計画するときは、レジストリの最短除去日と移行先を起点に、使っているSDKが警告を出す時期と、接続先サーバーがModernとLegacyのどちらかを合わせて見る形になります。
背景として、2026-07-28で何が変わったかの全体像はMCP仕様のバージョン履歴にあります。非推奨になったRootsとSamplingがクライアント接続でどう扱われるかはMCPクライアントの仕組み、MCPの基礎はMCPとはから読めます。