Skip to content

Define error code allocation policy and renumber draft error codes#2907

Open
felixweinberger wants to merge 7 commits into
mainfrom
fweinberger/error-code-allocation
Open

Define error code allocation policy and renumber draft error codes#2907
felixweinberger wants to merge 7 commits into
mainfrom
fweinberger/error-code-allocation

Conversation

@felixweinberger

@felixweinberger felixweinberger commented Jun 12, 2026

Copy link
Copy Markdown
Contributor

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..-32099 for implementation-defined server errors, and our SDKs have long used the low end of that range for their own purposes: -32000/-32001 are request-timeout/connection-closed in the TypeScript and Python SDKs, -32001 is also "session not found" in the TypeScript and C# HTTP transports, and go-sdk uses -32001/-32005/-32006/-32007 internally. The codes introduced in this draft (-32001 HeaderMismatch via SEP-2243, -32003/-32004 via SEP-2575/#2716) landed on top of that usage. SEP-2164 removed -32002 from 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..-32019 stays implementation-defined; existing SDK usage is grandfathered; no new codes there. Receivers must not assign cross-implementation semantics to these codes.
  • -32020..-32099 is reserved for the MCP specification, with every allocation recorded in schema.ts, allocated sequentially from -32020.
  • Applications belong outside the JSON-RPC reserved range entirely.

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.

Code Old New
HeaderMismatch -32001 -32020
MissingRequiredClientCapability -32003 -32021
UnsupportedProtocolVersion -32004 -32022

HeaderMismatchError is 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-25 schema.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/ErrClientClosing shuffle), inspector's -32099 proxy 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 via npm 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

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

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..-32011 codes during their migration out of the reserved band.

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.
@felixweinberger felixweinberger requested a review from a team as a code owner June 12, 2026 12:41
@mintlify

mintlify Bot commented Jun 12, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
mcp-staging 🟢 Ready View Preview Jun 12, 2026, 12:45 PM

💡 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.
@mintlify

mintlify Bot commented Jun 12, 2026

Copy link
Copy Markdown

Preview deployment for your docs. Learn more about Mintlify Previews.

Project Status Preview Updated (UTC)
mcp 🟢 Ready View Preview Jun 12, 2026, 12:48 PM

💡 Tip: Enable Workflows to automatically generate PRs for you.

Comment thread docs/specification/draft/basic/index.mdx Outdated
Comment thread docs/specification/draft/basic/index.mdx Outdated
Comment thread docs/specification/draft/basic/index.mdx
Comment on lines +147 to +150
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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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.

felixweinberger and others added 3 commits June 12, 2026 14:20
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.
Comment thread docs/specification/draft/basic/index.mdx Outdated
Comment thread docs/specification/draft/basic/index.mdx Outdated
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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
specified meanings.

Comment thread docs/specification/draft/basic/index.mdx Outdated
Comment thread docs/specification/draft/basic/index.mdx Outdated
Comment thread docs/specification/draft/basic/index.mdx Outdated
Comment thread docs/specification/draft/basic/index.mdx Outdated
Comment thread docs/specification/draft/basic/index.mdx Outdated
Comment thread docs/specification/draft/basic/index.mdx Outdated
Comment thread docs/specification/draft/basic/index.mdx Outdated
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.
Comment on lines +115 to +118
- **`-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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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.

Comment on lines +150 to +152
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.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

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:

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

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:

-32020 to -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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants