GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — feat: validate SEP-2243 Mcp-Param headers in modern server by prathamgoyal787 · Pull Request #1202 · modelcontextprotocol/java-sdk

Conversation

@prathamgoyal787

@prathamgoyal787 prathamgoyal787 commented Oct 20, 2026 •
edited
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown

Validates SEP-2243 Mcp-Param-{Name} headers in the modern server: for every tool parameter marked with x-mcp-header, tools/call now checks the header the client sent against the argument in the body.

Closes #1199

Motivation and Context

SEP-2243 (part of the 2026-07-28 revision) lets a tool mark parameters with x-mcp-header so clients copy their values into Mcp-Param-{Name} HTTP headers. Load balancers and gateways can then route on them without parsing the JSON body. The spec makes it a MUST for servers to reject a request whose headers disagree with the body, are missing while the body has a value, or are malformed. Otherwise an intermediary could route on a header the server never checked.

The modern server already validates Mcp-Method, Mcp-Name and MCP-Protocol-Version, but not Mcp-Param-*. This was listed as a Known Limitation in conformance-tests/VALIDATION_RESULTS.md, and http-custom-header-server-validation could not pass. The check needs the called tool's inputSchema, which the transport doesn't have. So, as proposed in #1199:

  • Transport: HttpServletMcpTransport collects the headers into a new TransportParams value.

    • Header names are case-insensitive.
    • Optional whitespace (OWS) around values is trimmed.
    • Values in the exact lowercase =?base64?…?= form are decoded strictly: padding is required and the bytes must be valid UTF-8.
    • Plain values must be printable ASCII.
    • Malformed or repeated headers are flagged rather than failing the request.
  • Context: the value is attached to the McpTransportContext under TransportParams.KEY after the user's contextExtractor runs, so the extractor can neither drop nor forge it.

  • stdio: StdioMcpTransport attaches TransportParams.NOT_MIRRORED, the only value that skips validation. A context without the key counts as "no headers sent", not "skip".

  • Validation: ToolsFeature validates after find and before inputSchema validation. Only x-mcp-header annotations reached through properties count; items, allOf and $ref are not followed.

    Case Outcome
    Argument present Header required and must match. Strings exactly, integers numerically (42.0 = 42), booleans as true/false
    Argument null or absent (incl. missing intermediate object) No header expected
    Argument present, header missing Rejected
    Header of a declared parameter malformed Rejected
    Mcp-Param-* header no parameter declares Ignored

    Rejections throw McpException with ErrorCodes.HEADER_MISMATCH (-32020), which the servlet answers with 400.

  • Invalid definitions: invalid server-side x-mcp-header definitions are ignored with a debug log, per the open question in Validate SEP-2243 Mcp-Param-{Name} headers in the modern server #1199. Invalid means a name that is empty or not an RFC 9110 token, a type other than string/integer/boolean, or a case-insensitive duplicate.

How Has This Been Tested?

New and extended tests:

  • TransportParamsTests covers:
    • valid Base64, and invalid Base64 (padding, alphabet, UTF-8)
    • values that only resemble the sentinel
    • OWS trimming, and characters that required Base64
    • case-insensitive names and repeated headers
    • attach overriding a value forged by the extractor
  • McpParamHeadersTests: nested properties paths; annotations behind items/allOf/$ref/$defs ignored; invalid names, types and duplicates.
  • ToolsFeatureParamHeaderTests: one test per table row, each asserting the tool and inputSchema validation never ran on rejection. Also 42.0 vs 42, booleans, Base64 and literal values, NOT_MIRRORED skipping validation, and a missing key not skipping it.
  • StdioMcpTransportTests: stdio passes NOT_MIRRORED.
  • HttpServletMcpTransportIntegrationTests, end to end over Tomcat: matching header → 200; mismatched, missing or malformed header → 400 / -32020.

Results:

  • mvn test -pl mcp-core: 635 tests, 0 failures, 0 errors.
  • mvn test -pl mcp-test: 1036 tests, 0 failures, 1 skipped. All modern-server tests pass. There were 12 errors, all Testcontainers "Could not find a valid Docker environment" in legacy client tests, because Docker wasn't available locally.
  • Conformance with @modelcontextprotocol/[email protected] against conformance-tests/server-servlet-modern, with the new test_custom_header fixture:
    • --scenario http-custom-header-server-validation: 10/10 passed.
    • --requirements 2026-07-28: all 37 required scenarios pass, so no regressions. The only failures are the unscored tasks-* extension.

