Skip to content

Claim MCP 2026-07-28 (#115) - #130

Merged
TGoodhew merged 1 commit into
mainfrom
issue-115-claim-2026-07-28
Jul 31, 2026
Merged

Claim MCP 2026-07-28 (#115)#130
TGoodhew merged 1 commit into
mainfrom
issue-115-claim-2026-07-28

Conversation

@TGoodhew

Copy link
Copy Markdown
Owner

Closes #115. The closing move of the epic.

Everything the revision asks of a server is implemented — stateless dispatch, server/discover, resultType, cacheable tools/list, the error-code policy, the transport metadata headers and status codes, subscriptions/listen, tasks. So 2026-07-28 joins SupportedProtocolVersions, and the server says so when asked.

MRTR: confirmed, not assumed

I read SEP-2322 rather than carry the earlier assumption. Every server obligation in it is conditional on choosing to return an InputRequiredResult"Servers MAY respond to any supported client request with an InputRequiredResult" — and this server initiates no sampling, elicitation or roots requests, so it never returns one. All of its results are resultType: "complete", which is conformant. The one MUST that could bind us ("Servers MUST send server-to-client requests using the MRTR pattern") is vacuous for a server that sends none.

Best-effort is gone, with the thing that needed it

While 2026-07-28 was half-built, refusing a request that declared it would have put its own features out of reach of the only clients asking for them. That justification is spent. One rule now: a revision is either implemented and served properly, or the client is told so with the list it can choose from.

2025-11-25 is the interesting case — a real revision we have not reviewed, so it is refused. Claiming a revision we haven't read is the exact dishonesty the list exists to prevent, and there's a test holding it off the list.

Two things this exposed

  • The handshake-negotiated revision now shapes later requests that name none. A client that agreed 2026-07-28 at initialize and then got 2025-06-18-shaped results back would have been misled by us, not by the protocol. Adding the revision to the list is what made that reachable.
  • ProtocolVersion and "the newest revision" were the same constant and are no longer the same idea. LatestProtocolVersion is what we implement; ProtocolVersion is what the legacy handshake answers when the client names nothing — deliberately not the newest, because using initialize at all predates the revision that removed it.

Also: a version refusal is now 400 over HTTP whatever the request declared. Only a request that named a version can be refused for it, so its client is version-aware by definition, and the status is what tells it to read the list.

Verification

  • 422 GpibMcp + 113 Hpgl, 0 failures (Release|x86) — was 414 + 113. Five tests encoded the old behaviour and were rewritten to the new rules rather than deleted; the theory in ErrorCodeTests now walks served-vs-refused across five declared versions.
  • End-to-end on the built exe: server/discover reports all four versions newest-first; a 2026-07-28 tools/list returns resultType: "complete" with ttlMs/cacheScope; 2025-11-25 is refused with -32022 and the supported list; a request with no _meta still gets the old shape untouched — which is the compatibility promise this whole epic was built on.

README and the startup log updated: the server now reports the full supported set rather than a single revision.

Everything the revision asks of a server is implemented: stateless dispatch,
server/discover, resultType, cacheable tools/list, the error-code policy, the
transport metadata headers and status codes, subscriptions/listen, tasks. So the
revision joins SupportedProtocolVersions and the server says so when asked.

MRTR confirmed inapplicable rather than assumed. Every server obligation in
SEP-2322 is conditional on choosing to return an InputRequiredResult - "servers
MAY respond" - and this server initiates no sampling, elicitation or roots
requests, so it never returns one. Its results are all resultType "complete",
which is conformant.

Best-effort is gone with the thing that needed it. While 2026-07-28 was
half-built, refusing a request that declared it would have put its own features
out of reach; now there is one rule, and it is the negotiation working as
designed: a revision is either implemented and served properly, or the client is
told so with the list it can choose from. 2025-11-25 is the interesting case - a
real revision we have not reviewed, so it is refused, because claiming a
revision we have not read is the exact dishonesty the list exists to prevent.

Two things this exposed, both fixed here:

- The handshake-negotiated revision now shapes later requests that name none. A
  client that agreed 2026-07-28 at initialize and then got 2025-06-18-shaped
  results back would have been misled by us, not by the protocol.
- ProtocolVersion and "the newest revision" had been the same constant and are
  no longer the same idea. LatestProtocolVersion is what we implement;
  ProtocolVersion is what the legacy handshake answers when the client names
  nothing - deliberately NOT the newest, since using initialize at all predates
  the revision that removed it.

A version refusal is now 400 over HTTP whatever the request declared: only a
request that named a version can be refused for it, so its client is
version-aware by definition and the status is what tells it to read the list.

Verified on the built exe: discover reports all four versions newest-first, a
2026-07-28 tools/list comes back complete with the cache hints, 2025-11-25 is
refused with -32022 and the list, and a request with no _meta still gets the old
shape untouched.
@TGoodhew
TGoodhew merged commit 0efc5a1 into main Jul 31, 2026
1 check passed
@TGoodhew
TGoodhew deleted the issue-115-claim-2026-07-28 branch July 31, 2026 19:24
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.

Epic: adopt MCP specification 2026-07-28

1 participant