未対応のMCPのバージョンを拒否したら、AIクライアントが接続できなかった

English

この記事の目次

本記事の概要

私が個人会社で開発しているサービスのMCPサーバは、対応しないバージョンのヘッダを持つ要求を、認証の前にHTTPの400で拒否していた。MCPは、AIのアプリケーションを外部のツールやデータソースにつなぐ公開の規格で、Model Context Protocolの略である。バージョンのヘッダは、HTTPのクライアントがMCPの要求に付ける、仕様が定めるヘッダで、2025-11-25のような日付の文字列でMCPのバージョンを示す。対応するかどうかは、対応バージョンの一覧で判定していた。対応バージョンの一覧は、MCPサーバが対応すると表明するバージョンを並べたもので、サーバのコードに書いてある。この拒否のために、2026-09-24に、主要なAIクライアントがこのMCPサーバに接続できなかった。主要なAIクライアントは、利用者がMCPサーバをコネクタとして追加できるAIチャットの製品の1つである。

AIエージェントは初回の修正で、観測した2025-11-25を対応バージョンの一覧に1つ追加しただけだった。主要なAIクライアントは頻繁に更新されるので、私はこの修正に対して、バージョンの小さな違いで接続を拒否するのは厳しすぎる、と指摘した。AIエージェントは2回目の修正で、対応バージョンの一覧を2025-11-25と2025-06-18の2つにした。あわせて、日付の形で2026-07-28より小さい値なら、一覧に無くても受け付けるようにした。2026-07-28のバージョンで、MCPの仕様は、クライアントが最初に送ってバージョンを決めるinitializeの要求を使わない方式に変わった。2026-07-28以降の日付の値と、日付の形でない値には、400を返す処理を残した。MCPの仕様には、対応しないバージョンのヘッダを受け取ったサーバは400で応答する、というMUSTの規定、すなわち必ず守る義務の規定がある。AIエージェントは、私の判断に基づいて、一覧に無い2026-07-28より前のバージョンについて、この規定を意図して実装しなかった。翌日の2026-09-25に、AIエージェントは、2026-07-28のバージョンの要求にも応答できるようにMCPサーバを修正した。

最初の節では、主要なAIクライアントの接続を止めたバージョンのヘッダの検査を説明し、修正の前と2026-09-24の2回目の修正の後の検査の結果を表で示す。次の節では、legacyのバージョンの判定とmodernのバージョンの扱いを説明する。legacyのバージョンは、initializeの要求で接続を確立する2025-11-25以前のバージョンで、modernのバージョンは2026-07-28以降のバージョンである。この節には、翌日にMCPサーバを両方のバージョンに対応させた理由も書いている。続く節では、仕様の2つのMUSTの規定と、2回目の修正の後のMCPサーバの扱いを表で比べる。その後の節では、観測したバージョンを1つ追加した初回の修正と、私の指摘を説明する。最後の節では、受け取るものには寛容に、という堅牢性の原則と、RFC 9413がこの原則に付けた限定を説明する。そのうえで、2回目の修正を入れたMCPサーバが、この原則のうち想定外の入力への寛容の面の適用にも、RFC 9413の2.2節にある明確な規則の拡張にも当たらず、仕様が定めた扱いと違う扱いを意図して選んだ実装に当たることを整理する。

記事から得られること

MCPサーバを開発している方に向けて、次の3つを説明する。

本文は、2026-09-24から2026-09-25にかけて個人会社のサービスのMCPサーバを修正した記録と、2026-10-04に確かめたMCPの仕様とRFCの原文に基づいて書いている。

主要なAIクライアントの接続を止めたバージョンのヘッダの検査

私は個人会社でサービスを開発している。そのサービスのMCPサーバは、対応バージョンの一覧に無いバージョンのヘッダを、認証の前にHTTPの400で拒否していた。そのため、2026-09-24に主要なAIクライアントが接続できなかった。

