modelcontextprotocol / modelcontextprotocol/python-sdk
Client treats JSON-null structuredContent as missing, skipping outputSchema validation
Nobody has claimed this yet.
- Dominant language
- Python
- Stars
- 24.3k
- Forks
- 4k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 31
Description
Initial Checks
- I confirm that I'm using the newest release of my line (the latest 2.x, or the latest 1.x if I'm still on v1)
- I confirm that I searched for my issue in https://github.com/modelcontextprotocol/python-sdk/issues before opening this issue
Release line
2.x (current stable)
Description
On current main (57394b0548d1e2dc2dce8d67d84985769df3b8bb), ClientSession.validate_tool_result treats structured_content is None as "the tool did not return structured content".
That collapses two different wire shapes:
- omitted
structuredContent(field absent) - explicit JSON
null("structuredContent": null)
SEP-2106 / spec 2026-07-28 allow structuredContent to be any JSON value, including null. The TypeScript SDK already checks === undefined (not falsy / not null) for this reason.
Pydantic stores both omitted and JSON null as None. model_fields_set distinguishes them: a CallToolResult parsed from {"content": [], "structuredContent": null} has "structured_content" in model_fields_set, while an omitted field does not.
What happens today
- Tool advertises
"outputSchema": {"type": "null"}(or{"type": ["object", "null"], ...}). - Server returns
"structuredContent": null. - Client raises
Tool {name} has an output schema but did not return structured contentand never runs jsonschema against the value.
What I expected
- Omitted
structuredContentstill raises the existing missing-field error. - Explicit JSON null is validated against the advertised schema: accept if the schema allows null, reject as a schema mismatch if it does not.
- Falsy JSON values (
0,false,"") stay validated (they already are, because the current check isis Nonerather than falsy).
This is not #3224 (server injecting nulls for NotRequired keys). That issue is about serializing omitted object keys as null. This one is the client presence check before outputSchema validation.
I hit this while checking official SDK conformance of declared outputSchema against structuredContent. I have a small backwards-compatible test and fix ready and would like to send the PR if a maintainer wants it.
AI assistance: researched and drafted with Grok 4.6; I reviewed the spec text, the TypeScript v2 presence check, and the Pydantic model_fields_set behavior before filing.
Example Code
from mcp_types import CallToolResult
omitted = CallToolResult.model_validate({"content": []})
explicit_null = CallToolResult.model_validate({"content": [], "structuredContent": None})
assert omitted.structured_content is None
assert explicit_null.structured_content is None
assert "structured_content" not in omitted.model_fields_set
assert "structured_content" in explicit_null.model_fields_set
Against a tool whose outputSchema is {"type": "null"}, validate_tool_result currently raises the missing-field RuntimeError for explicit_null. After a presence check that uses model_fields_set, that result validates.
Python & MCP Python SDK
- Python 3.12
- MCP Python SDK
mainat57394b0548d1e2dc2dce8d67d84985769df3b8bb(2.x)
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start at ClientSession.validate_tool_result and inspect how CallToolResult.model_fields_set distinguishes omitted structuredContent from explicit JSON null. Add or update a focused validation test for an outputSchema allowing null, while preserving the missing-field error for omitted content; run the relevant SDK test suite to confirm schema mismatches still fail.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- python
- Domain
- api
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 75/100