Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .changeset/envelope-auto-emission.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 1 addition & 1 deletion .changeset/missing-client-capability-error.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 1 addition & 1 deletion .changeset/mrtr-server-seam.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 1 addition & 1 deletion .changeset/pin-modern-rejection-codes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 The blanket -32004→-32022 retro-edit in this changeset rewrote a backward-looking sentence: "These cells previously emitted a provisional -32022…" — but the header/body-mismatch cells previously emitted the provisional -32004; no build has ever emitted -32022 for them, and -32022 also appears in the next sentence as the current (unchanged) envelope-less rejection code, which makes the changelog entry confusing. Keep -32004 in the historical clause (or reword to "the provisional pre-renumber unsupported-protocol-version code").

Extended reasoning...

What's wrong. The PR retro-aligns the 8 pre-existing alpha changesets by replacing the old error-code literals with the renumbered ones. For most of those changesets that's correct, because the sentences describe what the release will ship. But in .changeset/pin-modern-rejection-codes.md (line 6) the replacement landed inside a sentence that describes history: the pre-PR text read "These cells previously emitted a provisional -32004 while the upstream error-code discussion was open", which was accurate — the header/body-mismatch cells provisionally borrowed the then-current UnsupportedProtocolVersion wire code -32004 in earlier v2 alpha builds before being pinned to HeaderMismatch. After the edit it claims those cells "previously emitted a provisional -32022", which is false: -32022 only exists as of this PR's spec#2907 renumber and was never emitted by any build for those cells.

Why it's confusing in context. Within the same paragraph, -32022 now appears twice with two different meanings: first as the code the mismatch cells used to emit (false), then in the very next sentence as the current, unchanged code for the envelope-less rejection on a modern-only endpoint (true). It also reads oddly next to the new spec-2907-error-code-renumber.md changeset in the same release, which correctly states the -32004-32022 transition for UnsupportedProtocolVersion.

Concrete walkthrough. (1) An earlier v2 alpha emitted -32004 for a header/body protocol-version mismatch on the modern path. (2) The pin-modern-rejection-codes change (already pending in this changeset) moved those cells to HeaderMismatch — at that time -32001, now -32020 after this PR. (3) A consumer who hard-coded -32004 for the mismatch cells reads the generated changelog after the next version bump: the entry tells them those cells "previously emitted a provisional -32022", a code their build never saw, while the migration note elsewhere in this PR correctly says -32004-32022 is the UnsupportedProtocolVersion renumber. The code-transition story for the mismatch cells comes out garbled.

On the counter-argument that the retro-alignment is deliberate and harmless. The retro-alignment of forward-looking statements is indeed deliberate and correct, and the changesets do publish atomically — but that argument applies to sentences describing what the release ships, not to a sentence whose subject is what earlier interim builds emitted. "Previously emitted a provisional -32022" is simply not true under any reading; referring to the historical interim code by its post-renumber identity would at minimum need rewording (e.g. "previously borrowed the provisional unsupported-protocol-version code") rather than a bare numeric literal that names a value that did not exist yet. The PR itself treats the renumber as wire-visible for v2-alpha consumers (the migration note tells them to update hard-coded literals), so changelog readers who care about these numbers are real.

Fix. One-word change: keep -32004 in that historical sentence, or reword it to avoid a numeric literal entirely ("These cells previously emitted the provisional pre-renumber unsupported-protocol-version code while the upstream error-code discussion was open"). All other claims in the changeset (the -32020 HeaderMismatch pin, the -32602 envelope rejection, the unchanged -32022 envelope-less cell) match the implementation in this diff.

This is changelog-prose accuracy only — code, tests, and conformance baselines are all consistent — so it's a nit and shouldn't block the merge.

2 changes: 1 addition & 1 deletion .changeset/sep-2243-mcp-param-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 1 addition & 1 deletion .changeset/sep-2243-std-header-server.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
7 changes: 7 additions & 0 deletions .changeset/spec-2907-error-code-renumber.md
Original file line number Diff line number Diff line change
@@ -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`.
2 changes: 1 addition & 1 deletion .changeset/spec-anchor-repin-2fb207da.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,6 @@

- `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).

Check warning on line 11 in .changeset/spec-anchor-repin-2fb207da.md

View check run for this annotation

Claude / Claude Code Review

spec-anchor-repin changeset retro-edit misattributes -32020 to the pre-#2907 anchor