MCPは、AIのアプリケーションを外部のツールやデータソースにつなぐ公開の規格で、Model Context Protocolの略である。主要なAIクライアントは、利用者がMCPサーバをコネクタとして追加できるAIチャットの製品の1つである。バージョンのヘッダは、HTTPのクライアントがMCPの要求に付ける、仕様が定めるヘッダである。値は2025-11-25のような日付の文字列で、MCPのバージョンを示す。対応バージョンの一覧は、MCPサーバが対応すると表明するバージョンを並べたもので、サーバのコードに書いてある。

2025-11-25以前のバージョンでは、クライアントが最初にinitializeの要求を送り、サーバとの間で使うバージョンを決める。この形で接続を確立するバージョンを、legacyのバージョンと呼ぶ。この名前は、2026-07-28のバージョンの仕様にある用語である。

2026-09-24より前のMCPサーバでは、対応バージョンの一覧は2025-06-18の1つだけだった。サーバのコードの注記には、2025-03-26のバージョンを表明しない理由が書いてあった。このバージョンには、JSON-RPCのバッチを受け取る実装を求める規定があり、MCPサーバはバッチに対応していない。MCPサーバは、バージョンのヘッダが無い要求を受け付けていた。

2026-09-24に、私はテスト環境のMCPサーバを主要なAIクライアントにコネクタとして追加した。主要なAIクライアントの画面は、接続中の表示のまま止まった。画面には、見つからないという趣旨のエラーとHTTPの400が表示された。この日の観測では、主要なAIクライアントは、最初のinitializeの要求からバージョンのヘッダに2025-11-25を入れていた。

同じ日に、AIエージェントはMCPサーバを2回修正した。2回目の修正で、対応バージョンの一覧を2025-11-25と2025-06-18の2つにした。クライアントがinitializeの要求で一覧のバージョンを求めれば、MCPサーバはそのバージョンで応答する。一覧に無いバージョンなら、2025-11-25で応答する。MCPサーバが400で拒否したときは、拒否したバージョンの値と接続元のUser-Agentを、警告としてログに記録する。

2026-07-28以降のバージョンにはinitializeの要求が無く、クライアントは要求ごとに要求のボディの_metaでバージョンを宣言する。このバージョンを、modernのバージョンと呼ぶ。次の表に、ヘッダの値ごとの検査の結果を並べる。

バージョンのヘッダの値 修正の前 2026-09-24の2回目の修正の後
2025-06-18 受け付ける 受け付ける
2025-11-25 400で拒否する 受け付ける
2026-07-28より小さい、そのほかの日付の値。例は2025-03-26 400で拒否する 受け付ける
modernのバージョンの値。2026-07-28以降の日付の値 400で拒否する 400で拒否する
日付の形でない値 400で拒否する 400で拒否する

legacyのバージョンの判定とmodernのバージョンの扱い

2回目の修正を入れたMCPサーバは、ヘッダの値がYYYY-MM-DDの形で2026-07-28より小さければ、legacyのバージョンと判定する。大小は文字列の比較で決まるので、この判定は値がYYYY-MM-DDの形であることに依存する。2025-11-25と2026-07-28のあいだの日付は仕様のバージョンに当たらないが、この判定ではlegacyのバージョンになる。

AIエージェントは、バージョンのヘッダの値がmodernのバージョンのときは400を返す処理を残した。legacyとmodernの両方のバージョンに対応する実装を、dual-eraと呼ぶ。この名前も2026-07-28のバージョンの仕様にある。AIエージェントが修正の説明に書いた理由は、dual-eraのクライアントが、400の応答のボディを見てlegacyのバージョンに切り替えることである。

私は2026-09-25に、MCPサーバをdual-eraにする作業を承認した。AIエージェントは、この作業の理由を次のように書いた。2026-09-24の時点では、主要なAIクライアントはlegacyのバージョンで通信していた。しかし、クライアントの更新はサーバの修正より速いので、主要なAIクライアントがmodernのバージョンへ移るより先にdual-eraにする。AIエージェントはこの作業の修正を2026-09-25に取り込んだ。MCPサーバはmodernのバージョンの要求にも応答するようになった。

仕様の義務と2回目の修正の後のMCPサーバ

2回目の修正を入れたMCPサーバは、クライアントがinitializeの要求で一覧に無いバージョンを求めたとき、別のバージョンで応答する義務を満たす。一方で、対応しないバージョンのヘッダに400を返す義務は、legacyのバージョンについて意図して満たしていない。

