Skip to content

mcp: keep x-mcp-header handling working next to type arrays - #1410

Open
RafalOfficial wants to merge 1 commit into
modelcontextprotocol:mainfrom
RafalOfficial:fix/param-header-type-arrays
Open

RafalOfficial wants to merge 1 commit into
modelcontextprotocol:mainfrom
RafalOfficial:fix/param-header-type-arrays

Conversation

@RafalOfficial

Copy link
Copy Markdown

headerSchemaProperty decoded type into a string. One property with an array type (such as the ["null", "string"] that jsonschema.For infers for a pointer field) or a boolean subschema made decoding of the whole inputSchema fail. The client then sent no Mcp-Param-* headers for that tool, the server skipped validating them, and validateParamHeaderAnnotations accepted invalid annotations. Details and an end-to-end repro are in #1406.

This change keeps type as raw JSON and treats boolean subschemas as empty properties, so each property decodes on its own. An annotated property must still have a single primitive type; a nullable one (["null", "string"]) gets the existing "primitive types" error.

Tests: 5 new table cases in TestExtractToolParamHeaders and TestValidateToolParamHeaders, including one built with jsonschema.For and a pointer field. They fail on main and pass with this change. On Windows with Go 1.27, rebased on 3e9d812:

go build ./... && go vet ./... && gofmt -l .
go test ./...
go run honnef.co/go/tools/cmd/staticcheck@latest ./...   # 2026.2.2; CI's v0.6.1 can't read Go 1.27 export data

All pass and are clean.

Fixes #1406

This PR was written with Claude Code (AI-assisted).

🤖 Generated with Claude Code

headerSchemaProperty decoded "type" into a string, so one property
whose type is an array, such as the ["null", "string"] that
jsonschema.For infers for a pointer field, failed decoding of the whole
inputSchema. A boolean subschema did the same. The client then sent no
Mcp-Param-* headers for the tool, the server skipped validating them,
and validateParamHeaderAnnotations returned nil without checking any
annotation.

Keep "type" raw and accept boolean subschemas, so each property is
decoded on its own. An annotated property must still have a single
primitive type.

Fixes modelcontextprotocol#1406

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@RafalOfficial

Copy link
Copy Markdown
Author

Heads-up for reviewers: #1408 fixes the same issue (#1406). Pick whichever you prefer; if it's #1408, I'll close this one.

One difference I checked: #1408's UnmarshalJSON decodes with encoding/json, so the keys inside a property schema match case-insensitively. For a property {"TYPE": "string", "X-MCP-Header": "Region"}, extractParamHeaderAnnotations returns a Region binding on #1408 (db40f4d), and none on main (25f4880) or on this PR. The rest of streamable_headers.go decodes with internaljson, which has been case-sensitive since #807.

(Checked with a throwaway test, written with Claude Code.)

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