ADR-0023 — Guard denial moves to -32010; spec claims -32003/-32004¶
- Status: Accepted — amends ADR-0012
- Date: 2026-06-11
Context¶
Since ADR-0012, a guard denial has surfaced as
JSON-RPC error -32003 with message "Forbidden: <reason>". That code
was chosen freely from JSON-RPC 2.0's implementation-defined
server-error range (-32000 to -32099).
MCP 2026-07-28 now assigns meanings inside that same range
(ADR-0019): -32003 is
MissingRequiredClientCapabilityError (the server needs a capability
the client did not declare in clientCapabilities) and -32004 is
UnsupportedProtocolVersionError. Both carry spec-defined data
shapes. Additionally, -32001 is used by the Streamable HTTP transport
prose for HeaderMismatch, and -32002 historically meant
resource-not-found (this revision moves that to -32602).
Keeping guard denial on -32003 would make an authorization denial
indistinguishable from a missing-client-capability error — same code,
different (and now spec-mandated) data payload. A 2026-07-28 client
is entitled to parse error.data.requiredCapabilities out of any
-32003 it receives.
Decision¶
Mocapi-private error codes start at -32010, leaving -32000 to
-32009 to the spec and transport prose (current and future). Guard
denial moves from -32003 to -32010. The message contract
("Forbidden: <reason>") and all Guard SPI semantics from ADR-0012 are
unchanged — only the numeric code moves.
The spec-defined codes are referenced via their model-layer constants
(MissingRequiredClientCapabilityErrorData.CODE,
UnsupportedProtocolVersionErrorData.CODE); mocapi defines no
duplicate constants for them.
Consequences¶
Clients keying on -32003 to detect a guard denial must switch to
-32010 — acceptable pre-1.0 and consistent with the clean break
(ADR-0019: no current consumers). Authorization denials and
missing-capability errors are now unambiguous on the wire. ADR-0012
remains the authority on Guard semantics; this ADR amends only the
error-code choice.
2026-07-15 update — spec renumbered its codes off the low band¶
Upstream renumbered the spec-defined error codes (commits f505a6c7 +
73ab7d2f, still protocol version 2026-07-28). The implementation-defined
server-error range is now explicitly partitioned: -32000 to -32019 stays
implementation-defined (grandfathered SDK usage), and -32020 to -32099
is reserved for spec-defined errors. Consequently the spec-defined codes moved
out of the low band:
MissingRequiredClientCapabilityError:-32003→-32021UnsupportedProtocolVersionError:-32004→-32022HeaderMismatch:-32001→-32020
-32003 is therefore no longer spec-claimed — the original collision
that motivated relocating guard denial is gone. The decision nonetheless
stands: guard denial remains -32010, which sits squarely inside the
implementation-defined sub-range (-32000 to -32019) that the spec has now
formally reserved for implementations. No re-relocation is warranted; keeping
-32010 stable avoids churn and stays clear of the spec-reserved band. Status
remains Accepted.
See docs/plans/2026-07-28-schema-diff.md (§ "2026-07-15 re-diff") for the
full re-diff.
Code anchors: mocapi-server/src/main/java/com/callibrity/mocapi/server/JsonRpcErrorCodes.java, mocapi-server/src/main/java/com/callibrity/mocapi/server/guards/GuardEvaluationInterceptor.java.