| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
…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
Previous run failed on pre-existing flaky race in AbstractMcpClientServerIntegrationTests.testRootsNotificationWithEmptyRootsList (Stream unavailable for session); unrelated transport changes all green.
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.
| Back | FazBrowse Home | New Git URL |
Closes #990. Supersedes #994, #1026, #1092 (with credit to @cooleditphoto,
@nikita-kibitkin, and @ez-lbz — the consolidation proposed in #990).
Summary
Implements SEP-2243
HTTP header standardization end-to-end:
an Mcp-Name header whenever the request targets a named artifact;
headers against the deserialized request body, and validate the
MCP-Protocol-Version header against the supported version set.
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:
400 Bad Request and a message naming both values.
not send the new headers keep working unchanged.
present-but-unsupported version is rejected.
This replaces the opt-in rejectMissingHeaders(false) switch discussed for the
consolidation: gating absence would wrongly gate mismatches too, and splitting
the two concerns needs two flags where current semantics need none.
Implementation notes
for both requests and notifications. The name/URI comes from typed binding
of the params (tools/call, prompts/get use .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.
so validation compares header against the parsed body, not raw text.
Responses carry no method and are skipped.
Testing
JDK HTTP server round-trip.
protocol version, method mismatch, name mismatch) and the tolerance rule
(absent headers produce only unrelated errors such as a missing session),
for both the streamable servlet provider and the stateless transport.
Conformance Tests (@modelcontextprotocol/conformance@0.2.0-alpha.11)
All tests match the expected baseline 100% across all released spec versions (2025-03-26, 2025-06-18, and 2025-11-25).
Compatibility
Non-breaking for conformant legacy traffic: emission is additive on outbound
requests, and server behavior changes only for clients that already send these
headers with wrong values, which is what the SEP requires servers to catch.
Out of scope, deliberately
The Spring/WebClient/WebMvc stack has no separate streamable-HTTP transport in
this codebase, so there is nothing further to wire. Name extraction is
duplicated as private helpers in the two servlet classes today; pulling it
into a shared utility can follow once a third caller exists.