Skip to content

mcp: don't let an array or boolean property schema hide x-mcp-header annotations - #1408

Open
jay23606 wants to merge 2 commits into
modelcontextprotocol:mainfrom
jay23606:fix/param-header-type-arrays
Open

jay23606 wants to merge 2 commits into
modelcontextprotocol:mainfrom
jay23606:fix/param-header-type-arrays

Conversation

@jay23606

Copy link
Copy Markdown
Contributor

Fixes #1406

What was broken

headerSchemaProperty decoded each property's type as a plain string. JSON Schema also allows type to be an array, and jsonschema.For emits "type": ["null", "string"] for every pointer field. A boolean subschema ("extra": true) is also valid JSON Schema.

When any property in a tool's inputSchema had one of these shapes, decoding the whole schema failed and the SDK silently treated the tool as having no x-mcp-header annotations at all, including on properties that were correctly annotated. The visible effects:

  • The client sent no Mcp-Param-* headers for the tool, so a server that validates them rejects the call with HeaderMismatch.
  • The server skipped validateParamHeaders, so a request whose Mcp-Param-* header contradicted the body was accepted.
  • Invalid annotations (for example on a number property) were not reported by AddTool or the client's tools/list filter.

What changed

headerSchemaProperty now has its own UnmarshalJSON, so each property decodes independently:

  • A non-string type is kept as its raw JSON text. It therefore still fails the existing primitive-type check, so an annotated nullable property (["null", "string"]) is still rejected, as before.
  • A boolean subschema decodes to an empty property with no annotations.

The change is confined to mcp/streamable_headers.go. No exported API changes.

How it was tested

  • Added regression cases to TestExtractToolParamHeaders (an array-typed sibling and a boolean subschema must not hide an annotated property) and to TestValidateToolParamHeaders (an invalid annotation next to an array-typed or boolean sibling must be reported, and a nullable annotated property must be rejected). All five new cases fail on the unmodified code and pass with this change.
  • go test ./mcp/... passes, go vet ./mcp/ is clean, and the touched files are gofmt-clean.

This patch was prepared with AI assistance (Claude Code). The failure mode and the test cases were checked by hand against the code paths listed above.

🤖 Generated with Claude Code

jay23606 and others added 2 commits October 16, 2026 10:18
…annotations

headerSchemaProperty decoded every property's "type" as a string. JSON
Schema allows an array there, and jsonschema.For emits ["null", T] for
pointer fields. One such property made the remarshal of the whole
inputSchema fail, so the tool was treated as having no x-mcp-header
annotations at all: clients sent no Mcp-Param-* headers and servers
skipped header validation for it. A boolean subschema had the same effect.

Decode each property leniently. A non-string type is kept as its raw
JSON text, so an annotated nullable property is still rejected by the
primitive-type check.

Fixes modelcontextprotocol#1406

Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com>
Signed-off-by: jay23606 <4602056+jay23606@users.noreply.github.com>

This branch has not been deployed

No deployments
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.

mcp: a property with an array "type" (any pointer field from jsonschema.For) disables x-mcp-header handling for the whole tool

1 participant