From ac89541be973448aee88a255ae0bcc061a6609e2 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Fri, 19 Jun 2026 11:57:24 +0000 Subject: [PATCH 1/3] feat(core): adopt spec#2907 / conformance#353 error-code renumber for 2026-07-28 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit HeaderMismatch -32001 -> -32020, MissingRequiredClientCapability -32003 -> -32021, UnsupportedProtocolVersion -32004 -> -32022. These codes are part of the draft 2026-07-28 protocol revision only and have never appeared on a 2025-era wire — the 2025 serving paths and the SDK-conventional -32001 ('Session not found') on the stateful Streamable HTTP transport are unchanged. - ProtocolErrorCode enum members and HEADER_MISMATCH_ERROR_CODE constant renumbered; spec.types.2026-07-28 anchor constants follow. - Emission sites (createMcpHandler/serveStdio/inboundClassification/mcpParamHeaders), the LADDER_ERROR_HTTP_STATUS table and the multi-round-trip capability gate emit the renumbered codes via the renumbered enum members. - Client recognition: the probe classifier recognizes -32022 for the corrective continuation, NOT_PROBE_RECOGNIZED keeps -32001 (deployed Session-not-found overload) and adds -32020/-32021; ProtocolError.fromError reconstructs the typed classes from the renumbered codes; the SEP-2243 one-refresh-on-miss retry keys on -32020. - encodeErrorCode pass-through pin: -32000 literal untouched; the pass-through list updated to -32020/-32021/-32022. - Conformance: request-metadata / server-stateless / http-custom-header-server-validation / http-header-validation now pass; the 'renumber pending Felix ruling' entries are burned from both expected-failures yamls and the header NOTE rewritten to reflect alignment. - Migration docs note the alpha-to-alpha renumber (no v1.x->v2 impact). The vendored schema-twins/2026-07-28.schema.json and corpus/fixtures/2026-07-28/* are deliberately untouched — they are sha256- locked upstream artifacts at spec commit 2fb207da (pre-#2907) and refresh atomically with the next spec-anchor repin. --- .changeset/envelope-auto-emission.md | 2 +- .changeset/missing-client-capability-error.md | 2 +- .changeset/mrtr-server-seam.md | 2 +- .changeset/pin-modern-rejection-codes.md | 2 +- .changeset/sep-2243-mcp-param-server.md | 2 +- .changeset/sep-2243-std-header-server.md | 2 +- .changeset/spec-2907-error-code-renumber.md | 7 +++ .changeset/spec-anchor-repin-2fb207da.md | 2 +- .changeset/spec-reference-types-2026-07-28.md | 2 +- docs/client.md | 2 +- docs/migration-SKILL.md | 4 +- docs/migration.md | 18 +++++--- docs/server.md | 2 +- packages/client/src/client/client.ts | 10 ++--- packages/client/src/client/probeClassifier.ts | 20 +++++---- .../client/src/client/versionNegotiation.ts | 4 +- .../test/client/mcpParamMirroring.test.ts | 10 ++--- .../test/client/probeClassifier.test.ts | 43 +++++++++++-------- .../test/client/probeFixtureCorpus.test.ts | 12 +++--- .../test/client/versionNegotiation.test.ts | 20 ++++----- .../shared/clientCapabilityRequirements.ts | 4 +- .../core/src/shared/inboundClassification.ts | 14 +++--- packages/core/src/shared/mcpParamHeaders.ts | 8 ++-- packages/core/src/shared/protocol.ts | 2 +- packages/core/src/types/enums.ts | 4 +- packages/core/src/types/errors.ts | 4 +- .../core/src/types/spec.types.2026-07-28.ts | 8 ++-- packages/core/src/types/types.ts | 4 +- .../clientCapabilityRequirements.test.ts | 2 +- .../test/shared/errorHttpStatusMatrix.test.ts | 10 ++--- .../test/shared/inboundClassification.test.ts | 14 +++--- .../shared/inboundLadderCellSheet.test.ts | 40 ++++++++--------- .../core/test/shared/mcpParamHeaders.test.ts | 10 ++--- packages/core/test/shared/protocol.test.ts | 4 +- .../shared/standardHeaderValidation.test.ts | 4 +- .../core/test/spec.types.2026-07-28.test.ts | 4 +- .../types/crossBundleErrorRecognition.test.ts | 12 +++--- .../core/test/types/errorSurfacePins.test.ts | 8 ++-- packages/core/test/types/errors.test.ts | 10 ++--- .../missingClientCapabilityError.test.ts | 18 ++++---- .../core/test/wire/encodeContract.test.ts | 2 +- packages/core/test/wire/eraGates.test.ts | 10 ++--- .../server/src/server/createMcpHandler.ts | 6 +-- packages/server/src/server/server.ts | 4 +- .../test/server/createMcpHandler.test.ts | 14 +++--- .../createMcpHandlerCapabilityGate.test.ts | 6 +-- .../server/test/server/inputRequired.test.ts | 14 +++--- .../server/test/server/invokeSeam.test.ts | 2 +- .../test/server/mcpParamValidation.test.ts | 14 +++--- .../test/server/perRequestTransport.test.ts | 8 ++-- .../server/test/server/serveStdio.test.ts | 14 +++--- .../test/server/serveStdioListen.test.ts | 2 +- .../test/server/stdHeaderValidation.test.ts | 12 +++--- .../expected-failures.2026-07-28.yaml | 20 +++------ test/conformance/expected-failures.yaml | 33 +++----------- test/conformance/src/everythingClient.ts | 2 +- test/conformance/src/everythingServer.ts | 2 +- test/e2e/requirements.ts | 2 +- test/e2e/scenarios/sep2243.test.ts | 6 +-- .../test/server/createMcpHandler.test.ts | 2 +- .../test/server/dualEraStdio.test.ts | 2 +- 61 files changed, 261 insertions(+), 268 deletions(-) create mode 100644 .changeset/spec-2907-error-code-renumber.md diff --git a/.changeset/envelope-auto-emission.md b/.changeset/envelope-auto-emission.md index d832c64d8d..9ae614a84f 100644 --- a/.changeset/envelope-auto-emission.md +++ b/.changeset/envelope-auto-emission.md @@ -8,4 +8,4 @@ Per-request `_meta` envelope auto-emission on modern-era connections: once a cli (the default, and the `'auto'`-mode fallback) never gain these keys, so 2025-era outbound traffic is byte-identical to before. Adds `Client.getProtocolEra()` (`'legacy' | 'modern' | undefined`), the `ProtocolEra` type, `Client.setVersionNegotiation()` for configuring negotiation pre-connect on an already-constructed instance, and the `probe.maxRetries` knob (default `0`) which governs probe-timeout -re-sends only — the spec-mandated `-32004` corrective continuation is never counted against it. The `versionNegotiation` default remains `'legacy'`: absent (or `mode: 'legacy'`), `connect()` runs the plain 2025 sequence, byte-identical to a v1.x client. +re-sends only — the spec-mandated `-32022` corrective continuation is never counted against it. The `versionNegotiation` default remains `'legacy'`: absent (or `mode: 'legacy'`), `connect()` runs the plain 2025 sequence, byte-identical to a v1.x client. diff --git a/.changeset/missing-client-capability-error.md b/.changeset/missing-client-capability-error.md index 9653679e05..842e44073b 100644 --- a/.changeset/missing-client-capability-error.md +++ b/.changeset/missing-client-capability-error.md @@ -4,4 +4,4 @@ '@modelcontextprotocol/server': minor --- -Add `MissingRequiredClientCapabilityError`, the typed error class for the 2026-07-28 `-32003` protocol error (processing a request requires a capability the client did not declare). Its `data.requiredCapabilities` lists the missing capabilities and `ProtocolError.fromError` recognizes the code/data shape. The 2026-07-28 HTTP entry gains a pre-dispatch gate that refuses a request requiring an undeclared client capability with this error and HTTP status `400`; no method served on the 2026-07-28 registry currently carries such a requirement, so observable behavior is unchanged until methods with capability requirements exist. +Add `MissingRequiredClientCapabilityError`, the typed error class for the 2026-07-28 `-32021` protocol error (processing a request requires a capability the client did not declare). Its `data.requiredCapabilities` lists the missing capabilities and `ProtocolError.fromError` recognizes the code/data shape. The 2026-07-28 HTTP entry gains a pre-dispatch gate that refuses a request requiring an undeclared client capability with this error and HTTP status `400`; no method served on the 2026-07-28 registry currently carries such a requirement, so observable behavior is unchanged until methods with capability requirements exist. diff --git a/.changeset/mrtr-server-seam.md b/.changeset/mrtr-server-seam.md index 861d7df9b6..51f7fa06b5 100644 --- a/.changeset/mrtr-server-seam.md +++ b/.changeset/mrtr-server-seam.md @@ -6,7 +6,7 @@ Add the server side of multi round-trip requests (protocol revision 2026-07-28, SEP-2322). Handlers for `tools/call`, `prompts/get`, and `resources/read` can return the value built by `inputRequired()` (exported from the server package together with `acceptedContent()`) to request additional client input in-band; the structured-content requirement and the tools/call result-schema validation are skipped for that return, the encode seam emits it as `resultType: 'input_required'`, and the handler reads the responses on re-entry from `ctx.mcpReq.inputResponses` (with non-bare entries reported via `ctx.mcpReq.droppedInputResponseKeys`). The seam re-checks the at-least-one rule for hand-built results, checks every embedded request against the capabilities the client declared on that request's envelope -(answering the typed `-32003` error on violation), and fails loudly — never emitting a mis-typed result — when an input-required value is returned from any other method or toward a 2025-era request. A `UrlElicitationRequiredError` escaping a handler on a 2026-era request +(answering the typed `-32021` error on violation), and fails loudly — never emitting a mis-typed result — when an input-required value is returned from any other method or toward a 2025-era request. A `UrlElicitationRequiredError` escaping a handler on a 2026-era request fails as an internal error with a clear steer to `inputRequired.elicitUrl(...)`, so the `-32042` error never reaches the 2026-07-28 wire; 2025-era serving keeps today's `-32042` behavior exactly. The typed local error raised when push-style server-to-client request APIs are used while serving a 2026-era request now steers to `inputRequired(...)`. Tool, prompt, and resource callback types accept the new return alongside their existing result types; 2025-era wire behavior is unchanged. An optional `ServerOptions.requestState.verify` hook lets a server integrity-check the echoed `requestState` before the handler runs — a throw answers the wire-level `-32602` Invalid Params error with `data.reason: 'invalid_request_state'`; the SDK provides no default verification. diff --git a/.changeset/pin-modern-rejection-codes.md b/.changeset/pin-modern-rejection-codes.md index f54bdd9785..9638c7eac0 100644 --- a/.changeset/pin-modern-rejection-codes.md +++ b/.changeset/pin-modern-rejection-codes.md @@ -3,4 +3,4 @@ '@modelcontextprotocol/server': patch --- -Pin the modern (2026-07-28) HTTP serving path's rejection codes to the assignments the published conformance suite asserts: a header/body cross-check mismatch (`MCP-Protocol-Version` or `Mcp-Method` disagreeing with the request body) is now rejected with `-32001` (HeaderMismatch), and a request whose protocol-version header names a modern revision but whose body is missing the `_meta` envelope (or its required protocol-version key) is rejected with `-32602` invalid params naming the missing key(s). Both keep HTTP 400. These cells previously emitted a provisional `-32004` while the upstream error-code discussion was open. The envelope-less rejection on a modern-only endpoint (`-32004` with the supported-versions list), the 2025-era serving paths, and the client-side probe handling are unchanged. +Pin the modern (2026-07-28) HTTP serving path's rejection codes to the assignments the published conformance suite asserts: a header/body cross-check mismatch (`MCP-Protocol-Version` or `Mcp-Method` disagreeing with the request body) is now rejected with `-32020` (HeaderMismatch), and a request whose protocol-version header names a modern revision but whose body is missing the `_meta` envelope (or its required protocol-version key) is rejected with `-32602` invalid params naming the missing key(s). Both keep HTTP 400. These cells previously emitted a provisional `-32022` while the upstream error-code discussion was open. The envelope-less rejection on a modern-only endpoint (`-32022` with the supported-versions list), the 2025-era serving paths, and the client-side probe handling are unchanged. diff --git a/.changeset/sep-2243-mcp-param-server.md b/.changeset/sep-2243-mcp-param-server.md index 796b42ec53..fc0316cfb7 100644 --- a/.changeset/sep-2243-mcp-param-server.md +++ b/.changeset/sep-2243-mcp-param-server.md @@ -2,4 +2,4 @@ '@modelcontextprotocol/server': minor --- -SEP-2243 `Mcp-Param-*` server-side validation (protocol revision 2026-07-28). On the modern (2026-07-28) serving path, `createMcpHandler` now validates `Mcp-Param-{Name}` headers against the named tool's `x-mcp-header` declarations and the body `arguments` before dispatch: a missing header for a present body value, a header that decodes to a different value than the body, or an invalid `=?base64?…?=` sentinel is rejected with `400 Bad Request` and JSON-RPC `-32001` (`HeaderMismatch`) — the same shape the existing standard-header cross-checks emit. A `null`/absent body value passes regardless of any header (the spec's "server MUST NOT expect the header" rows). `McpServer.registerTool` now warns at registration time when an `x-mcp-header` declaration violates the spec's constraints. The 2025-era serving paths and the low-level `Server` factory shape are unchanged. +SEP-2243 `Mcp-Param-*` server-side validation (protocol revision 2026-07-28). On the modern (2026-07-28) serving path, `createMcpHandler` now validates `Mcp-Param-{Name}` headers against the named tool's `x-mcp-header` declarations and the body `arguments` before dispatch: a missing header for a present body value, a header that decodes to a different value than the body, or an invalid `=?base64?…?=` sentinel is rejected with `400 Bad Request` and JSON-RPC `-32020` (`HeaderMismatch`) — the same shape the existing standard-header cross-checks emit. A `null`/absent body value passes regardless of any header (the spec's "server MUST NOT expect the header" rows). `McpServer.registerTool` now warns at registration time when an `x-mcp-header` declaration violates the spec's constraints. The 2025-era serving paths and the low-level `Server` factory shape are unchanged. diff --git a/.changeset/sep-2243-std-header-server.md b/.changeset/sep-2243-std-header-server.md index dd2cd37967..8e3c250ce9 100644 --- a/.changeset/sep-2243-std-header-server.md +++ b/.changeset/sep-2243-std-header-server.md @@ -2,4 +2,4 @@ '@modelcontextprotocol/server': minor --- -SEP-2243 standard-header server-side validation (protocol revision 2026-07-28). On the modern (2026-07-28) serving path, `createMcpHandler` now enforces the required `Mcp-Method` and `Mcp-Name` standard request headers in addition to the existing `MCP-Protocol-Version` and `Mcp-Method` cross-checks: a modern request without an `Mcp-Method` header, a `tools/call` / `prompts/get` / `resources/read` request without an `Mcp-Name` header, an `Mcp-Name` header carrying an invalid `=?base64?…?=` sentinel, and an `Mcp-Name` header whose (decoded) value disagrees with the body's `params.name` / `params.uri` are all rejected with `400 Bad Request` and JSON-RPC `-32001` (`HeaderMismatch`). The 2025-era serving paths are unchanged. +SEP-2243 standard-header server-side validation (protocol revision 2026-07-28). On the modern (2026-07-28) serving path, `createMcpHandler` now enforces the required `Mcp-Method` and `Mcp-Name` standard request headers in addition to the existing `MCP-Protocol-Version` and `Mcp-Method` cross-checks: a modern request without an `Mcp-Method` header, a `tools/call` / `prompts/get` / `resources/read` request without an `Mcp-Name` header, an `Mcp-Name` header carrying an invalid `=?base64?…?=` sentinel, and an `Mcp-Name` header whose (decoded) value disagrees with the body's `params.name` / `params.uri` are all rejected with `400 Bad Request` and JSON-RPC `-32020` (`HeaderMismatch`). The 2025-era serving paths are unchanged. diff --git a/.changeset/spec-2907-error-code-renumber.md b/.changeset/spec-2907-error-code-renumber.md new file mode 100644 index 0000000000..aeed3f11e2 --- /dev/null +++ b/.changeset/spec-2907-error-code-renumber.md @@ -0,0 +1,7 @@ +--- +'@modelcontextprotocol/core': minor +'@modelcontextprotocol/client': minor +'@modelcontextprotocol/server': minor +--- + +Align the 2026-07-28 protocol error codes to the spec renumber: `HeaderMismatch` is now `-32020` (was `-32001`), `MissingRequiredClientCapability` is now `-32021` (was `-32003`), and `UnsupportedProtocolVersion` is now `-32022` (was `-32004`). These codes are part of the draft 2026-07-28 protocol revision only and have never appeared on a 2025-era wire — the 2025 serving paths and the SDK-conventional `-32001` (`Session not found`) on the stateful Streamable HTTP transport are unchanged. `ProtocolErrorCode.MissingRequiredClientCapability`, `ProtocolErrorCode.UnsupportedProtocolVersion`, the `HEADER_MISMATCH_ERROR_CODE` constant, and the `HEADER_MISMATCH` / `MISSING_REQUIRED_CLIENT_CAPABILITY` / `UNSUPPORTED_PROTOCOL_VERSION` spec-type constants now carry the renumbered values; the `UnsupportedProtocolVersionError` and `MissingRequiredClientCapabilityError` classes (and `ProtocolError.fromError` recognition) follow. The client probe classifier recognizes `-32022` for the corrective continuation and the SEP-2243 one-refresh-on-miss retry triggers on `-32020`. diff --git a/.changeset/spec-anchor-repin-2fb207da.md b/.changeset/spec-anchor-repin-2fb207da.md index b021ff4d77..feaf90002c 100644 --- a/.changeset/spec-anchor-repin-2fb207da.md +++ b/.changeset/spec-anchor-repin-2fb207da.md @@ -8,6 +8,6 @@ Re-pin the 2026-07-28 draft references (spec reference types, vendored schema.js - `notifications/elicitation/complete` is no longer part of the 2026-07-28 wire registry (the draft removed the notification together with `elicitationId` on URL-mode elicitation). On connections negotiated at 2026-07-28, sending it — including via `Server.createElicitationCompletionNotifier()` — now fails locally with `SdkErrorCode.MethodNotSupportedByProtocolVersion`, and inbound copies are dropped as unknown notifications. Both remain fully supported on 2025-11-25. - `notifications/cancelled` on 2026-era connections now parses with a revision-exact schema that requires `requestId` (the draft made it required); the notification `_meta` shape types the `io.modelcontextprotocol/subscriptionId` key. 2025-era parsing is unchanged. -- The error code `-32001` emitted for HTTP header/body mismatches is now defined by the draft schema (`HEADER_MISMATCH`); the emitted behavior is unchanged (documentation only). +- The error code `-32020` emitted for HTTP header/body mismatches is now defined by the draft schema (`HEADER_MISMATCH`); the emitted behavior is unchanged (documentation only). No public API surface changes; the regenerated reference artifacts are internal/test-only. diff --git a/.changeset/spec-reference-types-2026-07-28.md b/.changeset/spec-reference-types-2026-07-28.md index df0101e05f..36f0a1f677 100644 --- a/.changeset/spec-reference-types-2026-07-28.md +++ b/.changeset/spec-reference-types-2026-07-28.md @@ -3,4 +3,4 @@ '@modelcontextprotocol/codemod': patch --- -Add per-revision spec reference types (2025-11-25 and 2026-07-28) with split comparison tests, and the 2026-07-28 wire contract surface: request-meta key constants, `RequestMetaEnvelopeSchema`, `server/discover` shapes, the typed `-32004` error, the `-32003` code constant, and a `resultType` passthrough on the base result. Types and constants only — no behavior changes. +Add per-revision spec reference types (2025-11-25 and 2026-07-28) with split comparison tests, and the 2026-07-28 wire contract surface: request-meta key constants, `RequestMetaEnvelopeSchema`, `server/discover` shapes, the typed `-32022` error, the `-32021` code constant, and a `resultType` passthrough on the base result. Types and constants only — no behavior changes. diff --git a/docs/client.md b/docs/client.md index 92f39a78cd..377644ec54 100644 --- a/docs/client.md +++ b/docs/client.md @@ -311,7 +311,7 @@ console.log(result.content); On a 2026-07-28 connection over Streamable HTTP, `callTool()` mirrors any argument whose `inputSchema` property carries an `x-mcp-header` annotation into an `Mcp-Param-{Name}` HTTP request header so intermediaries can route on it without parsing the body. The mirrored headers are built from the most recent `listTools()` result; if you already hold the tool definition (e.g. from configuration), pass it via `CallToolRequestOptions.toolDefinition` so mirroring runs without a prior list. On a cache miss the call is sent without `Mcp-Param-*` headers and, -when a conforming server rejects it with `-32001` (`HeaderMismatch`), `callTool()` refreshes the definition cache once and retries. +when a conforming server rejects it with `-32020` (`HeaderMismatch`), `callTool()` refreshes the definition cache once and retries. On a modern HTTP connection `listTools()` **excludes** tool definitions whose `x-mcp-header` declarations violate the spec's constraints, logging a warning that names the tool and the reason. Browser clients skip mirroring (dynamically named headers cannot be statically allow-listed for credentialed CORS), so calling an `x-mcp-header` tool with a non-null designated argument from a browser against a server that enforces SEP-2243 validation will be rejected — a known limitation. The legacy-era `callTool`/`listTools` paths are unchanged. diff --git a/docs/migration-SKILL.md b/docs/migration-SKILL.md index d67a551b90..2ad1a6347d 100644 --- a/docs/migration-SKILL.md +++ b/docs/migration-SKILL.md @@ -574,6 +574,8 @@ No code changes required; these are wire-behavior notes: longer enable it. Behavior for all currently supported protocol versions is unchanged. - Session-ID mismatch still responds `404 Not Found` with JSON-RPC error code `-32001` (`Session not found`), unchanged from v1. This `-32001` usage is an SDK convention, not a spec-assigned code, and may be re-derived as 2026 protocol revision error handling is adopted — migrated client code should key off the HTTP `404` status, not the `-32001` code. +- The 2026-07-28 draft error codes were renumbered between v2 alphas: `HeaderMismatch` `-32001`→`-32020`, `MissingRequiredClientCapability` `-32003`→`-32021`, `UnsupportedProtocolVersion` `-32004`→`-32022`. No v1.x→v2 impact (these codes never existed in v1); v2-alpha code that + hard-coded the old literals must update — prefer `ProtocolErrorCode.*` / `HEADER_MISMATCH_ERROR_CODE`. ### Server (deprecated accessors and app-factory Origin validation) @@ -595,7 +597,7 @@ New in 2.0 — v1 has no equivalent API. How v1 Streamable HTTP hosting maps ont - An existing sessionful v1 Streamable HTTP setup (a `StreamableHTTPServerTransport` wiring with session IDs) keeps serving 2025 clients by routing in user land in front of a strict entry: `if (await isLegacyRequest(request)) return myExistingLegacyHandler(request); return strictHandler.fetch(request)` where `strictHandler = createMcpHandler(factory, { legacy: 'reject' })`. - `isLegacyRequest(request: Request, parsedBody?: unknown): Promise` from `@modelcontextprotocol/server` is the entry's own classification step. Returns `true` only for requests with no per-request `_meta` envelope claim (claim-less POSTs including `initialize`, - GET/DELETE session operations, all-legacy batches, posted responses, non-JSON bodies). Returns `false` for envelope-claiming requests AND for malformed/incomplete modern claims (the modern path answers those with `-32602`/`-32001`) — route `false` traffic to the modern handler, + GET/DELETE session operations, all-legacy batches, posted responses, non-JSON bodies). Returns `false` for envelope-claiming requests AND for malformed/incomplete modern claims (the modern path answers those with `-32602`/`-32020`) — route `false` traffic to the modern handler, never to a legacy handler. The predicate classifies a clone (the body stays readable); pass the parsed body as the second argument when the stream was already consumed. - `legacyStatelessFallback(factory)` is exported as a standalone fetch-shaped handler producing the same stateless legacy serving as the default. - The handler is web-standards-only (`{ fetch, close, notify, bus }`). On Workers / Bun / Deno, `export default handler` works directly. On Node frameworks (Express, Fastify, plain `node:http`), wrap once with `toNodeHandler(handler, { onerror? })` from diff --git a/docs/migration.md b/docs/migration.md index 89855c0ec2..804d3db82b 100644 --- a/docs/migration.md +++ b/docs/migration.md @@ -942,7 +942,7 @@ The protocol layer enforces the same boundary at runtime: The wire layer is now split into per-revision codecs inside the (private, bundled) core: one codec serves every 2025-era protocol version (2024-10-07 … 2025-11-25) and one serves 2026-07-28. The codec is selected by the negotiated protocol version, which is connection state on the `Client`/`Server` instance: the client stores it when its initialize handshake completes, the server stores it when it answers `initialize`, and instances with no negotiated version default to the 2025 era (with the pre-negotiation lifecycle messages routed by method: `initialize`/`notifications/initialized` are 2025-era vocabulary, `server/discover` is 2026-era vocabulary). An edge classification (`MessageExtraInfo.classification`) no longer switches the era per message — it is validated against the instance era, and a mismatch is rejected as -an entry/routing error (`-32004 Unsupported protocol version` for requests, a drop plus `onerror` for notifications). Methods deleted by a protocol revision are now PHYSICALLY absent from that era's registry: an inbound `tasks/get` on a 2026-era connection gets `-32601` even if a +an entry/routing error (`-32022 Unsupported protocol version` for requests, a drop plus `onerror` for notifications). Methods deleted by a protocol revision are now PHYSICALLY absent from that era's registry: an inbound `tasks/get` on a 2026-era connection gets `-32601` even if a handler is registered, and sending an era-mismatched spec method (for example `server/discover` toward a 2025-era peer, or any `tasks/*` method toward a 2026-era peer) throws a typed local error — `SdkError` with the new code `SdkErrorCode.MethodNotSupportedByProtocolVersion` — before anything reaches the transport. @@ -1030,7 +1030,7 @@ versionNegotiation: { } ``` -`maxRetries` governs timeout re-sends only (the spec-mandated `-32004` corrective continuation — select-and-continue with a mutual version — is a separate negotiation step and is never counted against it). Negotiation can also be configured pre-connect on an already-constructed +`maxRetries` governs timeout re-sends only (the spec-mandated `-32022` corrective continuation — select-and-continue with a mutual version — is a separate negotiation step and is never counted against it). Negotiation can also be configured pre-connect on an already-constructed instance via `client.setVersionNegotiation(options)` (equivalent to the constructor option; throws after connecting). Once a modern era is negotiated, the client **automatically attaches the per-request `_meta` envelope** (the reserved protocol-version / client-info / client-capabilities keys) to every outgoing request and notification — you never set it by hand. Any `_meta` keys you pass in a @@ -1069,7 +1069,7 @@ How the `legacy` option behaves: - **omitted / `legacy: 'stateless'`** (the default) — 2025-era (non-envelope) traffic is served per request through the established stateless idiom: a fresh instance from the same factory and a streamable HTTP transport constructed with only `sessionIdGenerator: undefined`. Because this serving is per-request and stateless, GET and DELETE (2025 session operations) are answered `405` / `Method not allowed.`, exactly like the canonical stateless example. The exported `legacyStatelessFallback(factory)` is the same serving as a standalone fetch-shaped handler for hand-wired compositions. -- **`legacy: 'reject'`** — modern-only strict. 2026-07-28 (per-request `_meta` envelope) requests are served; 2025-era requests are rejected with `-32004` naming the supported revisions, and 2025-era notifications are acknowledged with `202` and dropped. **There is no 2025 +- **`legacy: 'reject'`** — modern-only strict. 2026-07-28 (per-request `_meta` envelope) requests are served; 2025-era requests are rejected with `-32022` naming the supported revisions, and 2025-era notifications are acknowledged with `202` and dropped. **There is no 2025 serving in this mode.** > **If you have an existing sessionful 1.x Streamable HTTP setup** (a `StreamableHTTPServerTransport` wiring with session IDs that your deployed 2025-era clients depend on), keep that handler serving 2025 traffic and route it in front of a strict (`legacy: 'reject'`) entry with @@ -1106,7 +1106,7 @@ passed around (`const { fetch } = handler`). ### `Mcp-Param-*` request-metadata headers (SEP-2243, 2026-07-28 draft) On a 2026-07-28 connection over Streamable HTTP, `Client.callTool()` mirrors tool arguments designated with `x-mcp-header` in the tool's `inputSchema` into `Mcp-Param-{Name}` HTTP request headers (Base64-sentinel-encoded where needed) so HTTP intermediaries can route on them -without parsing the body, and `createMcpHandler` rejects a `tools/call` whose `Mcp-Param-*` headers are missing for a present body value, malformed, or disagree with the body — `400 Bad Request` with JSON-RPC `-32001` (`HeaderMismatch`). The legacy-era serving paths and the +without parsing the body, and `createMcpHandler` rejects a `tools/call` whose `Mcp-Param-*` headers are missing for a present body value, malformed, or disagree with the body — `400 Bad Request` with JSON-RPC `-32020` (`HeaderMismatch`). The legacy-era serving paths and the client's legacy-era `callTool`/`listTools` are unchanged. Two additive options support this: `CallToolRequestOptions.toolDefinition` (pass the tool definition directly so mirroring runs without a prior `tools/list`) and `TransportSendOptions.headers` (per-request HTTP headers; the Streamable HTTP transport skips the reserved @@ -1114,7 +1114,7 @@ standard/auth header names so a per-request header cannot override `mcp-protocol tool definitions whose `x-mcp-header` declarations violate the spec's constraints (logging a warning naming the tool and the reason). Browser clients skip mirroring (dynamically named headers cannot be statically allow-listed for credentialed CORS); calling an `x-mcp-header` tool with a non-null designated argument from a browser against a conforming SEP-2243 server is therefore a known limitation. -On the modern path, `createMcpHandler` also validates the SEP-2243 **standard** request-metadata headers against the body and rejects with the same `400` / `-32001` (`HeaderMismatch`) when the `MCP-Protocol-Version` or `Mcp-Method` header disagrees with the body, when the +On the modern path, `createMcpHandler` also validates the SEP-2243 **standard** request-metadata headers against the body and rejects with the same `400` / `-32020` (`HeaderMismatch`) when the `MCP-Protocol-Version` or `Mcp-Method` header disagrees with the body, when the required `Mcp-Method` header is absent, when the required `Mcp-Name` header is absent on a `tools/call` / `prompts/get` / `resources/read` request, and when the (Base64-sentinel-decoded) `Mcp-Name` value disagrees with `params.name` / `params.uri`. These checks only fire on the modern (2026-07-28) serving path — 2025-era traffic is unchanged — and a hand-built modern HTTP request must carry the `Mcp-Method` (and where applicable `Mcp-Name`) header; the SDK client already sends them. @@ -1275,12 +1275,16 @@ try { } ``` -### Typed `-32003` missing-client-capability error +### Typed `-32021` missing-client-capability error -`MissingRequiredClientCapabilityError` is the typed error class for the 2026-07-28 `-32003` protocol error: processing a request requires a capability the client did not declare in the request's `clientCapabilities`. Its `data.requiredCapabilities` lists the missing capabilities, +`MissingRequiredClientCapabilityError` is the typed error class for the 2026-07-28 `-32021` protocol error: processing a request requires a capability the client did not declare in the request's `clientCapabilities`. Its `data.requiredCapabilities` lists the missing capabilities, and `ProtocolError.fromError` recognizes the code/data shape (recognize peers' errors by their code and `error.data`, not by `instanceof`). When the HTTP entry refuses such a request, the response uses HTTP status `400` as the specification requires. The multi-round-trip seam answers with the same error when a handler embeds an input request (for example an elicitation) that the request's declared client capabilities do not cover. +> **Draft-only renumber**: the 2026-07-28 protocol error codes (`HeaderMismatch`, `MissingRequiredClientCapability`, `UnsupportedProtocolVersion`) were renumbered upstream from `-32001`/`-32003`/`-32004` to `-32020`/`-32021`/`-32022` between v2 alpha builds. These codes have only +> ever appeared on the draft 2026-07-28 wire, so there is **no v1.x → v2 migration impact** — but code written against an earlier v2 alpha that hard-coded the old numeric values must update to the new ones (or, preferably, use the exported `ProtocolErrorCode` enum members / +> `HEADER_MISMATCH_ERROR_CODE` constant). + ### Client identity accessors deprecated in favor of per-request context `Server.getClientCapabilities()`, `Server.getClientVersion()` and `Server.getNegotiatedProtocolVersion()` are deprecated (they remain functional). On 2026-07-28 requests the client's identity travels with each request in the validated `_meta` envelope and is available to handlers diff --git a/docs/server.md b/docs/server.md index e9e6ba4c42..47d866aa6e 100644 --- a/docs/server.md +++ b/docs/server.md @@ -103,7 +103,7 @@ Tools let clients invoke actions on your server — they are usually the main wa Register a tool with {@linkcode @modelcontextprotocol/server!server/mcp.McpServer#registerTool | registerTool}. Provide an `inputSchema` (Zod) to validate arguments, and optionally an `outputSchema` for structured return values. > On the 2026-07-28 draft serving path, a tool whose `inputSchema` carries an `x-mcp-header` annotation has that argument mirrored into an `Mcp-Param-{Name}` HTTP request header by conforming clients. `createMcpHandler` validates those headers before dispatch and rejects a -> `tools/call` whose `Mcp-Param-*` headers are missing for a present body value, malformed, or disagree with the body — `400 Bad Request` with JSON-RPC `-32001` (`HeaderMismatch`). `registerTool` warns at registration time when an `x-mcp-header` declaration violates the +> `tools/call` whose `Mcp-Param-*` headers are missing for a present body value, malformed, or disagree with the body — `400 Bad Request` with JSON-RPC `-32020` (`HeaderMismatch`). `registerTool` warns at registration time when an `x-mcp-header` declaration violates the > spec's constraints. The 2025-era serving paths and the low-level `Server` factory shape are unchanged. ```ts source="../examples/guides/serverGuide.examples.ts#registerTool_basic" diff --git a/packages/client/src/client/client.ts b/packages/client/src/client/client.ts index 65e91740e8..a2c8ded790 100644 --- a/packages/client/src/client/client.ts +++ b/packages/client/src/client/client.ts @@ -198,7 +198,7 @@ export type ClientOptions = ProtocolOptions & { * Probe policy lives under `probe: { timeoutMs?, maxRetries? }`; the probe * inherits the client's standard request timeout unless overridden, and * `maxRetries` (default `0`) governs timeout re-sends only — the - * spec-mandated `-32004` corrective continuation is never counted against it. + * spec-mandated `-32022` corrective continuation is never counted against it. * * Once a modern era is negotiated, the client automatically attaches the * per-request `_meta` envelope (the reserved protocol-version / client-info / @@ -366,7 +366,7 @@ export class Client extends Protocol { * keyed by tool name. Replaced on every fresh (cursor-less) list and * accumulated across pages of a paginated list; cleared on reconnect. * Freshness is NOT enforced: a stale schema is recovered through the - * `-32001` → refresh-and-retry path in {@linkcode callTool}. Only + * `-32020` → refresh-and-retry path in {@linkcode callTool}. Only * consumed on a modern connection. */ private _cachedToolDefinitions: Map = new Map(); @@ -1723,7 +1723,7 @@ export class Client extends Protocol { try { result = await this.request({ method: 'tools/call', params }, buildSendOptions()); } catch (error) { - // SEP-2243 one-refresh-on-miss: a `-32001` (HeaderMismatch) + // SEP-2243 one-refresh-on-miss: a `-32020` (HeaderMismatch) // rejection on a modern connection means the server enforced an // `Mcp-Param-*` header we did not (or could not) send. Refresh the // tool-definition cache once and retry with the now-known schema — @@ -1809,7 +1809,7 @@ export class Client extends Protocol { * `toolDefinition` escape hatch wins; otherwise the most recent * `tools/list` result is used as-is. Freshness is NOT enforced — the * cached schema is the best information available regardless of age, and - * a stale schema is recovered through the `-32001` → refresh-and-retry + * a stale schema is recovered through the `-32020` → refresh-and-retry * path in {@linkcode callTool}. On a miss the call proceeds without * `Mcp-Param-*` headers (the spec's "client SHOULD send without custom * headers" guidance) and relies on the same refresh-and-retry recovery. @@ -1826,7 +1826,7 @@ export class Client extends Protocol { * `_cachedToolDefinitions` is rebuilt completely. Only the caller's * `signal`/`timeout` are forwarded to each page request — `tools/call` * options like `toolDefinition`, `headers`, or `onprogress` do not apply - * to `tools/list`. The `-32001` retry path + * to `tools/list`. The `-32020` retry path * in {@linkcode callTool} uses this rather than a bare cursor-less * `listTools()`, which would only fetch page 1 and (because page 1 clears * the merged cache) drop the page-≥2 scans the application accumulated via diff --git a/packages/client/src/client/probeClassifier.ts b/packages/client/src/client/probeClassifier.ts index 25dd025a3b..0c164fdc97 100644 --- a/packages/client/src/client/probeClassifier.ts +++ b/packages/client/src/client/probeClassifier.ts @@ -1,7 +1,7 @@ /** * Probe outcome classifier (pure module): maps the outcome of the connect-time * `server/discover` probe onto one of four verdicts — modern era, the - * spec-mandated `-32004` corrective continuation, legacy fallback (the plain + * spec-mandated `-32022` corrective continuation, legacy fallback (the plain * 2025 `initialize` handshake on the same connection), or a typed connect error. * * The classifier is deliberately conservative: anything it does not positively @@ -57,7 +57,7 @@ export interface ProbeClassifierContext { * Whether a legacy `initialize` fallback is possible — `false` for a * modern-only client and for `pin` mode. Without a fallback, rows carrying * modern evidence but no usable version overlap — a `DiscoverResult` with - * no overlapping version, or a `-32004` whose `data.supported` lists only + * no overlapping version, or a `-32022` whose `data.supported` lists only * legacy revisions — yield a typed `UnsupportedProtocolVersionError` built * from that evidence; the remaining rows that would have fallen back still * classify as `legacy`, and the caller reports them as a typed negotiation @@ -74,7 +74,7 @@ export type ProbeVerdict = /** Definitive modern evidence: select `version` and continue without `initialize`. */ | { kind: 'modern'; version: string; discover: DiscoverResult } /** - * `-32004` with a mutual modern version: re-send the probe at `version`. + * `-32022` with a mutual modern version: re-send the probe at `version`. * Spec-mandated select-and-continue — the caller runs it exactly once and * arms a loop guard on the second rejection, throwing `error`. */ @@ -84,14 +84,16 @@ export type ProbeVerdict = /** Typed connect error — never converted to an era verdict. */ | { kind: 'error'; error: Error }; -/** The `-32004` UnsupportedProtocolVersion protocol error code (negotiation-phase recognition). */ -const UNSUPPORTED_PROTOCOL_VERSION = -32_004; +/** The `-32022` UnsupportedProtocolVersion protocol error code (negotiation-phase recognition). */ +const UNSUPPORTED_PROTOCOL_VERSION = -32_022; /** * Deliberately not probe-recognized in either direction: deployed servers - * overload `-32001` and the error-code ladder for these cells is still being - * derived upstream, so both fall into the conservative legacy default. + * overload `-32001` (the SDK-conventional `Session not found` body on a 2025 + * stateful server), and the spec-assigned `-32020` (`HeaderMismatch`) / + * `-32021` (`MissingRequiredClientCapability`) are not era evidence — all + * fall into the conservative legacy default. */ -const NOT_PROBE_RECOGNIZED = new Set([-32_001, -32_003]); +const NOT_PROBE_RECOGNIZED = new Set([-32_001, -32_020, -32_021]); /** * Classify a single probe outcome. Pure: no I/O, no state — loop-guard and @@ -159,7 +161,7 @@ function classifyRpcError(outcome: { code: number; message: string; data?: unkno if (code === UNSUPPORTED_PROTOCOL_VERSION) { const supported = parseSupportedList(data); if (supported === undefined) { - // -32004 without a valid data.supported list is not actionable modern evidence. + // -32022 without a valid data.supported list is not actionable modern evidence. return { kind: 'legacy' }; } const requested = parseRequested(data) ?? context.requestedVersion; diff --git a/packages/client/src/client/versionNegotiation.ts b/packages/client/src/client/versionNegotiation.ts index 710b4d399b..2e587f9cad 100644 --- a/packages/client/src/client/versionNegotiation.ts +++ b/packages/client/src/client/versionNegotiation.ts @@ -53,7 +53,7 @@ export interface VersionNegotiationProbeOptions { /** * Number of times to re-send the probe after a timeout before reaching the * timeout verdict. Governs timeout re-sends only — the spec-mandated - * `-32004` corrective continuation (select-and-continue with a mutual + * `-32022` corrective continuation (select-and-continue with a mutual * version) is a separate negotiation step and is never counted against * `maxRetries`. * @@ -342,7 +342,7 @@ export async function negotiateEra( const probe = async (): Promise => { let requestedVersion = clientModernVersions[0]!; - // The -32004 corrective continuation runs exactly once (even when the + // The -32022 corrective continuation runs exactly once (even when the // mutual version equals the just-rejected one); the loop guard arms on // the second rejection. let correctiveUsed = false; diff --git a/packages/client/test/client/mcpParamMirroring.test.ts b/packages/client/test/client/mcpParamMirroring.test.ts index e2970a1c5d..ac32b400e3 100644 --- a/packages/client/test/client/mcpParamMirroring.test.ts +++ b/packages/client/test/client/mcpParamMirroring.test.ts @@ -5,7 +5,7 @@ * `Mcp-Param-*` header construction from cached definitions and the * `toolDefinition` escape hatch; era-parity (legacy `callTool` byte-untouched); * stdio MAY-ignore (no headers on a single-channel transport); the - * one-refresh-on-`-32001` retry. + * one-refresh-on-`-32020` retry. */ import type { JSONRPCMessage, JSONRPCRequest, Tool, TransportSendOptions } from '@modelcontextprotocol/core'; import { encodeMcpParamValue, HEADER_MISMATCH_ERROR_CODE, InMemoryTransport, PROTOCOL_VERSION_META_KEY } from '@modelcontextprotocol/core'; @@ -134,13 +134,13 @@ describe('SEP-2243 Mcp-Param-* mirroring (modern era)', () => { expect(callHeaders[0]).toEqual({ 'Mcp-Param-Region': 'eu' }); }); - it('callTool() refreshes once and retries on a -32001 (HeaderMismatch) rejection', async () => { + it('callTool() refreshes once and retries on a -32020 (HeaderMismatch) rejection', async () => { const { clientTx, callHeaders, listCount } = await scriptedModernServer([REGION_TOOL], /* rejectFirstCall */ true); const client = modernClient(); await client.connect(clientTx); // No prior listTools — first send carries no param headers, server - // rejects -32001, client refreshes and retries with the headers. + // rejects -32020, client refreshes and retries with the headers. const result = await client.callTool({ name: 'route', arguments: { region: 'ap' } }); expect(result.content?.[0]).toEqual({ type: 'text', text: 'ok' }); expect(listCount()).toBe(1); @@ -202,9 +202,9 @@ describe('SEP-2243 Mcp-Param-* mirroring (modern era)', () => { expect(callHeaders[0]).toEqual({ 'Mcp-Param-Region': 'us-west1' }); }); - it('-32001 recovery refresh paginates: a page-2 x-mcp-header tool is recovered and page-2 scans are not wiped', async () => { + it('-32020 recovery refresh paginates: a page-2 x-mcp-header tool is recovered and page-2 scans are not wiped', async () => { // Page 1: `echo` (no declarations). Page 2: `route` (x-mcp-header on - // page ≥ 2). The first call is rejected -32001; the internal refresh + // page ≥ 2). The first call is rejected -32020; the internal refresh // must walk BOTH pages so the retry carries `Mcp-Param-Region` and the // application's page-2 scan is not lost. const PAGE1_TOOL: Tool = { name: 'echo', inputSchema: { type: 'object', properties: {} } }; diff --git a/packages/client/test/client/probeClassifier.test.ts b/packages/client/test/client/probeClassifier.test.ts index f442f65fb0..2991acd3d0 100644 --- a/packages/client/test/client/probeClassifier.test.ts +++ b/packages/client/test/client/probeClassifier.test.ts @@ -80,22 +80,22 @@ describe('row: DiscoverResult with NO overlap → initialize on the same connect }); }); -describe('row: -32004 + valid data.supported with a mutual modern version → select-and-continue, MUST NOT fall back', () => { - test('in-band -32004 yields a corrective verdict (never legacy)', () => { +describe('row: -32022 + valid data.supported with a mutual modern version → select-and-continue, MUST NOT fall back', () => { + test('in-band -32022 yields a corrective verdict (never legacy)', () => { const verdict = classify({ kind: 'rpc-error', - code: -32_004, + code: -32_022, message: 'Unsupported protocol version', data: { supported: [MODERN], requested: '2027-01-01' } }); expect(verdict).toMatchObject({ kind: 'corrective', version: MODERN }); }); - test('HTTP 400-bodied -32004 yields the same corrective verdict', () => { + test('HTTP 400-bodied -32022 yields the same corrective verdict', () => { const verdict = classify({ kind: 'http-error', status: 400, - body: httpErrorBody(-32_004, 'Unsupported protocol version', { supported: [MODERN], requested: MODERN }) + body: httpErrorBody(-32_022, 'Unsupported protocol version', { supported: [MODERN], requested: MODERN }) }); expect(verdict).toMatchObject({ kind: 'corrective', version: MODERN }); }); @@ -103,7 +103,7 @@ describe('row: -32004 + valid data.supported with a mutual modern version → se test('corrective even when the mutual version equals the just-rejected one (T2/A6 — caller runs it exactly once)', () => { const verdict = classify({ kind: 'rpc-error', - code: -32_004, + code: -32_022, message: 'Unsupported protocol version', data: { supported: [MODERN], requested: MODERN } }); @@ -114,11 +114,11 @@ describe('row: -32004 + valid data.supported with a mutual modern version → se }); }); -describe('row: -32004 with a disjoint-but-modern list → typed error, never initialize', () => { +describe('row: -32022 with a disjoint-but-modern list → typed error, never initialize', () => { test('no mutual modern version but the list is modern', () => { const verdict = classify({ kind: 'rpc-error', - code: -32_004, + code: -32_022, message: 'Unsupported protocol version', data: { supported: ['2027-12-31'], requested: MODERN } }); @@ -130,11 +130,11 @@ describe('row: -32004 with a disjoint-but-modern list → typed error, never ini }); }); -describe('row: -32004 with a legacy-only list → initialize; modern-only client → typed error carrying data.supported', () => { +describe('row: -32022 with a legacy-only list → initialize; modern-only client → typed error carrying data.supported', () => { test('legacy-only list with fallback available → legacy', () => { const verdict = classify({ kind: 'rpc-error', - code: -32_004, + code: -32_022, message: 'Unsupported protocol version', data: { supported: [LEGACY, '2025-06-18'] } }); @@ -143,7 +143,7 @@ describe('row: -32004 with a legacy-only list → initialize; modern-only client test('legacy-only list, modern-only client → typed error carrying data.supported', () => { const verdict = classify( - { kind: 'rpc-error', code: -32_004, message: 'Unsupported protocol version', data: { supported: [LEGACY] } }, + { kind: 'rpc-error', code: -32_022, message: 'Unsupported protocol version', data: { supported: [LEGACY] } }, { fallbackAvailable: false } ); expect(verdict.kind).toBe('error'); @@ -153,11 +153,11 @@ describe('row: -32004 with a legacy-only list → initialize; modern-only client } }); - test('-32004 with malformed data (no valid supported list) → conservative legacy', () => { - expect(classify({ kind: 'rpc-error', code: -32_004, message: 'nope', data: { supported: 'not-a-list' } })).toEqual({ + test('-32022 with malformed data (no valid supported list) → conservative legacy', () => { + expect(classify({ kind: 'rpc-error', code: -32_022, message: 'nope', data: { supported: 'not-a-list' } })).toEqual({ kind: 'legacy' }); - expect(classify({ kind: 'rpc-error', code: -32_004, message: 'nope' })).toEqual({ kind: 'legacy' }); + expect(classify({ kind: 'rpc-error', code: -32_022, message: 'nope' })).toEqual({ kind: 'legacy' }); }); }); @@ -233,16 +233,23 @@ describe('row: plain-text/unparseable 400, code 0, empty body, 406, any unrecogn }); }); -describe('row: -32001 / -32003 are NEVER probe-recognized → fall into unrecognized → legacy', () => { - test('-32001 (session-404 overload on deployed servers; the spec-assigned HeaderMismatch code is still never probe evidence)', () => { +describe('row: -32001 / -32020 / -32021 are NEVER probe-recognized → fall into unrecognized → legacy', () => { + test('-32001 (session-404 overload on deployed servers — the SDK-conventional code, never probe evidence)', () => { expect(classify({ kind: 'rpc-error', code: -32_001, message: 'Session not found' })).toEqual({ kind: 'legacy' }); expect(classify({ kind: 'http-error', status: 404, body: httpErrorBody(-32_001, 'Session not found') })).toEqual({ kind: 'legacy' }); }); - test('-32003 with data is NOT modern evidence', () => { - expect(classify({ kind: 'rpc-error', code: -32_003, message: 'Capability required', data: { capability: 'sampling' } })).toEqual({ + test('-32020 (the spec-assigned HeaderMismatch code is still never probe evidence)', () => { + expect(classify({ kind: 'rpc-error', code: -32_020, message: 'Header mismatch' })).toEqual({ kind: 'legacy' }); + expect(classify({ kind: 'http-error', status: 400, body: httpErrorBody(-32_020, 'Header mismatch') })).toEqual({ + kind: 'legacy' + }); + }); + + test('-32021 with data is NOT modern evidence', () => { + expect(classify({ kind: 'rpc-error', code: -32_021, message: 'Capability required', data: { capability: 'sampling' } })).toEqual({ kind: 'legacy' }); }); diff --git a/packages/client/test/client/probeFixtureCorpus.test.ts b/packages/client/test/client/probeFixtureCorpus.test.ts index 2d4c8a16f5..bb02c76fa9 100644 --- a/packages/client/test/client/probeFixtureCorpus.test.ts +++ b/packages/client/test/client/probeFixtureCorpus.test.ts @@ -118,25 +118,25 @@ const CORPUS: CorpusRow[] = [ expected: 'legacy' }, { - name: 'recognizer: -32004 with a structured supported list naming a mutual modern version → corrective continuation', + name: 'recognizer: -32022 with a structured supported list naming a mutual modern version → corrective continuation', outcome: { kind: 'rpc-error', - code: -32_004, + code: -32_022, message: 'Unsupported protocol version', data: { supported: [MODERN, LATEST_PROTOCOL_VERSION], requested: '2027-01-01' } }, expected: 'corrective' }, { - name: 'recognizer: -32004 without a parsable data.supported list is not actionable modern evidence → legacy', - outcome: { kind: 'rpc-error', code: -32_004, message: 'Unsupported protocol version' }, + name: 'recognizer: -32022 without a parsable data.supported list is not actionable modern evidence → legacy', + outcome: { kind: 'rpc-error', code: -32_022, message: 'Unsupported protocol version' }, expected: 'legacy' }, { - name: 'recognizer: -32004 with a legacy-only supported list is a definitive legacy signal → legacy', + name: 'recognizer: -32022 with a legacy-only supported list is a definitive legacy signal → legacy', outcome: { kind: 'rpc-error', - code: -32_004, + code: -32_022, message: 'Unsupported protocol version', data: { supported: [LATEST_PROTOCOL_VERSION], requested: MODERN } }, diff --git a/packages/client/test/client/versionNegotiation.test.ts b/packages/client/test/client/versionNegotiation.test.ts index 9187fa141b..b3f9d8df74 100644 --- a/packages/client/test/client/versionNegotiation.test.ts +++ b/packages/client/test/client/versionNegotiation.test.ts @@ -438,11 +438,11 @@ describe('probe timeout policy (transport-aware)', () => { }); /* ------------------------------------------------------------------------- * - * -32004 corrective continuation — exactly once; loop guard on second + * -32022 corrective continuation — exactly once; loop guard on second * rejection. * ------------------------------------------------------------------------- */ -describe('-32004 corrective continuation', () => { +describe('-32022 corrective continuation', () => { test('select-and-continue runs exactly once, even when the mutual version equals the just-rejected one', async () => { let discoverCalls = 0; const script: Script = (message, t) => { @@ -455,7 +455,7 @@ describe('-32004 corrective continuation', () => { jsonrpc: '2.0', id: message.id, error: { - code: -32_004, + code: -32_022, message: 'Unsupported protocol version', data: { supported: [MODERN], requested: MODERN } } @@ -486,7 +486,7 @@ describe('-32004 corrective continuation', () => { t.reply({ jsonrpc: '2.0', id: message.id, - error: { code: -32_004, message: 'Unsupported protocol version', data: { supported: [MODERN], requested: MODERN } } + error: { code: -32_022, message: 'Unsupported protocol version', data: { supported: [MODERN], requested: MODERN } } }); }; @@ -498,13 +498,13 @@ describe('-32004 corrective continuation', () => { expect(transport.sent.some(m => 'method' in m && m.method === 'initialize')).toBe(false); }); - test('-32004 with a disjoint-but-modern list: typed error, never initialize', async () => { + test('-32022 with a disjoint-but-modern list: typed error, never initialize', async () => { const script: Script = (message, t) => { if (!isJSONRPCRequest(message)) return; t.reply({ jsonrpc: '2.0', id: message.id, - error: { code: -32_004, message: 'Unsupported protocol version', data: { supported: ['2027-12-31'] } } + error: { code: -32_022, message: 'Unsupported protocol version', data: { supported: ['2027-12-31'] } } }); }; @@ -515,14 +515,14 @@ describe('-32004 corrective continuation', () => { expect(transport.sent.some(m => 'method' in m && m.method === 'initialize')).toBe(false); }); - test('-32004 with a legacy-only list: definitive legacy signal, initialize on the same connection', async () => { + test('-32022 with a legacy-only list: definitive legacy signal, initialize on the same connection', async () => { const script: Script = (message, t) => { if (!isJSONRPCRequest(message)) return; if (message.method === 'server/discover') { t.reply({ jsonrpc: '2.0', id: message.id, - error: { code: -32_004, message: 'Unsupported protocol version', data: { supported: ['2025-11-25'] } } + error: { code: -32_022, message: 'Unsupported protocol version', data: { supported: ['2025-11-25'] } } }); } else { legacyServerScript(message, t); @@ -537,13 +537,13 @@ describe('-32004 corrective continuation', () => { await client.close(); }); - test('modern-only client + legacy-only -32004 list: typed error carrying data.supported', async () => { + test('modern-only client + legacy-only -32022 list: typed error carrying data.supported', async () => { const script: Script = (message, t) => { if (!isJSONRPCRequest(message)) return; t.reply({ jsonrpc: '2.0', id: message.id, - error: { code: -32_004, message: 'Unsupported protocol version', data: { supported: ['2025-11-25'] } } + error: { code: -32_022, message: 'Unsupported protocol version', data: { supported: ['2025-11-25'] } } }); }; diff --git a/packages/core/src/shared/clientCapabilityRequirements.ts b/packages/core/src/shared/clientCapabilityRequirements.ts index 4f8fa65619..59b3d5086f 100644 --- a/packages/core/src/shared/clientCapabilityRequirements.ts +++ b/packages/core/src/shared/clientCapabilityRequirements.ts @@ -6,7 +6,7 @@ * request (`io.modelcontextprotocol/clientCapabilities`), and a server MUST * NOT rely on capabilities the client did not declare: when processing a * request requires an undeclared capability, the server answers - * `MissingRequiredClientCapabilityError` (`-32003`) with + * `MissingRequiredClientCapabilityError` (`-32021`) with * `data.requiredCapabilities` listing what is missing — HTTP status `400` on * HTTP transports. * @@ -112,7 +112,7 @@ export function requiredClientCapabilitiesForInputRequest(entry: { * declare. Returns `undefined` when every required capability is declared; * otherwise returns an object in the `ClientCapabilities` shape containing * exactly the missing capabilities (suitable for - * `data.requiredCapabilities` on the `-32003` error). + * `data.requiredCapabilities` on the `-32021` error). * * A capability counts as declared when its top-level key is present on the * declared capabilities; when the requirement names nested members (for diff --git a/packages/core/src/shared/inboundClassification.ts b/packages/core/src/shared/inboundClassification.ts index 63321bbcaf..f066753731 100644 --- a/packages/core/src/shared/inboundClassification.ts +++ b/packages/core/src/shared/inboundClassification.ts @@ -31,7 +31,7 @@ * posture, not a spec requirement: the spec leaves header rules for posted * notifications undefined (core client notifications do not occur over * Streamable HTTP); applying the request rules symmetrically is what an - * ecosystem custom-notification POST expects, and the −32001 cells stay + * ecosystem custom-notification POST expects, and the −32020 cells stay * passing for them. * - `GET`/`DELETE` (and any other non-`POST` method) are body-less 2025-era * session operations: the modern era is `POST`-only, so they are routed to @@ -52,7 +52,7 @@ * * - A header/body cross-check mismatch (the `MCP-Protocol-Version` header * disagreeing with the body, or the `Mcp-Method` header disagreeing with the - * body method) is rejected with `-32001` (`HeaderMismatch`) on HTTP 400. + * body method) is rejected with `-32020` (`HeaderMismatch`) on HTTP 400. * - A request whose protocol-version header names a modern revision but whose * body carries no `_meta` envelope claim — including an envelope present but * missing the required protocol-version key — is rejected with `-32602` @@ -208,13 +208,13 @@ export type InboundClassificationOutcome = InboundLegacyRoute | InboundModernRou * with the body's classification), and the `Mcp-Method` header disagreeing * with the body method. * - * `-32001` is the draft schema's `HEADER_MISMATCH` constant (the SEP-2243 + * `-32020` is the draft schema's `HEADER_MISMATCH` constant (the SEP-2243 * `HeaderMismatch` code; the spec requires HTTP 400 for it), as also asserted * by the published conformance suite for header-validation failures. It has no * {@linkcode ProtocolErrorCode} member because it is not part of the 2025-era * wire vocabulary; the validation ladder is its only emitter. */ -export const HEADER_MISMATCH_ERROR_CODE = -32_001; +export const HEADER_MISMATCH_ERROR_CODE = -32_020; /* ------------------------------------------------------------------------ * * The validation ladder as data @@ -281,7 +281,7 @@ export const INBOUND_VALIDATION_LADDER: readonly InboundValidationRungDescriptor conformance: ['server-stateless', 'http-header-validation', 'http-custom-header-server-validation'], rationale: 'Body-primary era classification with the protocol-version header as a cross-check; a header/body disagreement is rejected ' + - 'with -32001 (HeaderMismatch), and an envelope-less request on a modern-only endpoint is answered with the ' + + 'with -32020 (HeaderMismatch), and an envelope-less request on a modern-only endpoint is answered with the ' + 'unsupported-protocol-version error naming the supported revisions.' }, { @@ -351,7 +351,7 @@ export const INBOUND_VALIDATION_LADDER: readonly InboundValidationRungDescriptor rationale: 'SEP-2243 `Mcp-Param-*` headers are validated against the named tool’s `x-mcp-header` declarations and the body ' + '`arguments` after the tool registry is known and before dispatch reaches the handler; a missing/disagreeing/malformed ' + - 'header is rejected 400 / -32001 with the same shape as the standard-header cross-checks.' + 'header is rejected 400 / -32020 with the same shape as the standard-header cross-checks.' } ]; @@ -449,7 +449,7 @@ export const MCP_NAME_HEADER_SOURCE: Readonly> = * entry on a modern-classified request immediately after * {@linkcode classifyInboundRequest} returns a modern route. * - * Returns the `-32001` (`HeaderMismatch`) ladder rejection (HTTP `400`, + * Returns the `-32020` (`HeaderMismatch`) ladder rejection (HTTP `400`, * `standard-header-validation` rung — the same shape * {@linkcode classifyInboundRequest} already emits on the edge * `era-classification` rung for the `MCP-Protocol-Version` and diff --git a/packages/core/src/shared/mcpParamHeaders.ts b/packages/core/src/shared/mcpParamHeaders.ts index 9e60ec5be4..9931f07709 100644 --- a/packages/core/src/shared/mcpParamHeaders.ts +++ b/packages/core/src/shared/mcpParamHeaders.ts @@ -10,13 +10,13 @@ * * The standard-header half (`MCP-Protocol-Version`, `Mcp-Method`, `Mcp-Name`) * lives with the inbound classifier — this module is the custom-header half - * only, and it consumes the same `-32001` (`HeaderMismatch`) emission shape the + * only, and it consumes the same `-32020` (`HeaderMismatch`) emission shape the * classifier established for header/body cross-check failures. * * Spec text at the implementation's spec pin: * - draft/basic/transports/streamable-http.mdx § "Custom Headers from Tool Parameters" * (constraints, value encoding, the 5-step client algorithm, the - * server-behavior table, the `400` + `-32001` rejection) + * server-behavior table, the `400` + `-32020` rejection) * - draft/server/tools.mdx § "x-mcp-header" (the schema-extension property and * its constraints) */ @@ -272,7 +272,7 @@ export function buildMcpParamHeaders( * `42.0` and `42` are equal); everything else is compared as decoded strings. * * Returns `undefined` when every check passes, or an - * {@linkcode InboundLadderRejection} carrying the same `-32001` + * {@linkcode InboundLadderRejection} carrying the same `-32020` * (`HeaderMismatch`) shape the inbound classifier emits for the * standard-header cross-checks — `400 Bad Request` with the disagreeing pair * in `data.mismatch`. @@ -336,7 +336,7 @@ export function validateMcpParamHeaders( } /** - * Build the `-32001` (`HeaderMismatch`) rejection for an `Mcp-Param-*` + * Build the `-32020` (`HeaderMismatch`) rejection for an `Mcp-Param-*` * disagreement. Same shape as the inbound classifier's standard-header * cross-check mismatch (HTTP `400`, `data.mismatch` naming the disagreeing * pair, `settled: true`); only the rung differs because this check runs at the diff --git a/packages/core/src/shared/protocol.ts b/packages/core/src/shared/protocol.ts index a8e96bb8ae..57ba650ac2 100644 --- a/packages/core/src/shared/protocol.ts +++ b/packages/core/src/shared/protocol.ts @@ -887,7 +887,7 @@ export abstract class Protocol { // Edge→instance handoff check: a classification that disagrees with // the instance era means the entry routed another era's traffic onto // this instance. That is a routing error: answer with the typed era - // error (−32004 Unsupported protocol version) and surface it out of + // error (−32022 Unsupported protocol version) and surface it out of // band — never serve the request on a guessed era. if (extra?.classification !== undefined) { const classified = classifiedWireEra(extra.classification); diff --git a/packages/core/src/types/enums.ts b/packages/core/src/types/enums.ts index af7314ed38..be4649e8f0 100644 --- a/packages/core/src/types/enums.ts +++ b/packages/core/src/types/enums.ts @@ -27,11 +27,11 @@ export enum ProtocolErrorCode { * Processing the request requires a capability the client did not declare * in the request's `clientCapabilities` (protocol revision 2026-07-28). */ - MissingRequiredClientCapability = -32_003, + MissingRequiredClientCapability = -32_021, /** * The request's protocol version is unknown to the server or unsupported * by it (protocol revision 2026-07-28). */ - UnsupportedProtocolVersion = -32_004, + UnsupportedProtocolVersion = -32_022, UrlElicitationRequired = -32_042 } diff --git a/packages/core/src/types/errors.ts b/packages/core/src/types/errors.ts index b30c386573..468b3269e0 100644 --- a/packages/core/src/types/errors.ts +++ b/packages/core/src/types/errors.ts @@ -112,7 +112,7 @@ export class UrlElicitationRequiredError extends ProtocolError { } /** - * Error type for the `-32004` UnsupportedProtocolVersion protocol error (protocol + * Error type for the `-32022` UnsupportedProtocolVersion protocol error (protocol * revision 2026-07-28): the request's protocol version is unknown to the server or * unsupported by it. * @@ -141,7 +141,7 @@ export class UnsupportedProtocolVersionError extends ProtocolError { } /** - * Error type for the `-32003` MissingRequiredClientCapability protocol error + * Error type for the `-32021` MissingRequiredClientCapability protocol error * (protocol revision 2026-07-28): processing the request requires a capability * the client did not declare in the request's `clientCapabilities`. * diff --git a/packages/core/src/types/spec.types.2026-07-28.ts b/packages/core/src/types/spec.types.2026-07-28.ts index bf5ad3e095..198e32a39c 100644 --- a/packages/core/src/types/spec.types.2026-07-28.ts +++ b/packages/core/src/types/spec.types.2026-07-28.ts @@ -321,7 +321,7 @@ export interface InvalidRequestError extends Error { * * In MCP, a server returns this error when a client invokes a method the server does not implement — either a genuinely unknown method, or one gated behind a server capability the server did not advertise (e.g., calling `prompts/list` when the `prompts` capability was not advertised). * - * A request that requires a client capability the client did not declare is signalled instead by {@link MissingRequiredClientCapabilityError} (`-32003`). + * A request that requires a client capability the client did not declare is signalled instead by {@link MissingRequiredClientCapabilityError} (`-32021`). * * @see {@link https://www.jsonrpc.org/specification#error_object | JSON-RPC 2.0 Error Object} * @@ -387,7 +387,7 @@ export interface InternalError extends Error { * * @category Errors */ -export const HEADER_MISMATCH = -32001; +export const HEADER_MISMATCH = -32020; /** * Error code returned when a server requires a client capability that was @@ -395,7 +395,7 @@ export const HEADER_MISMATCH = -32001; * * @category Errors */ -export const MISSING_REQUIRED_CLIENT_CAPABILITY = -32003; +export const MISSING_REQUIRED_CLIENT_CAPABILITY = -32021; /** * Error code returned when the request's protocol version is not supported @@ -403,7 +403,7 @@ export const MISSING_REQUIRED_CLIENT_CAPABILITY = -32003; * * @category Errors */ -export const UNSUPPORTED_PROTOCOL_VERSION = -32004; +export const UNSUPPORTED_PROTOCOL_VERSION = -32022; /** * Returned when a server rejects a request because the values in the HTTP diff --git a/packages/core/src/types/types.ts b/packages/core/src/types/types.ts index 6e9fcaf851..f4a0451871 100644 --- a/packages/core/src/types/types.ts +++ b/packages/core/src/types/types.ts @@ -753,7 +753,7 @@ export interface InternalError extends JSONRPCErrorObject { } /** - * Data carried by a `-32003` MissingRequiredClientCapability protocol error + * Data carried by a `-32021` MissingRequiredClientCapability protocol error * (protocol revision 2026-07-28). */ export interface MissingRequiredClientCapabilityErrorData { @@ -766,7 +766,7 @@ export interface MissingRequiredClientCapabilityErrorData { } /** - * Data carried by a `-32004` UnsupportedProtocolVersion protocol error + * Data carried by a `-32022` UnsupportedProtocolVersion protocol error * (protocol revision 2026-07-28). */ export interface UnsupportedProtocolVersionErrorData { diff --git a/packages/core/test/shared/clientCapabilityRequirements.test.ts b/packages/core/test/shared/clientCapabilityRequirements.test.ts index 80758d3916..ff25edc6e2 100644 --- a/packages/core/test/shared/clientCapabilityRequirements.test.ts +++ b/packages/core/test/shared/clientCapabilityRequirements.test.ts @@ -1,5 +1,5 @@ /** - * The shared client-capability requirement helpers behind the `-32003` + * The shared client-capability requirement helpers behind the `-32021` * MissingRequiredClientCapability rule (protocol revision 2026-07-28). * * `missingClientCapabilities` is the single helper shared by the pre-dispatch diff --git a/packages/core/test/shared/errorHttpStatusMatrix.test.ts b/packages/core/test/shared/errorHttpStatusMatrix.test.ts index 7f505daece..fb5344a1bb 100644 --- a/packages/core/test/shared/errorHttpStatusMatrix.test.ts +++ b/packages/core/test/shared/errorHttpStatusMatrix.test.ts @@ -13,7 +13,7 @@ * carries its own HTTP 400 and is the only invalid-params rejection that * maps to 400. * - * The header/body mismatch family is pinned to `-32001` (HeaderMismatch) and + * The header/body mismatch family is pinned to `-32020` (HeaderMismatch) and * the missing-envelope cells to `-32602`, the assignments asserted by the * published conformance suite. * @@ -35,7 +35,7 @@ describe('the status matrix — pinned cells', () => { }, { code: ProtocolErrorCode.UnsupportedProtocolVersion, status: 400, cell: 'unsupported protocol version' }, { code: ProtocolErrorCode.MissingRequiredClientCapability, status: 400, cell: 'missing required client capability' }, - { code: -32_001, status: 400, cell: 'header mismatch family (when emitted by the ladder)' }, + { code: -32_020, status: 400, cell: 'header mismatch family (when emitted by the ladder)' }, { code: ProtocolErrorCode.ParseError, status: 400, cell: 'unparseable request body' }, { code: ProtocolErrorCode.InvalidRequest, status: 400, cell: 'malformed JSON-RPC body / rejected batch' } ]; @@ -76,13 +76,13 @@ describe('the status matrix — pinned cells', () => { Object.keys(LADDER_ERROR_HTTP_STATUS) .map(Number) .sort((a, b) => a - b) - ).toEqual([-32_700, -32_601, -32_600, -32_004, -32_003, -32_001].sort((a, b) => a - b)); + ).toEqual([-32_700, -32_601, -32_600, -32_022, -32_021, -32_020].sort((a, b) => a - b)); }); }); describe('the status matrix — header/body mismatch family', () => { - test('the header/body mismatch family is pinned to -32001 (HeaderMismatch) and maps to HTTP 400', () => { - expect(HEADER_MISMATCH_ERROR_CODE).toBe(-32_001); + test('the header/body mismatch family is pinned to -32020 (HeaderMismatch) and maps to HTTP 400', () => { + expect(HEADER_MISMATCH_ERROR_CODE).toBe(-32_020); expect(LADDER_ERROR_HTTP_STATUS[HEADER_MISMATCH_ERROR_CODE]).toBe(400); expect(httpStatusForErrorCode(HEADER_MISMATCH_ERROR_CODE, 'ladder')).toBe(400); }); diff --git a/packages/core/test/shared/inboundClassification.test.ts b/packages/core/test/shared/inboundClassification.test.ts index d288fd21d8..5108b8e6cf 100644 --- a/packages/core/test/shared/inboundClassification.test.ts +++ b/packages/core/test/shared/inboundClassification.test.ts @@ -5,7 +5,7 @@ * cross-checks, notification routing, element-wise batch classification, and * the modern-only (strict) rejection mapping. * - * The header/body mismatch cells are pinned to `-32001` (HeaderMismatch) and + * The header/body mismatch cells are pinned to `-32020` (HeaderMismatch) and * the missing-envelope / missing-protocol-version cells to `-32602` (invalid * params naming the missing key(s)) — the assignments asserted by the * published conformance suite. @@ -61,9 +61,9 @@ const expectMismatch = (outcome: ReturnType, cell expect(outcome.rung).toBe('era-classification'); expect(outcome.httpStatus).toBe(400); // Pinned: a header/body disagreement is a header-validation failure and - // answers -32001 (HeaderMismatch), per the published conformance suite. + // answers -32020 (HeaderMismatch), per the published conformance suite. expect(outcome.settled).toBe(true); - expect(outcome.code).toBe(-32_001); + expect(outcome.code).toBe(-32_020); }; describe('envelope claim detection (claim = the reserved protocol-version key)', () => { @@ -211,7 +211,7 @@ describe('body-primary era predicate', () => { }); }); -describe('header cross-checks (-32001 HeaderMismatch) and the missing-envelope rejection (-32602)', () => { +describe('header cross-checks (-32020 HeaderMismatch) and the missing-envelope rejection (-32602)', () => { test('a body claim disagreeing with the protocol-version header is a mismatch outcome', () => { const outcome = classifyInboundRequest(post(modernToolsCall(), { protocolVersion: '2025-06-18' })); expectMismatch(outcome, 'header-body-version-mismatch'); @@ -426,7 +426,7 @@ describe('modern-only (strict) rejection mapping', () => { expect(rejectionOutcome).toMatchObject({ cell: 'modern-only-missing-envelope', httpStatus: 400, - code: -32_004, + code: -32_022, settled: true, data: { supported: SUPPORTED } }); @@ -437,12 +437,12 @@ describe('modern-only (strict) rejection mapping', () => { test('an envelope-less initialize names the version it requested', () => { const rejectionOutcome = modernOnlyStrictRejection(legacyRoute(initializeRequest('2025-06-18')), SUPPORTED); - expect(rejectionOutcome).toMatchObject({ code: -32_004, data: { supported: SUPPORTED, requested: '2025-06-18' } }); + expect(rejectionOutcome).toMatchObject({ code: -32_022, data: { supported: SUPPORTED, requested: '2025-06-18' } }); }); test('an envelope-less request echoes the protocol-version header it sent', () => { const rejectionOutcome = modernOnlyStrictRejection(legacyRoute(legacyToolsList(), { protocolVersion: '2025-03-26' }), SUPPORTED); - expect(rejectionOutcome).toMatchObject({ code: -32_004, data: { requested: '2025-03-26' } }); + expect(rejectionOutcome).toMatchObject({ code: -32_022, data: { requested: '2025-03-26' } }); }); test('batch and response POSTs are invalid requests on a modern-only endpoint', () => { diff --git a/packages/core/test/shared/inboundLadderCellSheet.test.ts b/packages/core/test/shared/inboundLadderCellSheet.test.ts index 6713e3bd4b..87c28bec3d 100644 --- a/packages/core/test/shared/inboundLadderCellSheet.test.ts +++ b/packages/core/test/shared/inboundLadderCellSheet.test.ts @@ -6,7 +6,7 @@ * status. The header/body mismatch and missing-envelope cells were originally * parameterized (asserted as candidate-set membership) while their error codes * were under discussion upstream; they are now pinned to the assignments the - * published conformance suite asserts (`-32001` HeaderMismatch for header/body + * published conformance suite asserts (`-32020` HeaderMismatch for header/body * disagreements, `-32602` invalid params naming the missing key(s) for a * missing envelope or missing protocol-version key). If a future published * conformance release changes an assignment, the affected rows are re-derived @@ -203,7 +203,7 @@ const SHEET: readonly SheetRow[] = [ conformance: ['server-stateless'], input: post(bare('tools/list')), strict: true, - reject: { rung: 'era-classification', httpStatus: 400, code: -32_004, settled: true }, + reject: { rung: 'era-classification', httpStatus: 400, code: -32_022, settled: true }, rationale: 'A modern-only endpoint answers envelope-less requests with the unsupported-protocol-version error and its supported list. ' + 'This cell shares its numeric code with the disputed mismatch family but is itself settled.' @@ -216,7 +216,7 @@ const SHEET: readonly SheetRow[] = [ reject: { rung: 'era-classification', httpStatus: 400, - code: -32_004, + code: -32_022, settled: true, data: { supported: [MODERN_REVISION], requested: '2025-06-18' } }, @@ -254,9 +254,9 @@ const SHEET: readonly SheetRow[] = [ cell: 'header-body-version-mismatch', conformance: ['server-stateless', 'http-header-validation', 'http-custom-header-server-validation'], input: post(enveloped('tools/call', { name: 'echo', arguments: {} }), { protocolVersion: '2025-06-18' }), - reject: { rung: 'era-classification', httpStatus: 400, code: -32_001, settled: true }, + reject: { rung: 'era-classification', httpStatus: 400, code: -32_020, settled: true }, rationale: - 'Header/body protocol-version disagreement is a header-validation failure: -32001 (HeaderMismatch) on HTTP 400, as ' + + 'Header/body protocol-version disagreement is a header-validation failure: -32020 (HeaderMismatch) on HTTP 400, as ' + 'asserted by the published conformance suite.' }, { @@ -274,10 +274,10 @@ const SHEET: readonly SheetRow[] = [ input: post(bare('initialize', { protocolVersion: '2025-06-18', capabilities: {}, clientInfo: { name: 'c', version: '1' } }), { protocolVersion: MODERN_REVISION }), - reject: { rung: 'era-classification', httpStatus: 400, code: -32_001, settled: true }, + reject: { rung: 'era-classification', httpStatus: 400, code: -32_020, settled: true }, rationale: 'An envelope-less initialize classifies legacy; a modern header on it is a header/body disagreement and answers the ' + - 'same -32001 (HeaderMismatch) as the rest of the mismatch family.' + 'same -32020 (HeaderMismatch) as the rest of the mismatch family.' }, { cell: 'method-header-mismatch', @@ -286,10 +286,10 @@ const SHEET: readonly SheetRow[] = [ protocolVersion: MODERN_REVISION, mcpMethod: 'tools/list' }), - reject: { rung: 'era-classification', httpStatus: 400, code: -32_001, settled: true }, + reject: { rung: 'era-classification', httpStatus: 400, code: -32_020, settled: true }, rationale: 'The Mcp-Method header must describe the body it accompanies; a disagreement is a header-validation failure and ' + - 'answers -32001 (HeaderMismatch) on HTTP 400.' + 'answers -32020 (HeaderMismatch) on HTTP 400.' }, { cell: 'notification-header-body-version-mismatch', @@ -298,10 +298,10 @@ const SHEET: readonly SheetRow[] = [ { jsonrpc: '2.0', method: 'notifications/progress', params: { _meta: { [PROTOCOL_VERSION_META_KEY]: MODERN_REVISION } } }, { protocolVersion: '2025-06-18' } ), - reject: { rung: 'era-classification', httpStatus: 400, code: -32_001, settled: true }, + reject: { rung: 'era-classification', httpStatus: 400, code: -32_020, settled: true }, rationale: 'A notification body claim disagreeing with the protocol-version header is the same header-validation failure as the ' + - 'request cells above and answers the same -32001 (HeaderMismatch).' + 'request cells above and answers the same -32020 (HeaderMismatch).' }, { cell: 'notification-method-header-mismatch', @@ -310,10 +310,10 @@ const SHEET: readonly SheetRow[] = [ { jsonrpc: '2.0', method: 'notifications/progress', params: { progressToken: 1, progress: 1 } }, { protocolVersion: MODERN_REVISION, mcpMethod: 'notifications/cancelled' } ), - reject: { rung: 'era-classification', httpStatus: 400, code: -32_001, settled: true }, + reject: { rung: 'era-classification', httpStatus: 400, code: -32_020, settled: true }, rationale: 'The Mcp-Method header must describe the notification body it accompanies (validated only when the notification ' + - 'classifies modern); a disagreement answers -32001 (HeaderMismatch).' + 'classifies modern); a disagreement answers -32020 (HeaderMismatch).' }, { cell: 'multi-fault-mismatched-claim-and-malformed-envelope', @@ -407,9 +407,9 @@ describe('HTTP status mapping for ladder-originated errors (origin-keyed)', () = [-32_700]: 400, [-32_601]: 404, [-32_600]: 400, - [-32_004]: 400, - [-32_003]: 400, - [-32_001]: 400 + [-32_022]: 400, + [-32_021]: 400, + [-32_020]: 400 }); }); @@ -419,15 +419,15 @@ describe('HTTP status mapping for ladder-originated errors (origin-keyed)', () = }); test('handler-originated errors stay in-band on HTTP 200, whatever their code', () => { - for (const code of [-32_603, -32_602, -32_601, -32_004, -32_002, -32_000, 1234]) { + for (const code of [-32_603, -32_602, -32_601, -32_022, -32_002, -32_000, 1234]) { expect(httpStatusForErrorCode(code, 'in-band')).toBe(200); } }); test('ladder-originated codes map to their HTTP statuses', () => { expect(httpStatusForErrorCode(-32_601, 'ladder')).toBe(404); - expect(httpStatusForErrorCode(-32_004, 'ladder')).toBe(400); - expect(httpStatusForErrorCode(-32_003, 'ladder')).toBe(400); - expect(httpStatusForErrorCode(-32_001, 'ladder')).toBe(400); + expect(httpStatusForErrorCode(-32_022, 'ladder')).toBe(400); + expect(httpStatusForErrorCode(-32_021, 'ladder')).toBe(400); + expect(httpStatusForErrorCode(-32_020, 'ladder')).toBe(400); }); }); diff --git a/packages/core/test/shared/mcpParamHeaders.test.ts b/packages/core/test/shared/mcpParamHeaders.test.ts index 55963a9691..4f1303854a 100644 --- a/packages/core/test/shared/mcpParamHeaders.test.ts +++ b/packages/core/test/shared/mcpParamHeaders.test.ts @@ -192,12 +192,12 @@ describe('validateMcpParamHeaders — server-behavior table', () => { }); // sep-2243-server-reject-missing-required — globally-untested manifest check, covered here. - test('body has the value but the header is absent → reject 400/-32001', () => { + test('body has the value but the header is absent → reject 400/-32020', () => { const r = validateMcpParamHeaders(DECLS, { region: 'us-west1' }, new Headers()); expect(r).toMatchObject({ kind: 'reject', httpStatus: 400, code: HEADER_MISMATCH_ERROR_CODE, cell: 'param-header-missing' }); }); - test('header present but disagreeing → reject 400/-32001 with the mismatch in data', () => { + test('header present but disagreeing → reject 400/-32020 with the mismatch in data', () => { const r = validateMcpParamHeaders(DECLS, { region: 'us-west1' }, new Headers({ [`${MCP_PARAM_HEADER_PREFIX}Region`]: 'eu' })); expect(r).toMatchObject({ kind: 'reject', @@ -208,7 +208,7 @@ describe('validateMcpParamHeaders — server-behavior table', () => { }); }); - test('invalid Base64 sentinel → reject 400/-32001', () => { + test('invalid Base64 sentinel → reject 400/-32020', () => { const r = validateMcpParamHeaders( DECLS, { region: 'Hello' }, @@ -238,8 +238,8 @@ describe('validateMcpParamHeaders — server-behavior table', () => { }); }); -describe('paramHeaderMismatchRejection — consumes the inbound-classifier −32001 shape verbatim', () => { - test('shape: 400 / -32001 / settled, with data.mismatch and the same message prefix', () => { +describe('paramHeaderMismatchRejection — consumes the inbound-classifier −32020 shape verbatim', () => { + test('shape: 400 / -32020 / settled, with data.mismatch and the same message prefix', () => { const r = paramHeaderMismatchRejection('param-header-mismatch', 'Mcp-Param-Region', 'body says us-west1'); expect(r).toEqual({ kind: 'reject', diff --git a/packages/core/test/shared/protocol.test.ts b/packages/core/test/shared/protocol.test.ts index 1103c24920..dbfc314d53 100644 --- a/packages/core/test/shared/protocol.test.ts +++ b/packages/core/test/shared/protocol.test.ts @@ -1127,7 +1127,7 @@ describe('inbound validation precedence: −32601 outranks envelope −32602', ( }); }); -describe('inbound protocol-version mismatch (−32004): the error data lists every supported version', () => { +describe('inbound protocol-version mismatch (−32022): the error data lists every supported version', () => { const flush = () => new Promise(resolve => setTimeout(resolve, 10)); test('a request classified for a protocol version this connection does not serve is rejected with the full supported list', async () => { @@ -1162,7 +1162,7 @@ describe('inbound protocol-version mismatch (−32004): the error data lists eve message: string; data?: { supported?: string[]; requested?: string }; }; - expect(error.code).toBe(-32004); + expect(error.code).toBe(-32022); expect(error.message).toContain('Unsupported protocol version'); expect(error.data?.supported).toEqual(supportedProtocolVersions); expect(error.data?.requested).toBe('2026-07-28'); diff --git a/packages/core/test/shared/standardHeaderValidation.test.ts b/packages/core/test/shared/standardHeaderValidation.test.ts index 97baadb407..935bd66ad7 100644 --- a/packages/core/test/shared/standardHeaderValidation.test.ts +++ b/packages/core/test/shared/standardHeaderValidation.test.ts @@ -4,7 +4,7 @@ * * Evaluated by the HTTP entry on a modern-classified request immediately * after `classifyInboundRequest` returns a modern route: rejects `400` / - * `-32001` (`HeaderMismatch`) when the required `Mcp-Method` header is + * `-32020` (`HeaderMismatch`) when the required `Mcp-Method` header is * absent, when the required `Mcp-Name` header is absent on a `tools/call` / * `prompts/get` / `resources/read` request, when the `Mcp-Name` header * carries an invalid Base64 sentinel, and when its (decoded) value disagrees @@ -56,7 +56,7 @@ function expectRejection(result: InboundLadderRejection | undefined, cell: strin expect(result?.cell).toBe(cell); expect(result?.rung).toBe('standard-header-validation'); expect(result?.httpStatus).toBe(400); - expect(result?.code).toBe(-32_001); + expect(result?.code).toBe(-32_020); expect(result?.settled).toBe(true); } diff --git a/packages/core/test/spec.types.2026-07-28.test.ts b/packages/core/test/spec.types.2026-07-28.test.ts index f88b8e11f3..ada62d07e0 100644 --- a/packages/core/test/spec.types.2026-07-28.test.ts +++ b/packages/core/test/spec.types.2026-07-28.test.ts @@ -838,8 +838,8 @@ describe('Spec Types (2026-07-28)', () => { it('pins the 2026-07-28 protocol version and the new error codes', () => { expect(LATEST_PROTOCOL_VERSION).toBe('2026-07-28'); - expect(MISSING_REQUIRED_CLIENT_CAPABILITY).toBe(-32003); - expect(UNSUPPORTED_PROTOCOL_VERSION).toBe(-32004); + expect(MISSING_REQUIRED_CLIENT_CAPABILITY).toBe(-32021); + expect(UNSUPPORTED_PROTOCOL_VERSION).toBe(-32022); expect(ProtocolErrorCode.MissingRequiredClientCapability).toBe(MISSING_REQUIRED_CLIENT_CAPABILITY); expect(ProtocolErrorCode.UnsupportedProtocolVersion).toBe(UNSUPPORTED_PROTOCOL_VERSION); }); diff --git a/packages/core/test/types/crossBundleErrorRecognition.test.ts b/packages/core/test/types/crossBundleErrorRecognition.test.ts index 35f69acbae..c6f1377e99 100644 --- a/packages/core/test/types/crossBundleErrorRecognition.test.ts +++ b/packages/core/test/types/crossBundleErrorRecognition.test.ts @@ -38,7 +38,7 @@ class TestProtocol extends Protocol { * looks like to this copy: same name, same fields, different identity. */ class ForeignUnsupportedProtocolVersionError extends Error { - readonly code = -32_004; + readonly code = -32_022; readonly data = { supported: ['2025-11-25'], requested: '2099-01-01' }; constructor() { super('Unsupported protocol version: 2099-01-01'); @@ -47,7 +47,7 @@ class ForeignUnsupportedProtocolVersionError extends Error { } describe('cross-bundle typed-error recognition (data parse, never instanceof)', () => { - test('a -32004 error received over the wire materializes the typed class from code + data', async () => { + test('a -32022 error received over the wire materializes the typed class from code + data', async () => { // Full dispatch round trip: the peer answers with a plain JSON error // body — exactly what crosses a transport (and a bundle) boundary. const [clientTx, serverTx] = InMemoryTransport.createLinkedPair(); @@ -57,7 +57,7 @@ describe('cross-bundle typed-error recognition (data parse, never instanceof)', jsonrpc: '2.0', id: request.id, error: { - code: -32_004, + code: -32_022, message: 'Unsupported protocol version', data: { supported: ['2025-11-25', '2025-06-18'], requested: '2099-01-01' } } @@ -115,12 +115,12 @@ describe('cross-bundle typed-error recognition (data parse, never instanceof)', }); test('structurally invalid data falls back to the generic class — no guess, no throw', () => { - // -32004 with data that does not parse as UnsupportedProtocolVersionErrorData. + // -32022 with data that does not parse as UnsupportedProtocolVersionErrorData. for (const data of [undefined, null, 'nope', { supported: 'not-an-array', requested: '2099-01-01' }, { wrong: 'shape' }]) { - const recognized = ProtocolError.fromError(-32_004, 'unsupported', data); + const recognized = ProtocolError.fromError(-32_022, 'unsupported', data); expect(recognized).toBeInstanceOf(ProtocolError); expect(recognized).not.toBeInstanceOf(UnsupportedProtocolVersionError); - expect(recognized.code).toBe(-32_004); + expect(recognized.code).toBe(-32_022); } // -32042 with data missing the elicitations array. diff --git a/packages/core/test/types/errorSurfacePins.test.ts b/packages/core/test/types/errorSurfacePins.test.ts index a91bcd33f2..0396abf9c9 100644 --- a/packages/core/test/types/errorSurfacePins.test.ts +++ b/packages/core/test/types/errorSurfacePins.test.ts @@ -45,8 +45,8 @@ describe('ProtocolErrorCode', () => { InvalidParams: -32602, InternalError: -32603, ResourceNotFound: -32002, - MissingRequiredClientCapability: -32003, - UnsupportedProtocolVersion: -32004, + MissingRequiredClientCapability: -32021, + UnsupportedProtocolVersion: -32022, UrlElicitationRequired: -32042 }); }); @@ -112,13 +112,13 @@ describe('ProtocolError', () => { expect(urlError).toBeInstanceOf(UrlElicitationRequiredError); expect((urlError as UrlElicitationRequiredError).elicitations).toHaveLength(1); - const versionError = ProtocolError.fromError(-32004, 'unsupported', { supported: ['2025-11-25'], requested: '1999-01-01' }); + const versionError = ProtocolError.fromError(-32022, 'unsupported', { supported: ['2025-11-25'], requested: '1999-01-01' }); expect(versionError).toBeInstanceOf(UnsupportedProtocolVersionError); expect((versionError as UnsupportedProtocolVersionError).supported).toEqual(['2025-11-25']); expect((versionError as UnsupportedProtocolVersionError).requested).toBe('1999-01-01'); // Malformed/missing data falls back to the generic class instead of throwing. - const generic = ProtocolError.fromError(-32004, 'unsupported', { wrong: 'shape' }); + const generic = ProtocolError.fromError(-32022, 'unsupported', { wrong: 'shape' }); expect(generic).toBeInstanceOf(ProtocolError); expect(generic).not.toBeInstanceOf(UnsupportedProtocolVersionError); }); diff --git a/packages/core/test/types/errors.test.ts b/packages/core/test/types/errors.test.ts index b908dfb397..0b04ada841 100644 --- a/packages/core/test/types/errors.test.ts +++ b/packages/core/test/types/errors.test.ts @@ -6,10 +6,10 @@ import { ProtocolError, UnsupportedProtocolVersionError } from '../../src/types/ describe('UnsupportedProtocolVersionError', () => { const data = { supported: ['2025-11-25', '2025-06-18'], requested: '2026-07-28' }; - it('carries code -32004 and the supported/requested data', () => { + it('carries code -32022 and the supported/requested data', () => { const error = new UnsupportedProtocolVersionError(data); expect(error.code).toBe(ProtocolErrorCode.UnsupportedProtocolVersion); - expect(error.code).toBe(-32004); + expect(error.code).toBe(-32022); expect(error.supported).toEqual(['2025-11-25', '2025-06-18']); expect(error.requested).toBe('2026-07-28'); expect(error.data).toEqual(data); @@ -23,7 +23,7 @@ describe('UnsupportedProtocolVersionError', () => { }); it('is materialized by ProtocolError.fromError', () => { - const error = ProtocolError.fromError(-32004, 'Unsupported protocol version: 2026-07-28', data); + const error = ProtocolError.fromError(-32022, 'Unsupported protocol version: 2026-07-28', data); expect(error).toBeInstanceOf(UnsupportedProtocolVersionError); if (error instanceof UnsupportedProtocolVersionError) { expect(error.supported).toEqual(['2025-11-25', '2025-06-18']); @@ -34,10 +34,10 @@ describe('UnsupportedProtocolVersionError', () => { it('falls back to a generic ProtocolError when the data is missing or malformed', () => { for (const malformed of [undefined, {}, { supported: 'not-an-array', requested: '2026-07-28' }, { supported: ['2025-11-25'] }]) { - const error = ProtocolError.fromError(-32004, 'unsupported', malformed); + const error = ProtocolError.fromError(-32022, 'unsupported', malformed); expect(error).toBeInstanceOf(ProtocolError); expect(error).not.toBeInstanceOf(UnsupportedProtocolVersionError); - expect(error.code).toBe(-32004); + expect(error.code).toBe(-32022); expect(error.data).toEqual(malformed); } }); diff --git a/packages/core/test/types/missingClientCapabilityError.test.ts b/packages/core/test/types/missingClientCapabilityError.test.ts index 1d15ad1dae..ce121ff8a9 100644 --- a/packages/core/test/types/missingClientCapabilityError.test.ts +++ b/packages/core/test/types/missingClientCapabilityError.test.ts @@ -1,5 +1,5 @@ /** - * The `-32003` MissingRequiredClientCapability typed error. + * The `-32021` MissingRequiredClientCapability typed error. * * Recognition is data-parse based: a peer (or another bundled copy of the SDK) * is recognized by the error code plus the `data.requiredCapabilities` shape, @@ -11,10 +11,10 @@ import { ProtocolErrorCode } from '../../src/types/enums.js'; import { MissingRequiredClientCapabilityError, ProtocolError } from '../../src/types/errors.js'; describe('MissingRequiredClientCapabilityError', () => { - test('carries the -32003 code and the missing capabilities in data.requiredCapabilities', () => { + test('carries the -32021 code and the missing capabilities in data.requiredCapabilities', () => { const error = new MissingRequiredClientCapabilityError({ requiredCapabilities: { sampling: {}, elicitation: { url: {} } } }); expect(error.code).toBe(ProtocolErrorCode.MissingRequiredClientCapability); - expect(error.code).toBe(-32_003); + expect(error.code).toBe(-32_021); expect(error.requiredCapabilities).toEqual({ sampling: {}, elicitation: { url: {} } }); expect(error.data).toEqual({ requiredCapabilities: { sampling: {}, elicitation: { url: {} } } }); expect(error.message).toContain('sampling'); @@ -30,7 +30,7 @@ describe('MissingRequiredClientCapabilityError', () => { // Simulates an error received from the wire or from a separately // bundled SDK copy: plain code/message/data, no class identity. const wireShape = { - code: -32_003, + code: -32_021, message: 'Missing required client capabilities: sampling', data: { requiredCapabilities: { sampling: {} } } }; @@ -40,14 +40,14 @@ describe('MissingRequiredClientCapabilityError', () => { }); test('fromError falls back to the generic ProtocolError when the data shape does not match', () => { - expect(ProtocolError.fromError(-32_003, 'missing', undefined)).not.toBeInstanceOf(MissingRequiredClientCapabilityError); - expect(ProtocolError.fromError(-32_003, 'missing', { requiredCapabilities: ['sampling'] })).not.toBeInstanceOf( + expect(ProtocolError.fromError(-32_021, 'missing', undefined)).not.toBeInstanceOf(MissingRequiredClientCapabilityError); + expect(ProtocolError.fromError(-32_021, 'missing', { requiredCapabilities: ['sampling'] })).not.toBeInstanceOf( MissingRequiredClientCapabilityError ); - expect(ProtocolError.fromError(-32_003, 'missing', { somethingElse: true })).not.toBeInstanceOf( + expect(ProtocolError.fromError(-32_021, 'missing', { somethingElse: true })).not.toBeInstanceOf( MissingRequiredClientCapabilityError ); - expect(ProtocolError.fromError(-32_003, 'missing', { requiredCapabilities: { sampling: {} } })).toBeInstanceOf( + expect(ProtocolError.fromError(-32_021, 'missing', { requiredCapabilities: { sampling: {} } })).toBeInstanceOf( MissingRequiredClientCapabilityError ); }); @@ -57,7 +57,7 @@ describe('MissingRequiredClientCapabilityError', () => { requiredCapabilities: { sampling: {} } }); const looksLikeMissingCapability = - fromAnotherBundle.code === -32_003 && + fromAnotherBundle.code === -32_021 && typeof (fromAnotherBundle.data as { requiredCapabilities?: unknown } | undefined)?.requiredCapabilities === 'object'; expect(looksLikeMissingCapability).toBe(true); }); diff --git a/packages/core/test/wire/encodeContract.test.ts b/packages/core/test/wire/encodeContract.test.ts index 83c06223b6..16025ecf56 100644 --- a/packages/core/test/wire/encodeContract.test.ts +++ b/packages/core/test/wire/encodeContract.test.ts @@ -209,7 +209,7 @@ describe('the error half of the encode seam — encodeErrorCode', () => { }); test('every other code passes through identically on both eras', () => { - for (const code of [-32_700, -32_600, -32_601, -32_602, -32_603, -32_000, -32_001, -32_003, -32_004, -32_042, -1, 0]) { + for (const code of [-32_700, -32_600, -32_601, -32_602, -32_603, -32_000, -32_020, -32_021, -32_022, -32_042, -1, 0]) { expect(rev2026Codec.encodeErrorCode(code)).toBe(code); expect(rev2025Codec.encodeErrorCode(code)).toBe(code); } diff --git a/packages/core/test/wire/eraGates.test.ts b/packages/core/test/wire/eraGates.test.ts index 8776ee69c0..02fa305469 100644 --- a/packages/core/test/wire/eraGates.test.ts +++ b/packages/core/test/wire/eraGates.test.ts @@ -29,7 +29,7 @@ * `MessageExtraInfo.classification` (INJECTED here; the production * classifier is the entry/edge's job) no longer selects the era per message: * the funnel VALIDATES it against the instance era — a mismatch is an - * entry/routing error (typed −32004 rejection / notification drop, plus + * entry/routing error (typed −32022 rejection / notification drop, plus * onerror), and unclassified traffic on a legacy instance behaves exactly as * before the codec split (the B-2 rule). */ @@ -377,7 +377,7 @@ describe('encode-side deleted-field strictness (Q1-SD3 iii)', () => { }); describe('the edge→instance handoff — classification is validated, never an era switch', () => { - test('a modern-classified request on a legacy-era instance is an entry/routing error: typed −32004, handler never runs', async () => { + test('a modern-classified request on a legacy-era instance is an entry/routing error: typed −32022, handler never runs', async () => { let handlerRan = false; const h = await harness({ setup: receiver => { @@ -394,7 +394,7 @@ describe('the edge→instance handoff — classification is validated, never an expect(handlerRan).toBe(false); expect(h.sent).toHaveLength(1); const error = errorOf(h.sent[0]); - expect(error?.code).toBe(-32004); + expect(error?.code).toBe(-32022); expect(error?.message).toContain('Unsupported protocol version'); // Surfaced out of band too: the mismatch is the entry's bug, not the peer's. expect(h.errors.some(e => e.message.includes('Era mismatch'))).toBe(true); @@ -414,7 +414,7 @@ describe('the edge→instance handoff — classification is validated, never an }); await h.flush(); - expect(errorOf(h.sent[0])).toMatchObject({ code: -32004 }); + expect(errorOf(h.sent[0])).toMatchObject({ code: -32022 }); expect(h.errors.some(e => e.message.includes('Era mismatch'))).toBe(true); }); @@ -433,7 +433,7 @@ describe('the edge→instance handoff — classification is validated, never an await h.flush(); const error = errorOf(h.sent[0]) as { code: number; data?: { requested?: string } } | undefined; - expect(error?.code).toBe(-32004); + expect(error?.code).toBe(-32022); expect(error?.data?.requested).toBe('2025-06-18'); }); diff --git a/packages/server/src/server/createMcpHandler.ts b/packages/server/src/server/createMcpHandler.ts index 691bbca1f4..c1b0656873 100644 --- a/packages/server/src/server/createMcpHandler.ts +++ b/packages/server/src/server/createMcpHandler.ts @@ -502,7 +502,7 @@ async function classifyEntryRequest(request: Request, providedParsedBody?: unkno * answers it with the unsupported-protocol-version error), a malformed * envelope behind a present claim (answered `-32602`), a request whose * `MCP-Protocol-Version` header names a modern revision but that lacks the - * envelope (`-32602`), and header/body mismatches (`-32001`). Consumers + * envelope (`-32602`), and header/body mismatches (`-32020`). Consumers * routing on the predicate must send `false` traffic to the modern handler, * never to a legacy handler — the modern path owns those error answers. * - `server/discover` probes sent by negotiating clients always carry the @@ -637,7 +637,7 @@ export function createMcpHandler(factory: McpServerFactory, options: CreateMcpHa // `classifyInboundRequest` on the edge `era-classification` rung). // Evaluated after the supported-revision // gate so an envelope naming a revision this endpoint does not serve - // is still answered with `-32004` (the supported list is the more + // is still answered with `-32022` (the supported list is the more // useful answer to a client speaking the wrong revision); evaluated // before the capability gate, the factory call, and the // `Mcp-Param-*` rung so a request that fails several rungs is @@ -712,7 +712,7 @@ export function createMcpHandler(factory: McpServerFactory, options: CreateMcpHa // declaration against the request's `Mcp-Param-{Name}` headers and the // body `arguments`. A mismatch (or a missing header for a present body // value, or an invalid Base64 sentinel) emits the same `400` / - // `-32001` (`HeaderMismatch`) shape the edge cross-checks use. Only + // `-32020` (`HeaderMismatch`) shape the edge cross-checks use. Only // applied when the factory returns an `McpServer` (the registry is the // schema source); a low-level `Server` factory has no registry, so // there is nothing to validate against. diff --git a/packages/server/src/server/server.ts b/packages/server/src/server/server.ts index 6e3fffca06..f80c229277 100644 --- a/packages/server/src/server/server.ts +++ b/packages/server/src/server/server.ts @@ -509,7 +509,7 @@ export class Server extends Protocol { * must satisfy the at-least-one rule (`inputRequests` or * `requestState`), and every embedded request must be covered by the * capabilities the client declared on this request's envelope - * (violations answer with the typed `-32003` error). + * (violations answer with the typed `-32021` error). */ private async _invokeInputRequiredCapableHandler( method: string, @@ -601,7 +601,7 @@ export class Server extends Protocol { } // Per-embedded-request capability check against the capabilities the - // client declared on THIS request's envelope (-32003 on violation). + // client declared on THIS request's envelope (-32021 on violation). if (hasInputRequests) { const declared = ctx.mcpReq.envelope?.[CLIENT_CAPABILITIES_META_KEY] as ClientCapabilities | undefined; for (const [key, entry] of Object.entries(inputRequests)) { diff --git a/packages/server/test/server/createMcpHandler.test.ts b/packages/server/test/server/createMcpHandler.test.ts index 59e98b6a1d..fca9ac41ab 100644 --- a/packages/server/test/server/createMcpHandler.test.ts +++ b/packages/server/test/server/createMcpHandler.test.ts @@ -211,14 +211,14 @@ describe('createMcpHandler — modern path', () => { ); expect(response.status).toBe(400); const body = (await response.json()) as JSONRPCErrorBody; - expect(body.error.code).toBe(-32_004); + expect(body.error.code).toBe(-32_022); expect(body.error.data?.['supported']).toEqual([MODERN_REVISION]); expect(body.error.data?.['requested']).toBe('2030-01-01'); expect(body.id).toBe(1); expect(state.contexts).toHaveLength(0); }); - it('rejects a header/body protocol-version mismatch with -32001 (HeaderMismatch) over HTTP 400', async () => { + it('rejects a header/body protocol-version mismatch with -32020 (HeaderMismatch) over HTTP 400', async () => { const { factory } = testFactory(); const onerror = vi.fn(); const handler = createMcpHandler(factory, { onerror }); @@ -226,7 +226,7 @@ describe('createMcpHandler — modern path', () => { const response = await handler.fetch(postRequest(modernToolsCall('echo', { text: 'x' }), { 'mcp-protocol-version': '2025-11-25' })); expect(response.status).toBe(400); const body = (await response.json()) as JSONRPCErrorBody; - expect(body.error.code).toBe(-32_001); + expect(body.error.code).toBe(-32_020); // The rejection echoes the request id. expect(body.id).toBe(1); expect(onerror).toHaveBeenCalled(); @@ -326,7 +326,7 @@ describe("createMcpHandler — modern-only strict (legacy: 'reject')", () => { ); expect(response.status).toBe(400); const body = (await response.json()) as JSONRPCErrorBody; - expect(body.error.code).toBe(-32_004); + expect(body.error.code).toBe(-32_022); expect(body.error.data?.['supported']).toEqual([MODERN_REVISION]); expect(body.id).toBe(1); expect(state.contexts).toHaveLength(0); @@ -347,7 +347,7 @@ describe("createMcpHandler — modern-only strict (legacy: 'reject')", () => { ); expect(response.status).toBe(400); const body = (await response.json()) as JSONRPCErrorBody; - expect(body.error.code).toBe(-32_004); + expect(body.error.code).toBe(-32_022); expect(body.error.data?.['supported']).toEqual([MODERN_REVISION]); expect(body.error.data?.['requested']).toBe('2025-11-25'); expect(body.id).toBe('init-1'); @@ -679,7 +679,7 @@ describe('createMcpHandler — user-land routing with isLegacyRequest (replaces request: () => postRequest({ jsonrpc: '2.0', id: 5, method: 'server/discover', params: { _meta: ENVELOPE } }) }, { - name: 'envelope claiming an unsupported revision (modern path answers -32004)', + name: 'envelope claiming an unsupported revision (modern path answers -32022)', request: () => postRequest(modernToolsCall('echo', { text: 'x' }, { ...ENVELOPE, [PROTOCOL_VERSION_META_KEY]: '2030-01-01' })) }, @@ -696,7 +696,7 @@ describe('createMcpHandler — user-land routing with isLegacyRequest (replaces ) }, { - name: 'header/body mismatch (modern path answers -32001)', + name: 'header/body mismatch (modern path answers -32020)', request: () => postRequest(modernToolsCall('echo', { text: 'x' }), { 'mcp-protocol-version': '2025-11-25' }) } ]; diff --git a/packages/server/test/server/createMcpHandlerCapabilityGate.test.ts b/packages/server/test/server/createMcpHandlerCapabilityGate.test.ts index 9d40e8e66f..38d3463919 100644 --- a/packages/server/test/server/createMcpHandlerCapabilityGate.test.ts +++ b/packages/server/test/server/createMcpHandlerCapabilityGate.test.ts @@ -1,7 +1,7 @@ /** * The pre-dispatch client-capability gate at the HTTP entry: a request to a * method that requires a client capability the request's envelope did not - * declare is refused with the typed `-32003` error and HTTP 400, before any + * declare is refused with the typed `-32021` error and HTTP 400, before any * server instance is constructed or dispatched. * * No request method served on the 2026-07-28 registry has a static @@ -71,7 +71,7 @@ describe('the pre-dispatch client-capability gate', () => { expect(body.result.content[0]?.text).toBe('hi'); }); - it('refuses a request missing a required capability with -32003 and HTTP 400, echoing the request id', async () => { + it('refuses a request missing a required capability with -32021 and HTTP 400, echoing the request id', async () => { requirementTable['tools/call'] = { sampling: {} }; let factoryRan = false; const handler = createMcpHandler(() => { @@ -85,7 +85,7 @@ describe('the pre-dispatch client-capability gate', () => { id: unknown; error: { code: number; data?: { requiredCapabilities?: ClientCapabilities } }; }; - expect(body.error.code).toBe(-32_003); + expect(body.error.code).toBe(-32_021); expect(body.error.data?.requiredCapabilities).toEqual({ sampling: {} }); expect(body.id).toBe(7); // Pre-dispatch: the refusal happens before any per-request instance exists. diff --git a/packages/server/test/server/inputRequired.test.ts b/packages/server/test/server/inputRequired.test.ts index 9d0e1d26c4..efce872842 100644 --- a/packages/server/test/server/inputRequired.test.ts +++ b/packages/server/test/server/inputRequired.test.ts @@ -7,7 +7,7 @@ * tools/call result schema are skipped for it; cache fields are never * stamped on it); * - the guards: at-least-one re-check for hand-built results, the per-embedded - * -request `-32003` capability check against the request's OWN envelope + * -request `-32021` capability check against the request's OWN envelope * capabilities, the server-bug guard (non-multi-round-trip methods, and any * method on a 2025-era request, never put a mis-typed result on the wire); * - a UrlElicitationRequiredError escaping a handler on the modern era fails @@ -222,7 +222,7 @@ describe('guards', () => { await close(); }); - it('checks every embedded request against the capabilities the request itself declared (-32003 on violation)', async () => { + it('checks every embedded request against the capabilities the request itself declared (-32021 on violation)', async () => { const server = new McpServer({ name: 's', version: '1.0.0' }, { capabilities: { tools: {} } }); server.registerTool('ask', { inputSchema: z.object({}) }, async () => inputRequired({ @@ -240,10 +240,10 @@ describe('guards', () => { ); const { request, close } = await wire(server, { era: 'modern' }); - // No elicitation capability declared on the request → -32003 naming + // No elicitation capability declared on the request → -32021 naming // the form sub-capability the embedded form-mode elicitation needs. const noCapability = await request(modernToolCall(1, 'ask', {}, { clientCapabilities: {} })); - expect(errorOf(noCapability).code).toBe(-32_003); + expect(errorOf(noCapability).code).toBe(-32_021); expect(errorOf(noCapability).data).toMatchObject({ requiredCapabilities: { elicitation: { form: {} } } }); // Form-mode capability declared → the same tool is served. @@ -254,13 +254,13 @@ describe('guards', () => { const urlWithoutUrlCapability = await request( modernToolCall(3, 'open-url', {}, { clientCapabilities: { elicitation: { form: {} } } }) ); - expect(errorOf(urlWithoutUrlCapability).code).toBe(-32_003); + expect(errorOf(urlWithoutUrlCapability).code).toBe(-32_021); expect(errorOf(urlWithoutUrlCapability).data).toMatchObject({ requiredCapabilities: { elicitation: { url: {} } } }); - // Form-mode embedded request toward a URL-only client → -32003: modes + // Form-mode embedded request toward a URL-only client → -32021: modes // are sub-capabilities and the server must not send an undeclared one. const formTowardUrlOnly = await request(modernToolCall(4, 'ask', {}, { clientCapabilities: { elicitation: { url: {} } } })); - expect(errorOf(formTowardUrlOnly).code).toBe(-32_003); + expect(errorOf(formTowardUrlOnly).code).toBe(-32_021); expect(errorOf(formTowardUrlOnly).data).toMatchObject({ requiredCapabilities: { elicitation: { form: {} } } }); // A bare `elicitation: {}` declaration is read as form support (the diff --git a/packages/server/test/server/invokeSeam.test.ts b/packages/server/test/server/invokeSeam.test.ts index 98cd86377e..764bd99518 100644 --- a/packages/server/test/server/invokeSeam.test.ts +++ b/packages/server/test/server/invokeSeam.test.ts @@ -106,7 +106,7 @@ describe('invoke', () => { const response = await invoke(mcpServer, toolsCall('greet', { who: 'world' }), { classification: MODERN }); expect(response.status).toBe(400); const body = (await response.json()) as { error: { code: number; data: { supported: string[] } } }; - expect(body.error.code).toBe(-32_004); + expect(body.error.code).toBe(-32_022); expect(Array.isArray(body.error.data.supported)).toBe(true); }); diff --git a/packages/server/test/server/mcpParamValidation.test.ts b/packages/server/test/server/mcpParamValidation.test.ts index 8c49d92b49..0b8b02158a 100644 --- a/packages/server/test/server/mcpParamValidation.test.ts +++ b/packages/server/test/server/mcpParamValidation.test.ts @@ -4,7 +4,7 @@ * * Pre-dispatch ladder rung: a `tools/call` whose `Mcp-Param-{Name}` headers * disagree with the body `arguments` (or are missing for a present body value, - * or carry an invalid Base64 sentinel) is rejected `400` / `-32001` with the + * or carry an invalid Base64 sentinel) is rejected `400` / `-32020` with the * same `HeaderMismatch` shape the inbound classifier emits for the * standard-header cross-checks. A `null`/absent body value passes regardless * of the header (the spec's "server MUST NOT expect" rows). The @@ -79,25 +79,25 @@ describe('SEP-2243 Mcp-Param-* server validation (createMcpHandler, modern era)' expect(response.status).toBe(200); }); - it('a disagreeing header is rejected 400/-32001 (HeaderMismatch) and reports the rejection', async () => { + it('a disagreeing header is rejected 400/-32020 (HeaderMismatch) and reports the rejection', async () => { const onerror = vi.fn(); const handler = createMcpHandler(makeFactory(), { onerror }); const response = await handler.fetch(call({ region: 'us-west1' }, { 'Mcp-Param-Region': 'eu' })); expect(response.status).toBe(400); const body = (await response.json()) as { id: unknown; error: { code: number; data?: { mismatch?: { header?: string } } } }; - expect(body.error.code).toBe(-32_001); + expect(body.error.code).toBe(-32_020); expect(body.error.data?.mismatch?.header).toBe('Mcp-Param-Region'); expect(body.id).toBe(7); expect(onerror).toHaveBeenCalled(); }); // sep-2243-server-reject-missing-required (globally-untested manifest check). - it('a missing header for a present body value is rejected 400/-32001', async () => { + it('a missing header for a present body value is rejected 400/-32020', async () => { const handler = createMcpHandler(makeFactory()); const response = await handler.fetch(call({ region: 'us-west1' })); expect(response.status).toBe(400); const body = (await response.json()) as { error: { code: number } }; - expect(body.error.code).toBe(-32_001); + expect(body.error.code).toBe(-32_020); }); // sep-2243-server-not-expect-null (globally-untested manifest check). @@ -109,11 +109,11 @@ describe('SEP-2243 Mcp-Param-* server validation (createMcpHandler, modern era)' expect(r2.status).toBe(200); }); - it('an invalid Base64 sentinel is rejected 400/-32001', async () => { + it('an invalid Base64 sentinel is rejected 400/-32020', async () => { const handler = createMcpHandler(makeFactory()); const response = await handler.fetch(call({ region: 'Hello' }, { 'Mcp-Param-Region': '=?base64?SGVsbG8?=' })); expect(response.status).toBe(400); - expect(((await response.json()) as { error: { code: number } }).error.code).toBe(-32_001); + expect(((await response.json()) as { error: { code: number } }).error.code).toBe(-32_020); }); }); diff --git a/packages/server/test/server/perRequestTransport.test.ts b/packages/server/test/server/perRequestTransport.test.ts index 38d2952a4d..69a9088d7f 100644 --- a/packages/server/test/server/perRequestTransport.test.ts +++ b/packages/server/test/server/perRequestTransport.test.ts @@ -127,7 +127,7 @@ describe('classification handoff into dispatch', () => { const response = await transport.handleMessage(toolsCall(1, null)); expect(response.status).toBe(400); const error = errorOf(await response.json()); - expect(error?.code).toBe(-32_004); + expect(error?.code).toBe(-32_022); expect(error?.data).toMatchObject({ requested: expect.any(String), supported: expect.any(Array) }); }); @@ -140,7 +140,7 @@ describe('classification handoff into dispatch', () => { const transport = await connectedTransport(server, { classification: MODERN }); const response = await transport.handleMessage(toolsCall()); expect(response.status).toBe(400); - expect(errorOf(await response.json())?.code).toBe(-32_004); + expect(errorOf(await response.json())?.code).toBe(-32_022); }); }); @@ -195,13 +195,13 @@ describe('HTTP status mapping', () => { it('keeps a handler-thrown unsupported-protocol-version error in-band on HTTP 200', async () => { const { server } = modernServer({ toolsCallHandler: async () => { - throw new ProtocolError(-32_004, 'Unsupported protocol version: 2099-01-01'); + throw new ProtocolError(-32_022, 'Unsupported protocol version: 2099-01-01'); } }); const transport = await connectedTransport(server); const response = await transport.handleMessage(toolsCall()); expect(response.status).toBe(200); - expect(errorOf(await response.json())?.code).toBe(-32_004); + expect(errorOf(await response.json())?.code).toBe(-32_022); }); it('keeps handler-produced invalid-params errors in-band on HTTP 200 (never status-mapped)', async () => { diff --git a/packages/server/test/server/serveStdio.test.ts b/packages/server/test/server/serveStdio.test.ts index e342918179..aced8d3b9f 100644 --- a/packages/server/test/server/serveStdio.test.ts +++ b/packages/server/test/server/serveStdio.test.ts @@ -233,7 +233,7 @@ describe('modern opening', () => { await handle.close(); }); - it('once the modern era is pinned, a late claim-less initialize answers -32004 naming the supported revisions', async () => { + it('once the modern era is pinned, a late claim-less initialize answers -32022 naming the supported revisions', async () => { const { handle, request } = await startEntry(); const list = await request({ jsonrpc: '2.0', id: 1, method: 'tools/list', params: { _meta: envelope() } }); @@ -242,7 +242,7 @@ describe('modern opening', () => { const init = await request(initializeRequest(2)); expect(isJSONRPCErrorResponse(init)).toBe(true); if (isJSONRPCErrorResponse(init)) { - expect(init.error.code).toBe(-32_004); + expect(init.error.code).toBe(-32_022); const data = init.error.data as { supported?: string[]; requested?: string }; expect(data.supported).toContain(MODERN); expect(data.requested).toBe(LATEST_PROTOCOL_VERSION); @@ -457,7 +457,7 @@ describe('server/discover probe window', () => { const init = await request(initializeRequest(3)); expect(isJSONRPCErrorResponse(init)).toBe(true); if (isJSONRPCErrorResponse(init)) { - expect(init.error.code).toBe(-32_004); + expect(init.error.code).toBe(-32_022); } // The probe instance is the pinned instance: the factory ran exactly once. expect(eras).toEqual(['modern']); @@ -493,13 +493,13 @@ describe('server/discover probe window', () => { }); describe("legacy: 'reject'", () => { - it('answers a legacy opening with -32004 naming the supported modern revisions and never pins a legacy instance', async () => { + it('answers a legacy opening with -32022 naming the supported modern revisions and never pins a legacy instance', async () => { const { handle, request, eras } = await startEntry({ legacy: 'reject' }); const init = await request(initializeRequest(1)); expect(isJSONRPCErrorResponse(init)).toBe(true); if (isJSONRPCErrorResponse(init)) { - expect(init.error.code).toBe(-32_004); + expect(init.error.code).toBe(-32_022); const data = init.error.data as { supported?: string[]; requested?: string }; expect(data.supported).toContain(MODERN); expect(data.requested).toBe(LATEST_PROTOCOL_VERSION); @@ -553,7 +553,7 @@ describe('malformed and unsupported envelope claims (entry-answered, never pinne await handle.close(); }); - it('a valid claim naming an unsupported revision answers -32004 with the supported list', async () => { + it('a valid claim naming an unsupported revision answers -32022 with the supported list', async () => { const { handle, request, eras } = await startEntry(); const response = await request({ @@ -564,7 +564,7 @@ describe('malformed and unsupported envelope claims (entry-answered, never pinne }); expect(isJSONRPCErrorResponse(response)).toBe(true); if (isJSONRPCErrorResponse(response)) { - expect(response.error.code).toBe(-32_004); + expect(response.error.code).toBe(-32_022); const data = (response as JSONRPCErrorResponse).error.data as { supported?: string[]; requested?: string }; expect(data.supported).toContain(MODERN); expect(data.requested).toBe('2099-01-01'); diff --git a/packages/server/test/server/serveStdioListen.test.ts b/packages/server/test/server/serveStdioListen.test.ts index d800a21b2c..b78ae5a75a 100644 --- a/packages/server/test/server/serveStdioListen.test.ts +++ b/packages/server/test/server/serveStdioListen.test.ts @@ -182,7 +182,7 @@ describe('serveStdio — subscriptions/listen', () => { expect(err.id).toBe(9); // Same shape the opening classifier produces for an unsupported // revision (ProtocolErrorCode.UnsupportedProtocolVersion). - expect(err.error.code).toBe(-32_004); + expect(err.error.code).toBe(-32_022); expect(err.error.data).toMatchObject({ requested: '2099-01-01' }); expect(inbound.some(m => (m as JSONRPCNotification).method === 'notifications/subscriptions/acknowledged')).toBe(false); await handle.close(); diff --git a/packages/server/test/server/stdHeaderValidation.test.ts b/packages/server/test/server/stdHeaderValidation.test.ts index 58a8c89a40..3c7f9238ac 100644 --- a/packages/server/test/server/stdHeaderValidation.test.ts +++ b/packages/server/test/server/stdHeaderValidation.test.ts @@ -8,7 +8,7 @@ * header, a missing `Mcp-Name` header on a `tools/call` / `prompts/get` / * `resources/read` request, an `Mcp-Name` value disagreeing with * `params.name` / `params.uri`, and an invalid `Mcp-Name` Base64 sentinel are - * all rejected `400` / `-32001` (`HeaderMismatch`) on the + * all rejected `400` / `-32020` (`HeaderMismatch`) on the * `standard-header-validation` rung — the same shape the classifier already * emits for the `MCP-Protocol-Version` and `Mcp-Method` mismatch cells on the * edge `era-classification` rung. Legacy-era traffic is byte-unchanged. @@ -59,7 +59,7 @@ async function expectHeaderMismatch(response: Response): Promise<{ code: number; expect(response.status).toBe(400); const body = (await response.json()) as { id: unknown; error: { code: number; message: string } }; expect(body.id).toBe(5); - expect(body.error.code).toBe(-32_001); + expect(body.error.code).toBe(-32_020); return body.error; } @@ -74,13 +74,13 @@ describe('SEP-2243 standard-header validation (createMcpHandler, modern era)', ( expect(body.result.content[0]?.text).toBe('hi'); }); - it('a missing Mcp-Method header is rejected 400/-32001', async () => { + it('a missing Mcp-Method header is rejected 400/-32020', async () => { const handler = createMcpHandler(makeFactory()); const error = await expectHeaderMismatch(await handler.fetch(modernRequest('tools/list', {}))); expect(error.message).toContain('Mcp-Method header is absent'); }); - it('a missing Mcp-Name header on tools/call is rejected 400/-32001', async () => { + it('a missing Mcp-Name header on tools/call is rejected 400/-32020', async () => { const handler = createMcpHandler(makeFactory()); const error = await expectHeaderMismatch( await handler.fetch(modernRequest('tools/call', { name: 'echo', arguments: {} }, { 'mcp-method': 'tools/call' })) @@ -88,7 +88,7 @@ describe('SEP-2243 standard-header validation (createMcpHandler, modern era)', ( expect(error.message).toContain('Mcp-Name header is absent'); }); - it('an Mcp-Name header disagreeing with params.name is rejected 400/-32001', async () => { + it('an Mcp-Name header disagreeing with params.name is rejected 400/-32020', async () => { const handler = createMcpHandler(makeFactory()); const error = await expectHeaderMismatch( await handler.fetch( @@ -128,7 +128,7 @@ describe('SEP-2243 standard-header validation (createMcpHandler, modern era)', ( expect(sentinel.status).toBe(200); }); - it('an invalid Mcp-Name Base64 sentinel is rejected 400/-32001', async () => { + it('an invalid Mcp-Name Base64 sentinel is rejected 400/-32020', async () => { const handler = createMcpHandler(makeFactory()); await expectHeaderMismatch( await handler.fetch( diff --git a/test/conformance/expected-failures.2026-07-28.yaml b/test/conformance/expected-failures.2026-07-28.yaml index fe80b00a03..7e5f901486 100644 --- a/test/conformance/expected-failures.2026-07-28.yaml +++ b/test/conformance/expected-failures.2026-07-28.yaml @@ -15,6 +15,10 @@ # release pinned in package.json. Newer conformance releases are adopted by # deliberately bumping the pin and reconciling this file in the same change. # +# NOTE: the SDK's modern-path rejection codes are aligned with this referee's +# assignments — the spec#2907 / conformance#353 renumber (-32020 / -32021 / +# -32022) is adopted on both the emission and recognition paths. +# # Entries are grouped by what unblocks them. As each gap closes the # corresponding scenarios start passing and MUST be removed from this list # (the runner fails on stale entries), so the baseline burns down per @@ -40,18 +44,13 @@ client: # --- Auth scenarios cut short by the 2026 connection lifecycle --- # The fixture's auth flow drives the 2025 stateful lifecycle; the - # 2026-mode mock rejects the MCP POST (-32001, missing + # 2026-mode mock rejects the MCP POST (-32020, missing # MCP-Protocol-Version header) before the scope-escalation behaviour these # scenarios measure, so no authorization requests are observed. Unblocks # when the auth fixture flow speaks the 2026 per-request lifecycle. - auth/scope-step-up - auth/scope-retry-limit - # --- conformance#353 error-code renumber (spec#2907) --- - # Renumber pending Felix ruling (spec#2907 / conformance#353) — SDK still - # emits −32001/−32003/−32004. Same failure as the 2025 leg. - - request-metadata - # --- Same gaps as the 2025 baseline (fail identically when forced to 2026-07-28) --- # SEP-2106 (JSON Schema $ref handling): no fixture handler for the scenario yet. - json-schema-ref-no-deref @@ -74,12 +73,3 @@ server: # checks; it fails identically at 2025 in `--suite all` (not a 2026-path # regression). - json-schema-2020-12 - # conformance#353 error-code renumber: renumber pending Felix ruling - # (spec#2907 / conformance#353) — SDK still emits −32001/−32003/−32004; - # same failure as the 2025 leg. - - http-custom-header-server-validation - - http-header-validation - # One #353-renumber check fires in the server-stateless modern leg; the - # listChanged-on-listen WARNING was burned down separately by the listen - # arming change. - - server-stateless diff --git a/test/conformance/expected-failures.yaml b/test/conformance/expected-failures.yaml index 0a0ab4b688..335894d7fa 100644 --- a/test/conformance/expected-failures.yaml +++ b/test/conformance/expected-failures.yaml @@ -6,13 +6,10 @@ # README.md). Newer conformance releases are adopted by deliberately bumping # the package.json pin and reconciling this file in the same change. # -# NOTE: the SDK's modern-path rejection codes are NOT yet aligned with this -# referee's assignments. The referee at this pin asserts the spec#2907 / -# conformance#353 renumber (-32020 HeaderMismatch / -32021 / -32022); the SDK -# still emits the pre-renumber codes (-32001 / -32003 / -32004) pending a -# project-level ruling on adopting the renumber. The affected cells are -# annotated below ("renumber pending Felix ruling") and re-derived when the -# ruling lands and/or a newer conformance release is pinned. A missing _meta +# NOTE: the SDK's modern-path rejection codes are aligned with this referee's +# assignments — the spec#2907 / conformance#353 renumber (-32020 HeaderMismatch +# / -32021 MissingRequiredClientCapability / -32022 UnsupportedProtocolVersion) +# is adopted on both the emission and recognition paths. A missing _meta # envelope (or missing protocolVersion key) still answers -32602 on both sides. # # Entries are grouped by SEP. As each SEP/milestone is implemented in the SDK the @@ -43,24 +40,8 @@ client: # client support for the token-exchange + JWT bearer flow. - auth/enterprise-managed-authorization - # --- conformance#353 error-code renumber (spec#2907) --- - # Renumber pending Felix ruling (spec#2907 / conformance#353) — SDK still - # emits −32001/−32003/−32004. The mock now rejects with −32020/−32022 where - # the SDK still recognises −32001/−32004, so connect falls through to a - # malformed `initialize` result. - - request-metadata - server: # --- Draft-spec scenarios (in `--suite draft`; the default `active` suite is green) --- - # --- conformance#353 error-code renumber (spec#2907) --- - # Renumber pending Felix ruling (spec#2907 / conformance#353) — SDK still - # emits −32001/−32003/−32004; the referee at this pin asserts - # −32020/−32021/−32022 for header/body mismatch, missing-required-client- - # capability, and unsupported-protocol-version respectively. - - http-custom-header-server-validation - # WARNING-only at this pin; same #353 cause as above. - - http-header-validation - # One #353-renumber check fires in the server-stateless modern leg; the - # listChanged-on-listen WARNING was burned down separately by the listen - # arming change. - - server-stateless + # (empty — the conformance#353 error-code renumber entries burned when the + # SDK adopted the spec#2907 -32020/-32021/-32022 assignments.) + [] diff --git a/test/conformance/src/everythingClient.ts b/test/conformance/src/everythingClient.ts index 1cc2255d61..92e70f9f1a 100644 --- a/test/conformance/src/everythingClient.ts +++ b/test/conformance/src/everythingClient.ts @@ -195,7 +195,7 @@ async function runToolsCallModernClient(serverUrl: string): Promise { // request-metadata scenario (SEP-2575): every request must carry the // MCP-Protocol-Version header and the per-request _meta envelope, and the // client must retry with a supported version when its first choice is -// rejected with -32004. The version-negotiation probe (server/discover plus +// rejected with -32022. The version-negotiation probe (server/discover plus // the corrective continuation) is exactly that mechanism. async function runRequestMetadataClient(serverUrl: string): Promise { const clientInfo = { name: 'test-client', version: '1.0.0' }; diff --git a/test/conformance/src/everythingServer.ts b/test/conformance/src/everythingServer.ts index bb349a3f8c..256fb43ff9 100644 --- a/test/conformance/src/everythingServer.ts +++ b/test/conformance/src/everythingServer.ts @@ -930,7 +930,7 @@ function createMcpServer() { // Capability-aware input requests: only ask for kinds the request's // declared client capabilities cover (the server seam enforces the same - // rule with a -32003 error; the tool simply never trips it). + // rule with a -32021 error; the tool simply never trips it). mcpServer.registerTool( 'test_input_required_result_capabilities', { diff --git a/test/e2e/requirements.ts b/test/e2e/requirements.ts index b6aeeaac75..60972ac16b 100644 --- a/test/e2e/requirements.ts +++ b/test/e2e/requirements.ts @@ -2797,7 +2797,7 @@ export const REQUIREMENTS: Record = { 'typescript:mrtr:url-elicitation:no-32042-on-2026': { source: 'https://modelcontextprotocol.io/specification/draft/basic/patterns/mrtr', behavior: - 'URL-mode elicitation rides the multi-round-trip flow on the 2026-07-28 era: a tool handler that returns inputRequired.elicitUrl(...) embeds a URL-mode elicitation/create in an input_required result (capability-gated by -32003 on elicitation.url), the registered elicitation handler fulfils it, the retried call completes, and the urlElicitationRequired error code (-32042) never appears on the wire.', + 'URL-mode elicitation rides the multi-round-trip flow on the 2026-07-28 era: a tool handler that returns inputRequired.elicitUrl(...) embeds a URL-mode elicitation/create in an input_required result (capability-gated by -32021 on elicitation.url), the registered elicitation handler fulfils it, the retried call completes, and the urlElicitationRequired error code (-32042) never appears on the wire.', addedInSpecVersion: '2026-07-28', transports: ['entryModern'], supersedes: ['mcpserver:tool:url-elicitation-error', 'elicitation:url:required-error'], diff --git a/test/e2e/scenarios/sep2243.test.ts b/test/e2e/scenarios/sep2243.test.ts index 83353d9cef..4b946dc8d6 100644 --- a/test/e2e/scenarios/sep2243.test.ts +++ b/test/e2e/scenarios/sep2243.test.ts @@ -54,7 +54,7 @@ verifies('sep-2243:param-header:roundtrip', async ({ transport }: TestArgs) => { expect(headerValue).toBe('us-west1'); // The call succeeded against the validating server (header agreed with - // the body argument, so no -32001 HeaderMismatch on the wire). + // the body argument, so no -32020 HeaderMismatch on the wire). expect(result.isError).toBeFalsy(); expect(result.content).toEqual([{ type: 'text', text: 'region=us-west1' }]); }); @@ -85,7 +85,7 @@ verifies('sep-2243:std-header:mismatch-rejected', async ({ transport }: TestArgs expect(response.status).toBe(400); const body = (await response.json()) as { error: { code: number; message: string } }; - // -32001 is the SEP-2243 HeaderMismatch code at this branch's spec pin. - expect(body.error.code).toBe(-32_001); + // -32020 is the SEP-2243 HeaderMismatch code (post-spec#2907 renumber). + expect(body.error.code).toBe(-32_020); expect(body.error.message).toMatch(/Mcp-Method/); }); diff --git a/test/integration/test/server/createMcpHandler.test.ts b/test/integration/test/server/createMcpHandler.test.ts index 83e3c112cc..0cc2f2546c 100644 --- a/test/integration/test/server/createMcpHandler.test.ts +++ b/test/integration/test/server/createMcpHandler.test.ts @@ -139,7 +139,7 @@ describe('createMcpHandler over HTTP (legacy postures end to end)', () => { }); expect(response.status).toBe(400); const body = (await response.json()) as { id: unknown; error: { code: number; data: { supported: string[] } } }; - expect(body.error.code).toBe(-32_004); + expect(body.error.code).toBe(-32_022); expect(body.error.data.supported).toEqual([MODERN]); // The rejection echoes the request id it answers (it could be read from the body). expect(body.id).toBe(1); diff --git a/test/integration/test/server/dualEraStdio.test.ts b/test/integration/test/server/dualEraStdio.test.ts index ff74afdfd9..091d7aba26 100644 --- a/test/integration/test/server/dualEraStdio.test.ts +++ b/test/integration/test/server/dualEraStdio.test.ts @@ -170,7 +170,7 @@ describe('serveStdio over a real child-process pipe (one connection per spawned params: { protocolVersion: LATEST_PROTOCOL_VERSION, capabilities: {}, clientInfo: { name: 'late', version: '0' } } }); const lateError = (lateInitialize as { error: { code: number; data?: { supported?: string[] } } }).error; - expect(lateError.code).toBe(-32_004); + expect(lateError.code).toBe(-32_022); expect(lateError.data?.supported).toContain(MODERN); } finally { await client.close(); From bf559218770c7257406ff8d3f1526946cc402794 Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Fri, 19 Jun 2026 12:15:02 +0000 Subject: [PATCH 2/3] chore(conformance): swap vendored tarball pin for pkg.pr.new alpha.5 build (#357) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the file:./vendor/*.tgz pin (built locally from conformance@d70d7ad) with the pkg.pr.new build of conformance#357 (commit 65fcd39 — the 0.2.0-alpha.5 version bump on top of main@d70d7ad, carrying #347 + #353). Content-identical to the previous referee; expected-failures baselines are unchanged. - test/conformance/package.json: @modelcontextprotocol/conformance → https://pkg.pr.new/@modelcontextprotocol/conformance@357 - test/conformance/vendor/: deleted (tarball + .gitignore override) - README.md: drop local-build/tarball/sha256 instructions; note pkg.pr.new pin pending the npm publish (switch to ^0.2.0-alpha.5 once published) - expected-failures.yaml: header pin → 0.2.0-alpha.5 (via pkg.pr.new #357) - pnpm-lock.yaml: regenerated --- pnpm-lock.yaml | 12 ++++++------ test/conformance/README.md | 15 +++------------ test/conformance/expected-failures.yaml | 4 ++-- test/conformance/package.json | 2 +- test/conformance/vendor/.gitignore | 2 -- ...protocol-conformance-0.2.0-main.d70d7ad.tgz | Bin 102387 -> 0 bytes 6 files changed, 12 insertions(+), 23 deletions(-) delete mode 100644 test/conformance/vendor/.gitignore delete mode 100644 test/conformance/vendor/modelcontextprotocol-conformance-0.2.0-main.d70d7ad.tgz diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index f062d68951..6dab5e1d6f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1540,8 +1540,8 @@ importers: specifier: workspace:^ version: link:../../packages/client '@modelcontextprotocol/conformance': - specifier: file:./vendor/modelcontextprotocol-conformance-0.2.0-main.d70d7ad.tgz - version: file:test/conformance/vendor/modelcontextprotocol-conformance-0.2.0-main.d70d7ad.tgz(@cfworker/json-schema@4.1.1) + specifier: https://pkg.pr.new/@modelcontextprotocol/conformance@357 + version: https://pkg.pr.new/@modelcontextprotocol/conformance@357(@cfworker/json-schema@4.1.1) '@modelcontextprotocol/core': specifier: workspace:^ version: link:../../packages/core @@ -2552,9 +2552,9 @@ packages: '@manypkg/get-packages@1.1.3': resolution: {integrity: sha512-fo+QhuU3qE/2TQMQmbVMqaQ6EWbMhi4ABWP+O4AM1NqPBuy0OrApV5LO6BrrgnhtAHS2NH6RrVk9OL181tTi8A==} - '@modelcontextprotocol/conformance@file:test/conformance/vendor/modelcontextprotocol-conformance-0.2.0-main.d70d7ad.tgz': - resolution: {integrity: sha512-L61dGG8Fx+JzenEwzROovVB+tcIT8o6TzuKSVegYzgw3oIsf3aIHASJgZtKbnrhgOnSowxBpHm74d/HDKiaZnQ==, tarball: file:test/conformance/vendor/modelcontextprotocol-conformance-0.2.0-main.d70d7ad.tgz} - version: 0.2.0-main.d70d7ad + '@modelcontextprotocol/conformance@https://pkg.pr.new/@modelcontextprotocol/conformance@357': + resolution: {integrity: sha512-lBpIgubkIbMDksgtcebY6d/Z7HgQF81BIKIdudVhLOtgF8ymvhlC9O/ktAuLCDC+E1x7w/G96s89zRxH2Rf/FA==, tarball: https://pkg.pr.new/@modelcontextprotocol/conformance@357} + version: 0.2.0-alpha.5 hasBin: true '@modelcontextprotocol/sdk@1.29.0': @@ -6443,7 +6443,7 @@ snapshots: globby: 11.1.0 read-yaml-file: 1.1.0 - '@modelcontextprotocol/conformance@file:test/conformance/vendor/modelcontextprotocol-conformance-0.2.0-main.d70d7ad.tgz(@cfworker/json-schema@4.1.1)': + '@modelcontextprotocol/conformance@https://pkg.pr.new/@modelcontextprotocol/conformance@357(@cfworker/json-schema@4.1.1)': dependencies: '@modelcontextprotocol/sdk': 1.29.0(@cfworker/json-schema@4.1.1)(zod@4.3.6) '@octokit/rest': 22.0.1 diff --git a/test/conformance/README.md b/test/conformance/README.md index 08521b21ff..a30c2da877 100644 --- a/test/conformance/README.md +++ b/test/conformance/README.md @@ -4,18 +4,9 @@ This directory contains conformance test implementations for the TypeScript MCP > `@modelcontextprotocol/conformance` is pinned to an exact version (no `^` range) in `package.json`. New conformance releases are adopted by deliberately bumping the pin and updating `expected-failures.yaml` for any new scenarios/checks in the same change. -> **Local pin (temporary):** the pin currently points at a vendored tarball (`file:./vendor/modelcontextprotocol-conformance-0.2.0-main.d70d7ad.tgz`) built from `modelcontextprotocol/conformance@main` (`d70d7ad`, post-`0.2.0-alpha.4`). This pulls in -> [#347](https://github.com/modelcontextprotocol/conformance/pull/347) (client-scenario mocks now serve `server/discover`) ahead of the next published release so the discover-shim removal can be exercised. To revert to a published release, replace the `file:` spec in -> `package.json` with the exact version string (e.g. `"0.2.0-alpha.5"`), delete `vendor/`, run `pnpm install`, and reconcile `expected-failures.yaml` in the same change. -> -> Tarball sha256: `d09d694de2d3982e511d2b6a91af93b2e09a83f107bfc8f879c090d995e8ecfe`. Rebuild (from a checkout of `modelcontextprotocol/conformance` at `d70d7ad`, with this SDK's workspace `tsdown` on `PATH` because the conformance repo's own devDeps are unavailable on the -> internal mirror): -> -> ```sh -> npm version 0.2.0-main.d70d7ad --no-git-tag-version -> tsdown # deps externalised identically to the published alpha.4 dist -> npm pack --ignore-scripts -> ``` +> **Pre-release pin (temporary):** the pin currently points at the [pkg.pr.new](https://pkg.pr.new) build of [conformance#357](https://github.com/modelcontextprotocol/conformance/pull/357) (`https://pkg.pr.new/@modelcontextprotocol/conformance@357`, commit `65fcd39` — the +> `0.2.0-alpha.5` version bump on top of `main@d70d7ad`, carrying [#347](https://github.com/modelcontextprotocol/conformance/pull/347) and [#353](https://github.com/modelcontextprotocol/conformance/pull/353)). This is pinned to the alpha.5 pkg.pr.new build pending the npm +> publish; switch to `^0.2.0-alpha.5` once published, run `pnpm install`, and reconcile `expected-failures.yaml` in the same change. ## Client Conformance Tests diff --git a/test/conformance/expected-failures.yaml b/test/conformance/expected-failures.yaml index 335894d7fa..0da31cd545 100644 --- a/test/conformance/expected-failures.yaml +++ b/test/conformance/expected-failures.yaml @@ -2,8 +2,8 @@ # CI exits 0 if only these fail, exits 1 on unexpected failures or stale entries. # # Baseline established against the @modelcontextprotocol/conformance pin in -# package.json (0.2.0-main.d70d7ad — a vendored build of conformance@main; see -# README.md). Newer conformance releases are adopted by deliberately bumping +# package.json (0.2.0-alpha.5 (via pkg.pr.new #357); see README.md). Newer +# conformance releases are adopted by deliberately bumping # the package.json pin and reconciling this file in the same change. # # NOTE: the SDK's modern-path rejection codes are aligned with this referee's diff --git a/test/conformance/package.json b/test/conformance/package.json index a2688e54ee..580afd51a0 100644 --- a/test/conformance/package.json +++ b/test/conformance/package.json @@ -40,7 +40,7 @@ "test:conformance:all": "pnpm run test:conformance:client:all && pnpm run test:conformance:server:all" }, "devDependencies": { - "@modelcontextprotocol/conformance": "file:./vendor/modelcontextprotocol-conformance-0.2.0-main.d70d7ad.tgz", + "@modelcontextprotocol/conformance": "https://pkg.pr.new/@modelcontextprotocol/conformance@357", "@modelcontextprotocol/client": "workspace:^", "@modelcontextprotocol/server": "workspace:^", "@modelcontextprotocol/core": "workspace:^", diff --git a/test/conformance/vendor/.gitignore b/test/conformance/vendor/.gitignore deleted file mode 100644 index fceadb8a3a..0000000000 --- a/test/conformance/vendor/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -# Allow vendored conformance tarballs (root .gitignore has *.tgz). -!*.tgz diff --git a/test/conformance/vendor/modelcontextprotocol-conformance-0.2.0-main.d70d7ad.tgz b/test/conformance/vendor/modelcontextprotocol-conformance-0.2.0-main.d70d7ad.tgz deleted file mode 100644 index 2ef865142084210f592021c6116e561dea480ac3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 102387 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

