Support MCP 2026-07-28 (stateless protocol) across scanners and SDK - #2
Merged
Conversation
MCP revision 2026-07-28 turned the protocol from a stateful, handshake-based protocol into a stateless request/response one. The scanners were still negotiating 2025-06-18 via `initialize`, which no longer reaches a server on the current revision at all. Add a dual-era MCP client (apps/web/src/lib/mcp.ts) that probes `server/discover` at 2026-07-28, renegotiates on UnsupportedProtocolVersion, and falls back to the `initialize` handshake only when the server turns out to be legacy — inspecting the body of a 4xx before falling back, as the spec's compatibility rules require. Modern requests carry the required per-request `_meta` fields and the mirrored `MCP-Protocol-Version` / `Mcp-Method` / `Mcp-Name` headers, with the base64 sentinel encoding for unsafe values. Compliance tester now grades each server against the rules for its own era: `server/discover`, `supportedVersions`, `resultType`, `ttlMs`/`cacheScope` cache hints, header-mismatch rejection (400 + -32020), and statelessness (no minted `Mcp-Session-Id`, GET not served) for stateless servers; `initialize` / `ping` plus a superseded-revision warning for handshake servers. Security scanner adds version-aware checks for the new surface: deprecated Roots/Sampling/Logging capabilities, retained sessions and the removed SSE GET endpoint, `x-mcp-header` constraint violations and parameters mirrored into credential-shaped headers, `cacheScope: "public"` on authenticated servers, network `$ref` targets in tool schemas, and authorization-server metadata for RFC 9207 issuer identification and CIMD-vs-deprecated-DCR registration. Tool explorer calls tools in the server's era, mirroring `x-mcp-header` parameters, rejecting tools with invalid annotations, and surfacing multi round-trip `input_required` results instead of treating them as output. mcp-sdk gains the stateless types (`MCPDiscoverResult`, `MCPCacheableResult`, `MCPInputRequiredResult`, reserved `_meta` keys, spec error codes), a dual-era client with `connect()`/`discover()`, and era-tagged compliance rules. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01N4mJKbHLw7YzjnfHJjtWn5
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.
MCP revision 2026-07-28 turned the protocol from a stateful, handshake-based
protocol into a stateless request/response one. The scanners were still
negotiating 2025-06-18 via
initialize, which no longer reaches a server onthe current revision at all.
Add a dual-era MCP client (apps/web/src/lib/mcp.ts) that probes
server/discoverat 2026-07-28, renegotiates on UnsupportedProtocolVersion,and falls back to the
initializehandshake only when the server turns out tobe legacy — inspecting the body of a 4xx before falling back, as the spec's
compatibility rules require. Modern requests carry the required per-request
_metafields and the mirroredMCP-Protocol-Version/Mcp-Method/Mcp-Nameheaders, with the base64 sentinel encoding for unsafe values.Compliance tester now grades each server against the rules for its own era:
server/discover,supportedVersions,resultType,ttlMs/cacheScopecache hints, header-mismatch rejection (400 + -32020), and statelessness
(no minted
Mcp-Session-Id, GET not served) for stateless servers;initialize/pingplus a superseded-revision warning for handshake servers.Security scanner adds version-aware checks for the new surface: deprecated
Roots/Sampling/Logging capabilities, retained sessions and the removed SSE GET
endpoint,
x-mcp-headerconstraint violations and parameters mirrored intocredential-shaped headers,
cacheScope: "public"on authenticated servers,network
$reftargets in tool schemas, and authorization-server metadata forRFC 9207 issuer identification and CIMD-vs-deprecated-DCR registration.
Tool explorer calls tools in the server's era, mirroring
x-mcp-headerparameters, rejecting tools with invalid annotations, and surfacing multi
round-trip
input_requiredresults instead of treating them as output.mcp-sdk gains the stateless types (
MCPDiscoverResult,MCPCacheableResult,MCPInputRequiredResult, reserved_metakeys, spec error codes), a dual-eraclient with
connect()/discover(), and era-tagged compliance rules.Co-Authored-By: Claude Opus 5 noreply@anthropic.com
Claude-Session: https://claude.ai/code/session_01N4mJKbHLw7YzjnfHJjtWn5