MCP_PROTOCOL_NEGOTIATIONとは — Claude Codeの新プロトコル交渉を切り替える
MCP_PROTOCOL_NEGOTIATIONは、Claude CodeがMCPサーバーにプロトコル改訂2026-07-28を尋ねるかを決める環境変数です。autoとlegacyの違い、対象サーバー、legacyを選ぶ場面をまとめます。
MCP_PROTOCOL_NEGOTIATIONは、Claude CodeがMCPサーバーへ接続するとき「プロトコル改訂2026-07-28を話せますか」と尋ねるかどうかを決める環境変数です。値はautoとlegacyの2つ。autoは尋ねる対象を広げ、legacyはどのサーバーにも尋ねず、従来のハンドシェイクで接続します。
v2.1.292でローカルのstdioサーバーが既定で尋ねられる側に入り、v2.1.295ではclaude.aiコネクタも同じ扱いになりました。自分のMCPサーバーが急に遅くなった、チャンネルとして登録されなくなった、という症状の切り分けに、この変数が使えます。
この変数が切り替えるのは「尋ねるか」だけ
Claude CodeにはMCPクライアントのランタイムが2つあります。v1はMCP TypeScript SDK 1.xの上に作られ、v2は同じコードをMCP TypeScript SDK 2.0に載せ替えたものです。新しいプロトコル改訂2026-07-28を扱えるのはv2だけで、MCP_PROTOCOL_NEGOTIATIONもv2ランタイムにだけ効きます。要件はv2.1.221以降です。
役割は次のように分かれます。
| 変数 | 決めること | 値 |
|---|---|---|
MCP_SDK_GENERATION | 決めることどのランタイムで接続するか | 値v1 / v2 |
MCP_PROTOCOL_NEGOTIATION | 決めることv2で新改訂を尋ねるか | 値auto / legacy |
ランタイムの固定はMCP_SDK_GENERATIONの仕事です。legacyを設定してもv2ランタイムのままなので、v2側で変わった他の挙動は戻りません。たとえばMCPのOAuthサインインで、認可レスポンスの発行者が想定と違えば失敗する動きは、ランタイム側の仕様です。
2つの変数の組み合わせは、次のとおりです。
MCP_SDK_GENERATION | MCP_PROTOCOL_NEGOTIATION | 接続の結果 |
|---|---|---|
未設定またはv2 | MCP_PROTOCOL_NEGOTIATION未設定・auto | 接続の結果v2ランタイムで、HTTP・stdio・claude.aiコネクタに新改訂を尋ねる |
未設定またはv2 | MCP_PROTOCOL_NEGOTIATIONlegacy | 接続の結果v2ランタイムのまま、どのサーバーにも尋ねない |
v1 | MCP_PROTOCOL_NEGOTIATION何を入れても | 接続の結果v1ランタイムで接続し、MCP_PROTOCOL_NEGOTIATIONは効かない |
MCP_SDK_GENERATIONが未設定のとき、v2が選ばれる版はセッションの種類で違います。フラグを取得するセッションはv2.1.232以降、取得しないセッションはv2.1.274以降です。後者にはBedrock、Claude Platform on AWS、Google CloudのAgent Platform、Microsoft Foundryのセッション、Claude appsゲートウェイ経由のサインイン、テレメトリやフラグ取得を止めた環境が入ります。
新改訂で接続すると何が変わるか
新改訂で接続したサーバーは、扱いが3点変わります。1つ目はlist_changed通知の受け方です。v2ランタイムは、新改訂のサーバーからの通知を、開いたままにしたストリームで受け取ります。ツール一覧の動的な更新を使うサーバーを作っているなら、この経路の違いが再接続の挙動に出ます。仕組みはMCPの動的ツール更新と再接続で扱っています。
2つ目はチャンネルです。新改訂はチャンネルメッセージを運べないので、新改訂で接続したチャンネルサーバーは登録されません。3つ目はElicitationで、フォーム形式とURL形式の両方を宣言して接続します。この3点のどれにも当たらないサーバーは、改訂が変わっても使い勝手はほぼ同じです。
どのサーバーに尋ねるか
変数を設定したときの挙動は、サーバーの種類ごとに次のとおりです。
| サーバーの種類 | 未設定 | auto | legacy |
|---|---|---|---|
| HTTP | 未設定尋ねる | auto尋ねる | legacy尋ねない |
| stdio | 未設定尋ねる | auto尋ねる | legacy尋ねない |
| claude.aiコネクタ | 未設定尋ねる | auto尋ねる | legacy尋ねない |
| SSE・WebSocketなど | 未設定尋ねない | auto尋ねない | legacy尋ねない |
未設定のときは、HTTP・stdio・claude.aiコネクタのサーバーに新改訂を尋ね、対応していれば新改訂を使います。それ以外のサーバーはv1と同じ方法で接続します。autoはこの3種類に尋ねる設定、legacyはどれにも尋ねない設定です。
既定で尋ねる対象は、3回のリリースで広がりました。
既定で尋ねる対象が広がった経緯
- v2.1.274HTTPサーバー
Bedrock、Vertex、Foundryとテレメトリ無効のインストールも、v2クライアントで直接のHTTPサーバーに尋ねる既定になりました。
- v2.1.292stdioサーバー
ローカルのstdioサーバーが、Bedrock、Vertex、Foundryを含む全インストールで既定の対象になりました。
- v2.1.295claude.aiコネクタ
フラグを取得しないインストールでも、claude.aiコネクタが既定で尋ねられるようになりました。
それぞれの項目に、MCP_PROTOCOL_NEGOTIATION=legacyで戻せるという注記が付いています。各版の全体像はv2.1.292のリリースノートとv2.1.295のリリースノートにあります。
MCP_PROTOCOL_NEGOTIATIONの設定方法
シェルで一時的に切り替えるなら、起動時に付けるだけです。
# 新しい改訂を一切尋ねない
MCP_PROTOCOL_NEGOTIATION=legacy claude
# 尋ねる対象を明示する
MCP_PROTOCOL_NEGOTIATION=auto claude毎回付けたくないときは、settings.jsonのenvキーに入れます。
{
"env": {
"MCP_PROTOCOL_NEGOTIATION": "legacy"
}
}envの値は、claudeをどう起動しても読まれます。プロジェクトの.claude/settings.jsonに入れれば、チーム全員のstdioサーバーを同じ接続方式にそろえられます。
autoとlegacy以外の値は無視され、デバッグログに警告が出ます。Legacyやoffのような書き間違いは、エラーにならず既定の挙動のまま動くので、効いていないと感じたらまず綴りを見てください。
legacyを選ぶ場面
新しい改訂で困らない限り、既定のままで構いません。legacyを検討するのは次の3つの状況です。
チャンネルサーバーが登録されない
MCPサーバーがclaude/channelケイパビリティでメッセージを押し込む「チャンネル」の場合、v2ランタイムで新改訂を交渉すると、その改訂はチャンネルメッセージを運べないため、チャンネルとして登録されません。新改訂を話さないサーバーなら従来のハンドシェイクで接続し、これまでどおり登録されます。
stdioのチャンネルサーバーは既定で尋ねる側に入りました。更新後にチャンネル通知が来なくなったら、MCP_PROTOCOL_NEGOTIATION=legacyで従来のハンドシェイクに戻せます。legacyはすべてのサーバーを戻す設定です。チャンネルの仕組みはChannelsの解説、MCPサーバー側の設定はMCPチャンネルの手順で扱っています。
応じないstdioサーバーの最初の接続が遅い
新改訂の確認に応じないstdioサーバーは、最初の接続が1回だけ遅くなることがあります。v2.1.292では、その後そのサーバーを7日間覚えておき、待たずに従来の方式で接続する改善も入りました。毎回の起動で待たされるわけではありません。
それでも1回目の待ちが業務の都合で困る場合は、legacyを設定すれば最初から尋ねません。逆に、サーバーを新しい改訂に対応させたい開発者は、autoか未設定のまま接続を確かめられます。
新改訂側の機能を試したい
新改訂の接続では、Claude Codeがクライアントのケイパビリティとしてelicitation: {form: {}, url: {}}を宣言します。サーバーはフォーム形式とURL形式のどちらでも入力を求められます。ElicitationをMCPサーバー側で作っているなら、新改訂で接続されているかどうかが動作確認の前提です。違いはElicitationのフォームとURLにまとめています。
切り替えて確かめる手順
症状が新プロトコル交渉に関係するかどうかは、設定を1つだけ変えて比べると切り分けられます。
切り分けの流れ
- 1
バージョンを見る
claude --versionでv2.1.292以降かを確かめます。stdioサーバーの既定化はこの版からです。 - 2
legacyで起動する
MCP_PROTOCOL_NEGOTIATION=legacy claudeで起動し、症状が消えるか見ます。消えれば、新改訂の交渉が関係しています。 - 3
ランタイムの影響を分ける
消えない場合は
MCP_SDK_GENERATION=v1も付けて試します。ランタイム側の違いか、交渉の違いかを分けられます。 - 4
サーバーを再接続する
設定を変えたら、
/mcpの画面から該当サーバーを再接続して、状態を見直します。
MCP_SDK_GENERATIONの値はプロセスごとに1回だけ読み取られます。
legacyにしてもサインインが通らないとき
MCP_PROTOCOL_NEGOTIATION=legacyにしても直らない症状が、OAuthまわりに2つあります。どちらもv2ランタイムの仕様で、尋ねるかどうかとは別の動きです。
| 症状 | 原因 | 対処 |
|---|---|---|
Issuer mismatch in authorization responseで始まるエラーでサインインに失敗する | 原因v2ランタイムが、認可レスポンスの発行者(issuer)を確かめ、一致しないと失敗させる。v2.1.221以降 | 対処認可サーバーが返す発行者を正しい値にそろえる。v1ランタイムはこの確認をしないので、MCP_SDK_GENERATION=v1で挙動を比べられる |
トークンエンドポイントが平文のhttp://のサーバーでサインインに失敗する | 原因v2ランタイムは、HTTPSかlocalhost、127.0.0.1、::1のトークンエンドポイントにだけ資格情報を送る | 対処ローカルネットワーク上の機器などは、エンドポイントをHTTPSにする。詳細はerrorsのページの「Refusing to send credentials to non-https token endpoint」の項 |
エラーが出た段階でlegacyを試して変わらなければ、交渉ではなくランタイムの確認に当たっています。切り分けの次の一手はMCP_SDK_GENERATIONです。
運用で気を付ける点
チームで使うときは、次の3点を決めておくと、更新後の挙動差で迷いにくくなります。
- 共有設定では
autoかlegacyのどちらかを明示し、未設定の既定に頼らない - 版が上がるたびに既定の対象が広がるので、更新後は自作のstdioサーバーとチャンネルサーバーを1回ずつ起動して確かめる
- Bedrockなどのセッションでは、Claude Codeを組み込むホスト側が
CLAUDE_CODE_PROVIDER_MANAGED_BY_HOSTを設定していると、v2が既定になりません。この変数はCLAUDE_CODE_PROVIDER_MANAGED_BY_HOSTの記事にあります
新改訂に未対応のサーバーは、これまでどおり従来のハンドシェイクで動きます。ユーザー側が何もしなくても壊れる設計ではなく、設定が必要になるのは、チャンネルのように新改訂の側で制約がある用途に限られます。
まとめ
MCP_PROTOCOL_NEGOTIATIONは、v2ランタイムが新改訂2026-07-28を尋ねるかどうかの切り替えです。legacyは尋ねない、autoは尋ねる対象を広げる設定で、未設定でもHTTP、stdio、claude.aiコネクタには尋ねます。症状が出たら、legacyで起動して比べる1手で、原因が交渉にあるかどうかを分けられます。