[v2] Era-negotiation probe drops spec-conformant server/discover responses (top-level resultType/_meta) and misclassifies modern servers as legacy
メンテナーはふだん 1 日以内に返信
まだ誰も着手していません。
評価
- 難易度
- 4/5
- 見積もり時間
- 3〜5日
- 初心者へのやさしさ
- 62/100
- issue の種類
- バグ
- 明瞭さ
- おおむね明確
- 活発さ
- 活発
- 技術スタック
- typescript
- 領域
- api, networking
調査の方向性
client/dist/index.mjs の ProbeWindow.open から始め、言及されているバンドル内の JSONRPCResultResponseSchema、wireResultResponse、decodeResult、classifyResult を追跡します。固定された Client と、仕様に沿った形の server/discover レスポンスで再現します。完了条件は、ネゴシエーション中に準拠したレスポンスが受け入れられ、パースエラーやタイムアウトが誤解を招く legacy 分類ではなく、診断可能な結果を生成することです。
索引モデルが issue の本文から書いたものです。
説明
What happened?
Connecting a Client (stdio transport, pinned negotiation versionNegotiation: { mode: { pin: "2026-07-28" } }) to a spec-conformant MCP 2026-07-28 server fails:
SdkError [EraNegotiationFailed]: Version negotiation failed: the server did not offer
pinned protocol version 2026-07-28 via server/discover (no fallback in pin mode)
The server's response is spec-conformant per the 2026-07-28 Server Discovery spec example, where resultType and _meta appear as top-level siblings of result. Wire-captured exchange (server side verified correct via a binary stdio interceptor):
{"jsonrpc":"2.0","id":"server-discover-probe-1","resultType":"complete","result":{"supportedVersions":["2026-07-28"],"capabilities":{"tools":{"listChanged":false}},"instructions":"..."},"_meta":{"io.modelcontextprotocol/serverInfo":{"name":"<server-name>","version":"0.1.0"}}}
Root cause chain (dist line numbers from @modelcontextprotocol/client 2.0.0 / @modelcontextprotocol/core 2.0.0):
JSONRPCResultResponseSchema = z.object({ jsonrpc, id, result }).strict()(@modelcontextprotocol/core/dist/auth-CUe6YdwF.mjs:191-197; mirrored aswireResultResponse(...).strict()inclient/dist/src-D_zzAWoS.mjs:3178) rejects the unknown top-level membersresultType/_meta.ProbeWindow.open'stransport.onmessageguard (client/dist/index.mjs:2518-2524) resolves pending probes only whenisJSONRPCResultResponse(...) || isJSONRPCErrorResponse(...); the rejected message is dropped silently.- On timeout, the stdio classifier returns
{kind:'legacy'}(index.mjs:2321-2323), so pin mode throws atindex.mjs:2727— a modern, spec-literal server gets misdiagnosed as legacy. - Related:
decodeResult(src-D_zzAWoS.mjs:3920+) runs only on the post-handshake request path (~line 6120), never during the probe, so even a non-dropped envelope would reachclassifyResult'svalidateResultwithout decoding.
A raw newline-delimited JSON probe sending exactly this request shape succeeds against the same binary — only the SDK path fails.
What did you expect?
Per the 2026-07-28 Server Discovery spec, the probe should decode the response envelope before classification (or tolerate extra top-level members), and a silently-dropped/timed-out probe reply should surface as a diagnosable error rather than being classified as "legacy".
Suggested fixes (any of)
- Run
decodeResultin the probe path beforeclassifyResult. - Relax
.strict()→ passthrough when parsing response envelopes in the probe window. - Minimum viable: log when a probe reply fails envelope parsing instead of silently timing out into a misleading legacy verdict.
Code to reproduce
import { Client } from "@modelcontextprotocol/client";
import { StdioClientTransport } from "@modelcontextprotocol/client/stdio";
// Any stdio server answering server/discover with the spec-example shape
// (resultType/_meta as top-level siblings of result):
const transport = new StdioClientTransport({ command: "<server-command>" });
const client = new Client(
{ name: "repro", version: "1.0.0" },
{ versionNegotiation: { mode: { pin: "2026-07-28" } }, capabilities: {} },
);
await client.connect(transport); // -> EraNegotiationFailed after ~60s silent timeout
SDK version
@modelcontextprotocol/client 2.0.0, @modelcontextprotocol/core 2.0.0
Area
Client
- 主要言語
- TypeScript
- スター
- 13.6k
- フォーク
- 2.3k
- 平均マージ
- 1日 15時間
- マージ済み PR(30日)
- 51
環境構築
- Dockerfile・Docker Compose ファイルなし
- プルリクエストのテンプレートなし
- コントリビューションガイドを読む
はじめの一歩
- issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
- 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
- リポジトリをフォークし、ブランチを切って変更します。
- issue 番号を参照したプルリクエストを送ります。
modelcontextprotocol/typescript-sdk のほかの issue
-
Stateless 405 response omits the Allow header対応中かも @Hugo-DDT が 1 日前に担当しました。 オープンv2
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
modelcontextprotocol/typescript-sdk#2970 · コメント 2 件 ·
メンテナーはふだん 1 日以内に返信
-
[v2] @modelcontextprotocol/server inlines fast-uri 3.1.0, which has 9 published advisories対応中かも @Andiii208 が 4 日前に担当しました。 オープンv2
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
modelcontextprotocol/typescript-sdk#2966 · コメント 3 件 ·
メンテナーはふだん 1 日以内に返信
-
v1 v2
難易度 2/5 1〜3時間 初心者へのやさしさ 72/100
modelcontextprotocol/typescript-sdk#2946 · コメント 4 件 ·
メンテナーはふだん 1 日以内に返信
-
[v2] URI template reserved expansions encode existing %HH sequences again対応中かも @takagibit18 が 10 日前に担当しました。 オープンv1 v2
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
modelcontextprotocol/typescript-sdk#2920 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
[v2] URI template strict expansions leave !'()* unencoded対応中かも @takagibit18 が 10 日前に担当しました。 オープンv1 v2
難易度 2/5 1〜3時間 初心者へのやさしさ 84/100
modelcontextprotocol/typescript-sdk#2919 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
modelcontextprotocol/typescript-sdk の issue をすべて見る
似ている issue
-
難易度 2/5 1〜3時間 初心者へのやさしさ 77/100
apache/rocketmq-dashboard#6610 ·
メンテナーはふだん 3 日以内に返信
-
nextjs-tracking
難易度 2/5 1〜3時間 初心者へのやさしさ 69/100
cloudflare/vinext#3920 ·
メンテナーはふだん 1 日以内に返信
-
Team:Dashboards
難易度 2/5 1〜3時間 初心者へのやさしさ 65/100
elastic/kibana#297299 · コメント 1 件 ·
メンテナーはふだん 1 日以内に返信
-
analytics beginner friendly community contributions-welcome good first issue hacktoberfest help wanted up-for-grabs
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
メンテナーはふだん 1 日以内に返信
-
affected/v17 affected/v18 area/frontend type/bug
難易度 2/5 1〜3時間 初心者へのやさしさ 82/100
umbraco/Umbraco-CMS#24186 ·
メンテナーはふだん 2 日以内に返信