Skip to content

Map protocol errors onto HTTP status codes (follow-up to #110) - #128

Merged
TGoodhew merged 1 commit into
mainfrom
http/status-codes-for-protocol-errors
Jul 31, 2026
Merged

Map protocol errors onto HTTP status codes (follow-up to #110)#128
TGoodhew merged 1 commit into
mainfrom
http/status-codes-for-protocol-errors

Conversation

@TGoodhew

Copy link
Copy Markdown
Owner

The follow-up I flagged in #126: the same transport section says an unimplemented method MUST be 404 and an unsupported protocol version MUST be 400, with the JSON-RPC error still in the body.

Change

  • -32601404, -32022 / -32020 / -32021400, everything else → 200.
  • The body is the point. A modern server saying "I don't have that method" and a legacy server that doesn't host this endpoint at all both answer 404 — the JSON-RPC error in the body is exactly what lets a client tell them apart, which is how the backward-compatibility probe works.
  • A tool that fails is still 200. The request was served; the failure belongs in the result where the model reads it, not in the transport.
  • Gated on the declared revision, like everything else: a client written against 2025-06-18 may only read the body on 200, and nothing about its world changes.

A real hole found while wiring it

DeclaresRevisionAtLeast compared ordinally, and "latest" sorts above every dated revision because l comes after 2. So a request declaring nonsense read as newer than 2026-07-28 and would have been held to its rules — demanding Mcp-Method headers, getting resultType, and so on. The shape is now checked before the order, in one place (RequestContext.IsRevisionName) that the dispatcher shares rather than duplicating.

The dispatcher was already safe here — it rejects a non-revision before producing any result — so this was latent rather than live, but it was one code path away from mattering.

Verification

  • 5 new tests — unknown method 404 with the error body and the right id; still 200 for an older client; a non-revision version refused for what it is rather than treated as newest; a failed tool still 200; and the ordering hole itself, asserted directly on RequestContext.
  • Full suite green: 407 GpibMcp + 113 Hpgl, 0 failures (Release|x86) — was 402 + 113.

The transport rules that #110 covered also say an unimplemented method MUST be
404 and an unsupported protocol version MUST be 400, with the JSON-RPC error
still in the body. I flagged that as deliberately out of scope in PR #126; this
is it.

The body is the point. A modern server saying "I do not have that method" and a
legacy server that does not host this endpoint at all both answer 404 - the
JSON-RPC error in the body is exactly what lets a client tell them apart, which
is how the backward-compatibility probe works.

A tool that FAILS is still 200: the request was served, and the failure is in
the result where the model can read it.

Gated on the declared revision, like everything else here: a client written
against 2025-06-18 may only read the body on 200, and nothing about its world
changes.

Also fixes a real hole found while wiring this. DeclaresRevisionAtLeast compared
ordinally, and "latest" sorts above every dated revision because l comes after
2 - so a request declaring nonsense read as NEWER than 2026-07-28 and would have
been held to its rules. The shape is now checked before the order, in one place
(RequestContext.IsRevisionName) that the dispatcher shares.

5 tests.
@TGoodhew
TGoodhew merged commit 3464375 into main Jul 31, 2026
1 check passed
@TGoodhew
TGoodhew deleted the http/status-codes-for-protocol-errors branch July 31, 2026 18:50
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.

1 participant