feat(transport): add SEP-2243 Mcp-Method / Mcp-Name header mirroring with MCP-Protocol-Version validation - #1112
Open
slachiewicz wants to merge 4 commits into
Open
Conversation
slachiewicz
marked this pull request as draft
August 28, 2026 11:11
This was referenced Aug 28, 2026
slachiewicz
force-pushed
the
feat/sep-2243-headers
branch
from
August 28, 2026 17:15
d6b0d79 to
edcac59
Compare
…with MCP-Protocol-Version validation Implement SEP-2243 HTTP header standardization across client and server servlet transports. * Client: Emit 'Mcp-Method' on outbound Streamable HTTP requests and notifications, and 'Mcp-Name' when targeting named tools, prompts, or resources. * Server: Validate 'Mcp-Method' and 'Mcp-Name' headers against deserialized JSON-RPC payloads in HttpServletStreamableServerTransportProvider and HttpServletStatelessServerTransport. Reject mismatches with HTTP 400 while tolerating absent headers for backward compatibility. * Versioning: Validate 'MCP-Protocol-Version' against supported protocol versions on incoming servlet requests. * Tests: Add Sep2243ClientRequestHeaderTests and Sep2243ServerHeaderValidationTests verifying emission, mismatch rejections, and absent-header tolerance.
…checks Per the Streamable HTTP spec the MCP-Protocol-Version header is required only after initialization completes; version selection for initialize happens through body-level negotiation, not header validation. * Client: stop sending MCP-Protocol-Version on initialize requests * Servlet servers: skip strict header validation for initialize so clients advertising an unsupported version negotiate instead of getting 400 * Tests: pin client omission and server tolerance for initialize; make version-negotiation test contextExtractor null-safe for absent headers
The GET /mcp stream is opened asynchronously once initialize creates the session, so asserting recorded calls immediately races under load (seen as Jackson 2 Integration Tests failing usesLatestVersion with Expected size: 3 but was: 2). Await the recorded GET before asserting header propagation.
… and return -32020 HeaderMismatch * Encode non-ASCII and sentinel-matching Mcp-Name values in Base64 sentinel format (=?base64?...?=) in HttpClientStreamableHttpTransport to prevent JDK HttpClient IllegalArgumentException on non-Latin-1 characters. * Decode Base64 sentinel Mcp-Name values on HttpServletStreamableServerTransportProvider and HttpServletStatelessServerTransport prior to body validation. * Add HEADER_MISMATCH (-32020) error code to McpSchema.ErrorCodes per SEP-2243 and return it on header/body mismatches. * Add unit and integration tests for Base64 sentinel encoding/decoding and -32020 mismatch error codes. Co-authored-by: Nikita Kibitkin <nikita.n.kibitkin@gmail.com>
slachiewicz
force-pushed
the
feat/sep-2243-headers
branch
from
September 2, 2026 20:08
edcac59 to
63b1c04
Compare
slachiewicz
marked this pull request as ready for review
September 2, 2026 20:08
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.
Closes #990. Supersedes #994, #1026, #1092 (with credit to @cooleditphoto, @nikita-kibitkin, and @ez-lbz — the consolidation proposed in #990; @nikita-kibitkin agreed to fold in #1026).
Summary
Implements SEP-2243 HTTP header standardization end-to-end:
Mcp-Methodheader on every POST and anMcp-Nameheader whenever the request targets a named artifact (tools/call,prompts/get,resources/read,resources/subscribe,resources/unsubscribe).Mcp-Namevalues are safely encoded using the SEP-2243 Base64 sentinel format (=?base64?...?=), protecting against JDKHttpClientIllegalArgumentExceptionon non-Latin-1 characters.Mcp-Method/Mcp-Nameheaders against the deserialized request body (decoding Base64 sentinels where present), returningHEADER_MISMATCH(-32020) with HTTP 400 on mismatches.MCP-Protocol-Versionheader against the supported version set (exemptinginitializerequests, which negotiate version via payload).HttpClientStreamableHttpVersionNegotiationIntegrationTests.Semantics (the decision this PR stands on)
SEP-2243 requires servers to reject header/body mismatches, and discussion on #994 established that rejecting absent headers must not break legacy clients:
Mcp-MethodorMcp-Nameis rejected with400 Bad RequestandHEADER_MISMATCH(-32020).MCP-Protocol-Versionfalls back to negotiated behavior, while a present-but-unsupported version on post-init requests is rejected.Implementation notes
HttpHeaders.MCP_METHOD,HttpHeaders.MCP_NAME,HttpHeaders.BASE64_SENTINEL_PREFIX,HttpHeaders.BASE64_SENTINEL_SUFFIX, and helper methodsHttpHeaders.encodeHeaderValue/HttpHeaders.decodeHeaderValue.McpSchema.ErrorCodes.HEADER_MISMATCH = -32020.HttpClientStreamableHttpTransport.sendMessagefor both requests and notifications. The name/URI comes from typed binding of the params (tools/call,prompts/getuse.name(); the resource operations use.uri()), so no regex-on-body parsing is involved. Extraction failures log at debug and omit the header rather than fail the request.Testing
Sep2243ClientRequestHeaderTestsasserts emitted headers through a real JDK HTTP server round-trip, including Base64 sentinel encoding for non-ASCII tool names.Sep2243ServerHeaderValidationTestscovers the rejection matrix (bad protocol version, method mismatch, name mismatch with error code-32020), Base64 decoding acceptance, and the tolerance rule (absent headers do not trigger SEP-2243 errors), for both the streamable servlet provider and the stateless transport.HttpClientStreamableHttpVersionNegotiationIntegrationTestsverifies protocol version propagation and async stream readiness.Co-authored-by: Nikita Kibitkin nikita.n.kibitkin@gmail.com