2025-06-18と2025-11-25のバージョンのLifecycleの文書には、サーバが応答するバージョンのMUSTの規定がある。求められたバージョンに対応するサーバは同じバージョンで応答し、対応しないサーバは別のバージョンで応答する。仕様は、この別のバージョンをサーバの最新のバージョンにすることを、SHOULDの規定、すなわち推奨の規定として定めている。

2025-06-18と2025-11-25のバージョンのTransportsの文書には、ヘッダのMUSTの規定がある。不正なバージョンか対応しないバージョンのヘッダを受け取ったサーバは、400 Bad Requestで応答する。AIエージェントは、この義務を、MCPサーバが満たしていない義務としてサーバの文書に書いた。

仕様のMUSTの規定 規定があるバージョン 2回目の修正を入れたMCPサーバ
initializeの要求で対応しないバージョンを求められたサーバは、対応する別のバージョンで応答する 2025-06-18、2025-11-25 2025-11-25で応答する
対応しないバージョンのヘッダを受け取ったサーバは、400で応答する 2025-06-18、2025-11-25 一覧に無いlegacyのバージョンについては意図して400を返さない

400を返す義務を意図して実装しないのは、バージョンの違いだけで接続を拒否しないという私の判断に基づく。2回目の修正で新たに受け付ける値は、仕様のバージョンの2025-03-26と2024-11-05と、仕様のバージョンに当たらない日付の値である。AIエージェントは、この判断の理由を次のように説明した。

観測したバージョンを1つ追加した初回の修正

AIエージェントは初回の修正で、観測した2025-11-25を対応バージョンの一覧に1つ追加しただけだった。修正の前のMCPサーバは、主要なAIクライアントが送った2025-11-25を400で拒否していた。

私は初回の修正に対して、バージョンの小さな違いで接続を拒否するのは厳しすぎると指摘した。主要なAIクライアントは頻繁に更新されるためである。

修正の前の検査は、一覧に無い値をすべて400で拒否していた。これらの事実から、観測したバージョンを一覧に1つ追加する修正では、次にクライアントがバージョンを上げると同じ400が起きる、と言える。

堅牢性の原則とRFC 9413による限定

堅牢性の原則は、受け取るものには寛容に、送るものには保守的に、という実装の原則である。RFC 1122には、この原則が挙げてあり、インターネット層では特に重要だと書いてある。

RFC 9413には、堅牢性の原則には3つの面がある、と書いてある。3つの面は、ソフトウェアの欠陥への堅牢性と、攻撃への堅牢性と、想定外の入力への堅牢性である。RFC 9413の第1節には、仕様が不正なメッセージの扱いを明示している場合を、想定外の入力への堅牢性の面から除く、と書いてある。RFC 9413には、前の2つの面が必要な指針である、とも書いてある。一方で、想定外の入力を寛容に受け付ける解釈は、すべての場面で最善の方法とは言えなくなった、と書いてある。

RFC 9413の2.2節には、拡張性を堅牢性の原則の適用と取り違えることがある、と書いてある。よく設計された拡張の仕組みでは新しいメッセージや引数の扱いが明確な規則で決まるので、それらは想定内の入力になる、とも書いてある。

MCPの仕様には、対応しないバージョンのヘッダに400で応答する規定がある。そのため、2回目の修正を入れたMCPサーバは、仕様が扱いを定めている入力に、仕様と違う扱いをする実装である。想定外の入力への堅牢性の面は、仕様が扱いを明示した入力を含まない。2.2節の明確な規則の拡張は、プロトコルが規則を定め、どの実装も、その規則のとおりに動く仕組みである。これらの事実から、2回目の修正を入れたMCPサーバは、堅牢性の原則のうち想定外の入力への寛容の面の適用にも、2.2節の拡張にも当たらない、と言える。仕様が定めた扱いと違う扱いを、意図して選んだ実装に当たる、と言える。

参考にした資料

本文で参照した公開の資料は次の6項目で、文書は8つである。いずれも2026-10-04に原文を確かめた。