Breaking Changes

No public API is removed or changed. One behaviour change to be aware of: a custom transport or in-memory caller that passes an McpTransportContext without TransportParams (for example McpTransportContext.EMPTY) now gets -32020 when it calls a tool with an x-mcp-header argument value. This is deliberate: #1199 requires that a missing key must not skip validation. Such transports should attach TransportParams.NOT_MIRRORED, or the parsed headers, with TransportParams.attach(...). Tools without x-mcp-header are unaffected.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

  • A malformed header for a declared parameter is rejected even when the argument is absent, following the spec's "reject invalid characters".
  • A repeated Mcp-Param-X header counts as malformed.
  • Every case-insensitive duplicate definition is ignored, not just the later ones.
  • Numbers compare via BigDecimal, so 42, 42.0 and 4.2e1 all match.
  • Out of scope: the existing Mcp-Name decoder still accepts unpadded Base64.
  • Docs: VALIDATION_RESULTS.md moves the scenario to Passing and narrows Known Limitation Update the License #2 to "definitions aren't enforced at registration/listing". The server-servlet-modern README lists the new fixture.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
@prathamgoyal787
feat: validate SEP-2243 Mcp-Param headers in modern server
d9c8bdf
HttpServletMcpTransport collects every Mcp-Param-* header into
TransportParams (case-insensitive names, =?base64?...?= decoding,
malformed values flagged rather than failing) and attaches it to the
McpTransportContext after the user's contextExtractor, so the extractor
can neither drop nor forge it. StdioMcpTransport declares NOT_MIRRORED;
a context without params counts as a request with no headers.

ToolsFeature checks, after find and before inputSchema validation, every
x-mcp-header parameter reachable through properties: a present argument
needs a matching header (integers compared numerically, booleans as
true/false), a null or absent argument expects none, malformed headers
of declared parameters are rejected and undeclared headers are ignored.
Rejections fail with -32020 (HEADER_MISMATCH), answered with 400 over
HTTP. Invalid x-mcp-header definitions are ignored with a debug log.

Adds the test_custom_header conformance fixture; the
http-custom-header-server-validation scenario now passes (10/10).

Closes modelcontextprotocol#1199
@prathamgoyal787 prathamgoyal787 closed this Oct 20, 2026
@prathamgoyal787 prathamgoyal787 reopened this Oct 20, 2026
prathamgoyal787 and others added 2 commits October 20, 2026 18:55
@prathamgoyal787
Merge branch 'main' into feat/sep-2243-mcp-param-validation
4191ce3
@prathamgoyal787
Merge branch 'main' into feat/sep-2243-mcp-param-validation
b8b9492
Move ToolsFeatureParamHeaderTests to mcp-test with the other modern
server tests that rely on JSON serialization (modelcontextprotocol#1215), using the default
mapper instead of Gson.
This was referenced Oct 24, 2026
Add McpServerTool shortcuts for registering tools on the modern server #1271
Closed
Simplify registering tools, resources and prompts on the modern server #1200
Open
@pma1999 pma1999 mentioned this pull request Oct 24, 2026
Validate x-mcp-header in tool input schema #1269
Open
@prathamgoyal787
Merge branch 'main' into feat/sep-2243-mcp-param-validation
ed2e558
Adapt to find returning the tool with its handler (modelcontextprotocol#1282): validate the
Mcp-Param headers against the found tool's definition, after the
required-capabilities check and before inputSchema validation, and port
the tests to McpAsyncTool.
@prathamgoyal787

prathamgoyal787 commented Oct 31, 2026

Copy link
Copy Markdown
Author

Hi @Kehrlann, I saw you picked up #1199. This PR implements it (closes #1199) and is up to date with main, including the find change from #1282. Could you approve the CI run when you get a chance? Happy to rework anything if you had a different approach in mind.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Kehrlann

Kehrlann commented Oct 31, 2026

Copy link
Copy Markdown
Contributor

Hey @prathamgoyal787

This is too big for us to review and interact over in GitHub. We need tighter feedback loops and will be implementing it internally.

Closing as superseded by #1286

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

@Kehrlann Kehrlann closed this Oct 31, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

No reviews

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Validate SEP-2243 Mcp-Param-{Name} headers in the modern server

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@prathamgoyal787 @Kehrlann
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.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.