Skip to content

mcp: reject null titled enum entries in elicitation schemas - #1447

Open
jyotir-aditya wants to merge 1 commit into
modelcontextprotocol:mainfrom
jyotir-aditya:fix-nonum-elicit-null-entry
Open

jyotir-aditya wants to merge 1 commit into
modelcontextprotocol:mainfrom
jyotir-aditya:fix-nonum-elicit-null-entry

Conversation

@jyotir-aditya

@jyotir-aditya jyotir-aditya commented Oct 24, 2026 •

Copy link
Copy Markdown
Contributor

validateTitledEnumEntry dereferenced entry.Const without checking entry for nil. A JSON null inside oneOf (single-select) or anyOf (multi-select) unmarshals to a nil *jsonschema.Schema, so a client with an ElicitationHandler panicked while validating the elicitation/create request, before the handler ran.

The function now returns an error for a nil entry. The client then answers -32602 like it does for other invalid elicitation schemas.

The panic predates #1312 (the check was added in v1.4.0), but #1312 also routes "type": "string" items with anyOf through the same check, so that shape now reaches it too.

ServerSession.Elicit calls the same validateElicitSchema on the schema it sent once the client accepts, so a server that sends a nil entry would also panic there when paired with a client that doesn't validate the request. This only applies to sessions below protocol 2026-07-28; later versions refuse server-initiated elicitation. I confirmed this with a throwaway test (a client middleware that returns "accept"): without the guard it panics at server.go:1842, and with it Elicit returns an error.

Tests

Two cases added to TestElicitationSchemaValidation (oneOf: [null] and items.anyOf: [null]), both expecting CodeInvalidParams. On main they panic with a nil pointer dereference; with this change they pass. gofmt -l ., go vet ./... and go test ./... are clean.

@chrikrah chrikrah left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the guard removed and the two new cases kept, go test ./mcp -run TestElicitationSchemaValidation panics in client.go; with it, both pass. Both loops reach validateTitledEnumEntry, so from my perspective this can be merged.

ServerSession.Elicit runs the same validateElicitSchema after an accept (server.go:1842), so by reading the code a Go server sending a nil entry panics there too once a non-Go client accepts. Worth a sentence in the commit message, which names only the client?

validateTitledEnumEntry dereferenced entry.Const without checking
entry for nil. A JSON null inside oneOf (single-select) or anyOf
(multi-select) unmarshals to a nil *jsonschema.Schema, so the client
panicked while validating an elicitation/create request.

ServerSession.Elicit runs the same validateElicitSchema on the schema
it sent once the client accepts, so a server passing a nil entry could
panic there too.

Return an invalid-params error instead, as for other invalid schemas,
and add oneOf and anyOf regression cases to
TestElicitationSchemaValidation.
@jyotir-aditya
jyotir-aditya force-pushed the fix-nonum-elicit-null-entry branch from 7dddae9 to 3d4a82e Compare October 26, 2026 00:56
@jyotir-aditya

Copy link
Copy Markdown
Contributor Author

Thanks for checking. I confirmed the server path too. With a client that accepts without validating (a middleware stand-in for a non-Go client), ServerSession.Elicit panics at server.go:1842 without the guard and returns titled enum entries must be objects with it. That only applies below protocol 2026-07-28, since later versions refuse server-initiated elicitation. The single guard in validateTitledEnumEntry covers both paths, so there's no code change. I've added a sentence to the commit message and the PR description. I can add a server-side regression test if a maintainer wants one.

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.

2 participants