The blanket -32001→-32020 retro-edit also rewrote this anchored sentence, but this changeset documents the re-pin to spec commit 2fb207da — a pre-spec#2907 anchor where the draft schema's HEADER_MISMATCH constant was -32001, and the vendored schema-twins/2026-07-28.schema.json this PR deliberately leaves at that anchor still defines -32001 (no in-repo schema artifact defines -32020). Keep -32001 in this anchored sentence or drop the numeric literal; the "emitted behavior is unchanged (documentat

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 The blanket -32001→-32020 retro-edit also rewrote this anchored sentence, but this changeset documents the re-pin to spec commit 2fb207da — a pre-spec#2907 anchor where the draft schema's HEADER_MISMATCH constant was -32001, and the vendored schema-twins/2026-07-28.schema.json this PR deliberately leaves at that anchor still defines -32001 (no in-repo schema artifact defines -32020). Keep -32001 in this anchored sentence or drop the numeric literal; the "emitted behavior is unchanged (documentation only)" parenthetical also reads contradictory next to the sibling renumber changeset once the literal is flipped. Same class of retro-edit issue as the already-flagged pin-modern-rejection-codes.md sentence, but a separate instance in a different file.

Extended reasoning...

What's wrong. This PR retro-aligns 8 pre-existing alpha changesets by replacing the old 2026-07-28 error-code literals with the renumbered ones. That is correct for forward-looking sentences describing what the release will ship, but line 11 of .changeset/spec-anchor-repin-2fb207da.md is anchored to a specific artifact and spec commit: it documents the re-pin of the 2026-07-28 draft references to spec commit 2fb207da, and says the header/body-mismatch error code "is now defined by the draft schema (HEADER_MISMATCH)". At that anchor — which predates spec#2907 — the draft schema defines HEADER_MISMATCH as -32001, not -32020.

Why the in-repo artifact contradicts the new wording. The vendored schema twin produced by this re-pin, packages/core/test/corpus/schema-twins/2026-07-28.schema.json, still defines HeaderMismatchError with "const": -32001 (line 1149), and -32020 does not appear anywhere in that file. The PR description explicitly states these sha256-locked artifacts are deliberately left at the pre-#2907 anchor, to be refreshed atomically with the next repin. So after the retro-edit, the changeset whose subject is precisely that anchor claims "-32020 ... is now defined by the draft schema", a statement not backed by the artifact the changeset is about.

The parenthetical becomes contradictory. The original sentence's "the emitted behavior is unchanged (documentation only)" was accurate for -32001: the SDK already emitted -32001 for header/body mismatches, and the re-pin merely gave it schema backing. Flipped to -32020, the same parenthetical now sits next to the new spec-2907-error-code-renumber.md changeset in the same release, which describes exactly the wire-visible -32001 → -32020 change. A changelog reader sees one entry calling -32020 a wire-visible renumber and another calling it documentation-only.

Step-by-step proof. (1) The re-pin commit this changeset documents pinned the draft references to spec commit 2fb207da428f... (the manifest commit for the schema twin). (2) At that commit the schema's HeaderMismatchError constant is -32001 — confirmed by the vendored twin at packages/core/test/corpus/schema-twins/2026-07-28.schema.json:1149, which this PR does not touch. (3) The retro-edit replaced the literal in line 11, so the changeset now attributes -32020 to a schema anchor that defines -32001. (4) When the changesets are consumed into the release changelog, this entry says -32020 was "documentation only" while the renumber entry says -32020 is the new wire code replacing -32001 — the code-history story for HeaderMismatch comes out garbled.

Why this is not a duplicate. The existing inline PR comment covers .changeset/pin-modern-rejection-codes.md line 6 (the "previously emitted a provisional -32022" sentence). This is the same class of issue — a backward-looking/anchored sentence renumbered as if it were forward-looking — but a distinct surviving instance in a different file and sentence.

Fix. One-line reword: keep -32001 in this anchored sentence ("The error code -32001 emitted for HTTP header/body mismatches is now defined by the draft schema (HEADER_MISMATCH)..."), or drop the numeric literal entirely ("the header-mismatch code is now defined by the draft schema (HEADER_MISMATCH)"). Changelog-prose accuracy only — no code, test, or conformance impact — so this should not block the merge.


No public API surface changes; the regenerated reference artifacts are internal/test-only.
2 changes: 1 addition & 1 deletion .changeset/spec-reference-types-2026-07-28.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
2 changes: 1 addition & 1 deletion docs/client.md
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
4 changes: 3 additions & 1 deletion docs/migration-SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Expand All @@ -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<boolean>` 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
Expand Down
Loading
Loading