Adopt the JSON-RPC error-code allocation policy (#109) - #125
Merged
Conversation
2026-07-28 splits the server-error range: -32000..-32019 is implementation-
defined, -32020..-32099 belongs to the specification. Nothing we emit collides
today - every code is a standard JSON-RPC one - but there was no convention to
stop a future custom code landing in the reserved half, where it would collide
with a spec code and mean something else to every client.
McpError now documents the split, names the three renumbered spec codes
(HeaderMismatch -32020, MissingRequiredClientCapability -32021,
UnsupportedProtocolVersion -32022) with factories that carry useful data, and
exposes IsImplementationDefined so a test can hold us to the rule.
HeaderMismatch is for the transport-header work; MissingRequiredClientCapability
for wherever a capability turns out to be required.
UnsupportedProtocolVersion is wired to the one case that is unambiguous today: a
request declaring something that is not a revision at all ("latest") cannot be
served on any reading, so it gets the specification error carrying the list we
do speak. A DATED revision we do not fully implement is still served,
best-effort, and logged - we already answer much of 2026-07-28s shape, and
refusing it outright would put those features out of reach of the only clients
that ask for them. That branch becomes a refusal when the revision is either
finished or ruled out: the last step of the epic, not a step inside it.
Notifications are never answered with an error whatever they declare - JSON-RPC
has nowhere to put it.
7 tests, including one that walks every code the server emits and asserts each
is standard JSON-RPC or spec-allocated, never invented in the reserved block.
12 tasks
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #109.
2026-07-28 splits the server-error range:
-32000…-32019implementation-defined,-32020…-32099reserved for the specification. Nothing we emit collides today — every code is a standard JSON-RPC one — but there was no convention stopping a future custom code from landing in the reserved half, where it would collide with a spec code and mean something else to every client.Change
McpErrordocuments the split and names the three renumbered spec codes with factories that carry useful data:HeaderMismatch(-32020),MissingRequiredClientCapability(-32021),UnsupportedProtocolVersion(-32022).IsImplementationDefinedexists so a test can hold us to the rule.HeaderMismatchis there for MCP 2026-07-28: Streamable HTTP -Mcp-Method/Mcp-Nameheaders and stale session remnants #110;MissingRequiredClientCapabilityfor wherever a capability turns out to be genuinely required.The judgment call on UnsupportedProtocolVersion
Wired to the one case that is unambiguous today: a request declaring something that is not a revision at all (
"latest") cannot be served on any reading, so it gets the spec error carrying the list we do speak.A dated revision we do not fully implement is still served best-effort and logged. Refusing it would be more literally conformant and worse in practice: we already answer much of 2026-07-28's shape —
resultType, per-resultserverInfo,server/discover, the cache hints — and 2026-07-28 is not inSupportedProtocolVersionsyet, so a blanket refusal would put every one of those features out of reach of the only clients that ask for them. The code says where that changes: when the revision is either finished or ruled out, the best-effort branch becomes a refusal. That is the last step of the epic, not a step inside it.Verification
UnsupportedProtocolVersiondata names the supported list; a non-revision is refused; a dated unimplemented revision is served; a notification is never answered with an error whatever it declares (JSON-RPC has nowhere to put one).