KM_^0&uOl}Y#!0tM9eeI|9u&B@@coJDyElwVy} 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

n^H|G- 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 From fc381881a1c6fb97bc0281ab056b293aaeda314d Mon Sep 17 00:00:00 2001 From: Felix Weinberger Date: Fri, 19 Jun 2026 14:06:10 +0000 Subject: [PATCH 3/3] fix(server): streamableHttp stores request-related events when stream is disconnected The standalone-SSE path stores to eventStore first, then writes if connected. The request-related path only stored when the stream was live, so a notification sent after closeSSE() (SEP-1699 polling) was silently dropped instead of being persisted for replay on reconnect. Exposed by the ctx.mcpReq.log request-related change against the new sse-polling example story; the gap pre-exists on main for any request-related notification (progress, ctx.mcpReq.notify) emitted after closeSSE(). --- packages/server/src/server/streamableHttp.ts | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/server/src/server/streamableHttp.ts b/packages/server/src/server/streamableHttp.ts index fb6ffc2b02..ca5bd7ad09 100644 --- a/packages/server/src/server/streamableHttp.ts +++ b/packages/server/src/server/streamableHttp.ts @@ -1002,15 +1002,18 @@ export class WebStandardStreamableHTTPServerTransport implements Transport { const stream = this._streamMapping.get(streamId); - if (!this._enableJsonResponse && stream?.controller && stream?.encoder) { - // For SSE responses, generate event ID if event store is provided + if (!this._enableJsonResponse) { + // Store FIRST so request-related events emitted while the per-request + // stream is disconnected (e.g. after `closeSSE()`) are replayed on + // reconnect — same store-first semantics as the standalone path above. let eventId: string | undefined; - if (this._eventStore) { eventId = await this._eventStore.storeEvent(streamId, message); } - // Write the event to the response stream - this.writeSSEEvent(stream.controller, stream.encoder, message, eventId); + if (stream?.controller && stream?.encoder) { + // Write the event to the response stream + this.writeSSEEvent(stream.controller, stream.encoder, message, eventId); + } } if (isJSONRPCResultResponse(message) || isJSONRPCErrorResponse(message)) {