Define error code allocation policy and renumber draft error codes#2907
Define error code allocation policy and renumber draft error codes#2907felixweinberger wants to merge 7 commits into
Conversation
JSON-RPC 2.0 reserves -32000..-32099 for implementation-defined server errors, and existing SDKs already use the low end of that range (request timeouts, connection closed, session not found). The error codes introduced in this draft collided with that usage: -32001 (HeaderMismatch) is also used by SDKs for request timeouts and session-not-found responses. Partition the range instead: -32000..-32009 stays implementation-defined (existing usage grandfathered, no new codes), -32010..-32099 is reserved for the MCP specification, with allocations recorded in schema.ts and starting at -32020. Renumber the draft-introduced codes accordingly: - HeaderMismatch: -32001 -> -32020 - MissingRequiredClientCapability: -32003 -> -32021 - UnsupportedProtocolVersion: -32004 -> -32022 Also add HeaderMismatchError to the schema (it previously existed only in transport prose) with an example, and document the policy in the Error Codes section of the base protocol overview.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
Simpler boundary: implementation-defined space is -32000..-32019, the MCP specification reserves -32020..-32099. Drops the reserved-but-unallocated buffer concept in favor of a single clean split.
|
Preview deployment for your docs. Learn more about Mintlify Previews.
💡 Tip: Enable Workflows to automatically generate PRs for you. |
| Errors that are purely local to an implementation (for example, a request | ||
| timeout raised inside an SDK and never sent to the peer) are best represented | ||
| outside the JSON-RPC numeric code space entirely, so they cannot be confused | ||
| with wire-level protocol errors. |
There was a problem hiding this comment.
Not sure I agree with this statement. IMO it would have been better if MCP defined these, and probably we should in the future? MCP is not just a wire-level protocol: it's valuable to define what a client receives if a tool times out, even if it's not something actually sent over the wire.
There was a problem hiding this comment.
What about something like this?
Errors that are purely local to an implementation (for example, a request
timeout raised inside an SDK) are not currently assigned codes by this
specification. Implementations surfacing local errors in JSON-RPC-shaped
structures should ensure they cannot be mistaken for errors received from
the peer. Future versions of the specification may define standard codes
for common local error conditions in the reserved sub-range.
Co-authored-by: Peter Alexander <pja@anthropic.com>
Co-authored-by: Peter Alexander <pja@anthropic.com>
Co-authored-by: Peter Alexander <pja@anthropic.com>
Per review feedback: the spec may want to standardize what clients receive for common local conditions (e.g. request timeouts) in the future, so the note no longer steers implementations away from numeric codes entirely.
| recorded in the [schema](/specification/draft/schema). Implementations | ||
| **MUST NOT** emit codes from this sub-range with meanings other than those | ||
| defined by the specification. | ||
|
|
There was a problem hiding this comment.
| specified meanings. | |
Reframe -32000..-32019 as legacy allocations, state the emit/meaning rules for the spec-reserved sub-range explicitly, and list the historical codes as a bulleted MUST NOT emit list.
| - **`-32000` to `-32019` — legacy.** Codes in this sub-range were allocated by | ||
| implementations before this policy was introduced. New codes **MUST NOT** be | ||
| allocated in this sub-range. Apart from `-32002` and `-32042` (see below), | ||
| receivers **MUST NOT** assume any specific meaning for these codes. |
There was a problem hiding this comment.
I think we should add a line to this advising new implementations not to use this range at all - the fewer error code conflicts we have, the better. That wouldn't mean disallowing new/existing implementations to use it, but it's better if they don't, and we should say that.
| Applications layered on top of MCP **MUST NOT** define error codes inside the | ||
| JSON-RPC reserved range (`-32768` to `-32000`); the remainder of the integer | ||
| space is available for application-defined errors. |
There was a problem hiding this comment.
The distinction between an implementation and an application is not well-defined, so I think this clause makes the interpretation of the spec more confusing as it can reasonably be interpreted to conflict with this statement before it:
-32000to-32019— legacy. Codes in this sub-range were allocated by implementations before this policy was introduced. New codes MUST NOT be allocated in this sub-range. Apart from-32002and-32042(see below), receivers MUST NOT assume any specific meaning for these codes.
If an application is an implementation, then we can't permit continued use of the legacy range while also disallowing use of the entire reserved range (which is a superset of the legacy range).
I also think that if an application is an implementation, then the clause is partially-redundant with the statement immediately after that one:
-32020to-32099— reserved for the MCP specification. Error codes in this sub-range are defined exclusively by the MCP specification and recorded in the schema. Implementations MUST NOT emit any code from this sub-range that is not defined by this specification and MUST use defined codes only with their specified meanings.
If an application is not an implementation... I'm not sure how we would differentiate that besides "you probably know what this means."
To the point, though: I think we should just remove the clause and make sure that our normative language about implementation affordances applies equally whether an application is an implementation or not.
Partitions the JSON-RPC server-error range between implementations and the spec, and renumbers the error codes introduced in this draft so they no longer collide with existing SDK usage.
Motivation and Context
JSON-RPC 2.0 reserves
-32000..-32099for implementation-defined server errors, and our SDKs have long used the low end of that range for their own purposes:-32000/-32001are request-timeout/connection-closed in the TypeScript and Python SDKs,-32001is also "session not found" in the TypeScript and C# HTTP transports, and go-sdk uses-32001/-32005/-32006/-32007internally. The codes introduced in this draft (-32001HeaderMismatch via SEP-2243,-32003/-32004via SEP-2575/#2716) landed on top of that usage. SEP-2164 removed-32002from the spec citing exactly this reserved-range argument.Discussed with the Tier 1 SDK maintainers (Discord: https://discord.com/channels/1358869848138059966/1514317386570793060). The agreed approach:
-32000..-32019stays implementation-defined; existing SDK usage is grandfathered; no new codes there. Receivers must not assign cross-implementation semantics to these codes.-32020..-32099is reserved for the MCP specification, with every allocation recorded inschema.ts, allocated sequentially from-32020.Renumbering is draft-only — none of these codes exist in a released spec version, so this is non-breaking if it lands before 2026-07-28.
HeaderMismatch-32001-32020MissingRequiredClientCapability-32003-32021UnsupportedProtocolVersion-32004-32022HeaderMismatchErroris also added to the schema with a typed interface and example — it previously existed only in transport prose.Historical codes are documented as reserved-never-reused:
-32002(resource not found, ≤2025-11-25; clients still accept it per SEP-2164's compat note) and-32042(URL elicitation required, 2025-11-25 only — note it is in the released 2025-11-25schema.ts, tagged@internal).Follow-ups after merge: conformance pins for SEP-2243/SEP-2575 codes, go-sdk and csharp-sdk constants (both draft-gated; go-sdk can also undo its
ErrServerClosing/ErrClientClosingshuffle), inspector's-32099proxy code moves out of the reserved sub-range.How Has This Been Tested?
npm run check(schema TS/JSON/examples/MDX, docs format, links, SEPs) passes clean; schema artifacts regenerated vianpm run generate:schema.Breaking Changes
None against released versions — all renumbered codes are draft-only. Draft implementers (go-sdk, csharp-sdk, conformance) need to update constants.
Types of changes
Checklist
Additional context
The shift to
-32020+ (instead of-32010+ as floated on Discord) keeps the spec-reserved sub-range clear of Bedrock AgentCore's in-use-32001..-32011codes during their migration out of the reserved band.