mcp: a property with an array "type" (any pointer field from jsonschema.For) disables x-mcp-header handling for the whole tool
I maintainer di solito rispondono entro 1 giorno
@jay23606 ci sta già lavorando.
Dal 16/10/2026.
Valutazione
- Difficoltà
- 3/5
- Tempo stimato
- 1-2 giorni
- Idoneità per principianti
- 50/100
Direzione di ricerca
Start in mcp/streamable_headers.go: headerSchemaProperty decodes type as a string, so an array or boolean subschema makes unmarshalSchemaProperties return nil for the whole tool. Read validateParamHeaderAnnotations and the two tests named in the issue, TestExtractToolParamHeaders and TestValidateToolParamHeaders. Done when a property with an array or boolean schema no longer disables annotations on other properties, and an annotated nullable property is rejected with the existing primitive-types error, as the issue proposes. The maintainers still need to decide the nullable case.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Descrizione
Describe the bug
headerSchemaProperty (mcp/streamable_headers.go) decodes type into a string. JSON Schema also allows an array there, and jsonschema.For emits one for every pointer field ("type": ["null", "string"]). When any property in a tool's inputSchema has an array type, the remarshal in unmarshalSchemaProperties fails and returns nil. The client and server then treat the tool as having no x-mcp-header annotations at all, even on other properties:
- The client sends no
Mcp-Param-*headers for the tool. A server that validates them, as the 2026-07-28 spec requires, answers withHeaderMismatch. - The server skips
validateParamHeaders, so a request whoseMcp-Param-*header contradicts the body is accepted. validateParamHeaderAnnotationsreturns nil without checking anything, soAddTooland the client'stools/listfilter also accept an invalid annotation, such as one on anumberproperty.
A boolean subschema ("properties": {"extra": true}) fails the same way.
To Reproduce
A typed tool with an annotated region and an optional *string field, served over Streamable HTTP and called by the go-sdk client on 2026-07-28 (go run . with a replace to the checkout):
type withOptionalIn struct {
Region string `json:"region"`
Query string `json:"query"`
Note *string `json:"note,omitempty"` // inferred as "type": ["null", "string"]
}
s, _ := jsonschema.For[withOptionalIn](nil)
s.Properties["region"].Extra = map[string]any{"x-mcp-header": "Region"}
mcp.AddTool(server, &mcp.Tool{Name: "with_optional", InputSchema: s}, handler)
The full program registers this tool next to an identical plain tool without Note. The program serves both tools with NewStreamableHTTPHandler (stateless, TTLMs set so the client caches tools/list). It calls each tool with {"region": "eu", "query": "q"} and records the outgoing headers in a RoundTripper. Then it calls each tool again with Mcp-Param-Region overwritten to forged:
plain client sent Mcp-Param-Region="eu", call err=<nil>
with_optional client sent Mcp-Param-Region="", call err=<nil>
plain header forged to "forged" (body region=eu): call err=... header mismatch: Mcp-Param-Region header value 'forged' does not match body value: rejected by transport: Bad Request
with_optional header forged to "forged" (body region=eu): call err=<nil>
The only difference between the two tools is the extra optional field.
Expected behavior
with_optional behaves like plain: the client sends Mcp-Param-Region: eu, and the server rejects the forged header.
Proposed fix
In headerSchemaProperty, keep type as a json.RawMessage. Give the struct an UnmarshalJSON that turns true/false into an empty property, so each property decodes independently. An annotated property must still have a single primitive type. A nullable annotated property (["null", "string"]) is rejected with the existing "primitive types" error, like the TypeScript SDK's check (typeof schema.type === 'string'). The change is about 20 lines, plus table cases in TestExtractToolParamHeaders and TestValidateToolParamHeaders. If you'd rather accept ["null", <primitive>] on annotated properties (both header paths already skip null arguments), that is a small change.
The new cases fail on main and pass with the patch. With the patch, the repro output matches for both tools. go test ./..., go vet ./..., gofmt -l . and staticcheck 2026.2.2 are clean. I couldn't run v0.6.1, the CI version, because it can't read Go 1.27 export data. This is separate from #1250 / #1341, which covers annotations in positions that are not reachable through properties.
If you're happy with this direction, I can open the PR.
Additional context
- Go MCP SDK:
mainat 9012a21 go version go1.27.0 windows/amd64
This report and the patch were written with Claude Code (AI-assisted). I ran the repro and the tests above on my machine.
- Lingua principale
- Go
- Stelle
- 5.2k
- Fork
- 583
- Merge medio
- 2g 1h
- PR unite (30g)
- 55
Preparare l'ambiente
Avvia il container di sviluppo del progetto nel browser, con il tuo account GitHub.
- Nessun Dockerfile né file Docker Compose
- Ha un modello di pull request
- Leggi la guida per i contributori
Come iniziare
- Leggi tutta la issue e poi la guida ai contributi del progetto.
- Commenta sulla issue per dire che te ne occupi tu — evita che due persone facciano lo stesso lavoro.
- Fai un fork del repository e lavora su un branch.
- Apri una pull request che faccia riferimento al numero della issue.
Altre issue di modelcontextprotocol/go-sdk
-
Session-lifecycle bookkeeping logs at info, spamming multiple log lines per request on stateless streamable HTTPForse già presa @anneheartrecord l’ha presa 51 giorni fa. ApertaP3
Difficoltà 2/5 1-3 ore Idoneità per principianti 75/100
modelcontextprotocol/go-sdk#1204 · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
Expose generic `SendNotification` on `ServerSession` for custom protocol extensionsForse già presa @ajuijas l’ha presa 217 giorni fa. Apertaneeds investigation
Difficoltà 2/5 1-3 ore Idoneità per principianti 72/100
modelcontextprotocol/go-sdk#745 · 13 commenti · 1 reazione ·
I maintainer di solito rispondono entro 1 giorno
-
jsonrpc: decimal and exponent integer IDs still lose precision after #1401Forse già presa @skosovsky l’ha presa 2 giorni fa. Aperta
Difficoltà 3/5 1-2 giorni Idoneità per principianti 25/100
modelcontextprotocol/go-sdk#1404 · 2 commenti ·
I maintainer di solito rispondono entro 1 giorno
-
mcp: rejected request IDs receive no JSON-RPC error envelopeForse già presa @skosovsky l’ha presa 5 giorni fa. Aperta
Difficoltà 4/5 1-2 giorni Idoneità per principianti 68/100
modelcontextprotocol/go-sdk#1391 ·
I maintainer di solito rispondono entro 1 giorno
-
auth: Authorize fails against a 2025-03-26 server whose URL has a query stringForse già presa @nahapetyan-serob l’ha presa 4 giorni fa. Aperta
Difficoltà 2/5 1-3 ore Idoneità per principianti 40/100
modelcontextprotocol/go-sdk#1347 · 1 assegnatario ·
I maintainer di solito rispondono entro 1 giorno
Tutte le issue di modelcontextprotocol/go-sdk
Issue simili
-
agent-butler-finding chore
Difficoltà 1/5 Meno di un'ora Idoneità per principianti 90/100
jordansmall/spindrift#5575 ·
I maintainer di solito rispondono entro 1 giorno
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 88/100
open-telemetry/opentelemetry-go-compile-instrumentation#1512 ·
I maintainer di solito rispondono entro 3 giorni
-
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
JakeChampion/lang#12684 ·
I maintainer di solito rispondono entro 1 giorno
-
goose sub-agent runs are never indexed: blame finds no session for any file a `delegate` child wroteApertabug
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
I maintainer di solito rispondono entro 1 giorno
-
C-bug O-community X-blathers-triaged
Difficoltà 2/5 1-3 ore Idoneità per principianti 78/100
cockroachdb/cockroach#176150 · 1 commento ·
I maintainer di solito rispondono entro 12 giorni