Skip to content

Gate 2026-07-28 result fields on negotiated protocol version (#1721) - #1753

Merged
tarekgh merged 1 commit into
modelcontextprotocol:mainfrom
tarekgh:fix-1721-protocol-version-gating
Jul 27, 2026
Merged

Gate 2026-07-28 result fields on negotiated protocol version (#1721)#1753
tarekgh merged 1 commit into
modelcontextprotocol:mainfrom
tarekgh:fix-1721-protocol-version-gating

Conversation

@tarekgh

@tarekgh tarekgh commented Jul 27, 2026

Copy link
Copy Markdown
Contributor

Fixes #1721.

The server unconditionally stamped resultType, ttlMs, and cacheScope on every JSON-RPC result. These fields are exclusive to the 2026-07-28 revision, so strict 2025-11-25 clients (such as MCP Inspector 1.0.0) reject them as unrecognized keys and fail the handshake.

This change gates every stamping site on the negotiated (or per-request) protocol version:

  • SetHandler and SetWithAlternateHandler only stamp resultType, ttlMs, and cacheScope when the request is 2026-07-28 or later.
  • InitializeResult no longer hardcodes resultType (the initialize handshake only ever negotiates 2025-11-25 or earlier).
  • The default logging/setLevel handler returns a fresh EmptyResult instead of the shared, pre-stamped EmptyResult.Instance, so this legacy method no longer leaks resultType to down-level clients.

The 2026-07-28-only paths (server/discover, subscriptions/listen, and the Tasks extension) keep stamping these fields as required by the spec.

Testing

  • New Core regression tests covering tools/list and tools/call on both 2025-11-25 (fields omitted) and 2026-07-28 (fields present) sessions.
  • New raw HTTP wire tests for InitializeResult and a down-level tools/list.
  • New default logging/setLevel regression test.
  • Updated existing down-level assertions accordingly.
  • Core: 2317 passed, 0 failed. AspNetCore: 555 passed, 0 failed.

…ntextprotocol#1721)

The server unconditionally stamped resultType, ttlMs, and cacheScope on
every JSON-RPC result, which are exclusive to the 2026-07-28 revision.
Strict 2025-11-25 clients (such as MCP Inspector 1.0.0) reject these
unrecognized keys and fail the handshake.

Every stamping site is now gated on the negotiated (or per-request)
protocol version:
- SetHandler and SetWithAlternateHandler only stamp resultType, ttlMs,
  and cacheScope when the request is 2026-07-28 or later.
- InitializeResult no longer hardcodes resultType (the initialize
  handshake only ever negotiates 2025-11-25 or earlier).
- The default logging/setLevel handler returns a fresh EmptyResult
  instead of the shared, pre-stamped EmptyResult.Instance, so this
  legacy method no longer leaks resultType to down-level clients.

Added Core and raw HTTP wire regression tests, and updated existing
down-level assertions accordingly.

Copilot-Session: 80653343-5dcb-43cb-89b0-8ac8e572c4f7
@tarekgh
tarekgh requested a review from halter73 July 27, 2026 18:45
@tarekgh

tarekgh commented Jul 27, 2026

Copy link
Copy Markdown
Contributor Author

CC @p-ob

@halter73 halter73 left a comment

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.

Custom handlers and filters can still explicitly set resultType or cache hints for legacy requests, producing invalid wire shapes. I filed #1754 to decide whether we should reject, warn and strip, or silently strip those values. This shouldn’t block this release fix.

@tarekgh
tarekgh merged commit 6787c0c into modelcontextprotocol:main Jul 27, 2026
10 checks passed
This was referenced Jul 28, 2026
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.

bug(2.0.0-preview.3): resultType, ttlMs, and cacheScope emitted on all responses regardless of negotiated protocol version (breaks 2025-11-25 clients)

3 participants