Repository navigation
Client treats JSON-null structuredContent as missing, skipping outputSchema validation #3345
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_setAgainst 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)
Activity
lucianoon commentedon Aug 27, 2026
I'd like to take this one if it's still open.
I've confirmed the diagnosis on
main(6705402):validate_tool_resultkeys themissing-structured-content check on
result.structured_content is None, whichcannot distinguish an omitted
structuredContentfrom an explicit JSONnull—pydantic stores both as
None, and onlymodel_fields_setseparates them.My plan is the narrow fix you describe:
"structured_content" in result.model_fields_set, matchingthe
=== undefinedline the TypeScript SDK draws;nullgoes through the compiled validator, so it's accepted when theadvertised schema allows null and reported as a schema mismatch when it doesn't.
One note for whoever reviews it: servers built on this SDK can't produce the
explicit-null shape at all, because outbound results are dumped with
exclude_none=Trueinmcp/shared/peer.py. So the tests have to parseCallToolResultfrom a wire payload rather than construct it — constructing themodel can't express the distinction. That also means the change is inert for
in-SDK servers and only affects sessions with peers that do send
null.The change and three tests are ready and pushed, if it's useful to look before
deciding:
https://github.com/lucianoon/mcp-python-sdk/tree/fix/structured-content-explicit-null
The two explicit-null tests fail without the fix and pass with it; the third pins
the omitted-field behaviour so it can't drift. Locally:
ruff check,ruff format --checkandpyright(strict) clean on both touched files, thechanged lines fully covered with no new
no coverpragmas, and the full suiteshows no new failures.
Happy to open the PR as soon as you assign me — I understand the intake gate
closes it otherwise.
Disclosure: I used an AI coding agent to write the patch and the tests. I ran
the reproduction and the suite myself and can explain the change.
Alqudimi commentedon Aug 27, 2026
I reproduced this against current
main(6705402e246dc4eb1fcdf4d9902b78d3c9c36e1b). An explicitly suppliedstructuredContent: nullhasstructured_contentinmodel_fields_set, while an omitted field does not; both currently raiseTool nullable has an output schema but did not return structured contentbefore JSON Schema validation runs.I would keep the fix narrow in
ClientSession.validate_tool_result: use field presence for the missing-content check, then let the existing validator accept or reject the explicit JSONnullaccording tooutputSchema. I would add focused regression coverage for an explicit null accepted by {"type": "null"}, an explicit null rejected by an object schema, and an omitted field retaining the existing missing-content error. This should not require a public API, dependency, or protocol change.I used AI assistance while inspecting the code and preparing this reproduction, and I am accountable for verifying the behavior and any resulting patch. If this direction matches the intended contract, I would appreciate assignment before opening a PR.
maxisbey commentedon Oct 2, 2026
#3621 fixes this with the same
model_fields_setcheck you proposed in #3346, so thank you for both the report and the approach.An explicit null
structuredContentis now validated against the tool'soutputSchema, and only an absent field counts as missing.If your case still isn't covered, feel free to open a new issue.
AI Disclaimer