[v2] Era-negotiation probe drops spec-conformant server/discover responses (top-level resultType/_meta) and misclassifies modern servers as legacy
Mantenedores costumam responder em até 1 dia
Ninguém assumiu esta issue ainda.
Avaliação
- Dificuldade
- 4/5
- Tempo estimado
- 3-5 dias
- Facilidade para iniciantes
- 62/100
- Tipo de issue
- Bug
- Clareza
- Razoavelmente clara
- Status de atividade
- Ativa
- Stack de tecnologia
- typescript
- Domínio
- api, networking
Direção de pesquisa
Comece por ProbeWindow.open em client/dist/index.mjs e rastreie JSONRPCResultResponseSchema, wireResultResponse, decodeResult e classifyResult nos bundles mencionados. Reproduza com o Client fixado e uma resposta server/discover moldada conforme a especificação. Considera-se concluído quando a resposta conforme é aceita durante a negociação e falhas de parsing ou timeouts produzem um resultado diagnosticável em vez de uma classificação legacy enganosa.
Escrita pelo modelo de indexação a partir do texto da issue.
Descrição
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
- Linguagem predominante
- TypeScript
- Estrelas
- 13.6k
- Forks
- 2.5k
- Merge médio
- 1d 5h
- PRs com merge (30d)
- 62
Preparar o ambiente
- Sem Dockerfile nem arquivo Docker Compose
- Sem modelo de pull request
- Ler o guia de contribuição
Primeiros passos
- Leia a issue inteira e depois o guia de contribuição do projeto.
- Comente na issue dizendo que vai assumir — evita que duas pessoas façam o mesmo trabalho.
- Faça um fork do repositório e trabalhe em uma branch.
- Abra um pull request que referencie o número da issue.
Mais de modelcontextprotocol/typescript-sdk
-
[v1.x] Protocol.request keeps its abort listener after the request resolved, so a later abort sends notifications/cancelled for an answered request (1.30.0)Talvez já em andamento Um pull request vinculado a esta issue está aberto ou já foi mesclado. Abertav1
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 76/100
modelcontextprotocol/typescript-sdk#3090 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
[v2] e2e `protocol:timeout:max-total` is flaky over SSE: fake timers advance before the request reaches the serverTalvez já em andamento @Singmin assumiu há 6 dias. Abertav1 v2
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
modelcontextprotocol/typescript-sdk#3045 ·
Mantenedores costumam responder em até 1 dia
-
[v1.x] Backport #2654: `notifications/cancelled` with `requestId: 0` is ignored, so the first server→client request cannot be cancelled (still in 1.32.1)Talvez já em andamento @CloudCorpRecords assumiu há 7 dias. Abertav1
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 77/100
modelcontextprotocol/typescript-sdk#3043 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
v1 v2
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 72/100
modelcontextprotocol/typescript-sdk#2946 · 4 comentários ·
Mantenedores costumam responder em até 1 dia
-
[v2] URI template reserved expansions encode existing %HH sequences againTalvez já em andamento @takagibit18 assumiu há 23 dias. Abertav1 v2
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 84/100
modelcontextprotocol/typescript-sdk#2920 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
Todas as issues de modelcontextprotocol/typescript-sdk
Issues semelhantes
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 68/100
awesome-dsh-plugin/awesome-dsh-plugin#9184 ·
Mantenedores costumam responder em até 1 dia
-
RpcTest.makeClient: accept disableFatalDefectsTalvez já em andamento @effect-bot assumiu hoje. Aberta
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 75/100
Effect-TS/effect#9893 · 3 comentários ·
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 85/100
farion1231/cc-switch#8829 · 1 comentário ·
Mantenedores costumam responder em até 1 dia
-
[core-client] Remove unused hand-maintained transport helpers after the definition-table cutoverAbertadoc-audit enhancement
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 88/100
Mantenedores costumam responder em até 1 dia
-
Dificuldade 2/5 1-3 horas Facilidade para iniciantes 85/100