Skip to content

Client treats JSON-null structuredContent as missing, skipping outputSchema validation #3345

Description

@epistemedeus

Initial Checks

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:

  1. omitted structuredContent (field absent)
  2. 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 content and never runs jsonschema against the value.

What I expected

  • Omitted structuredContent still 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 is is None rather 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 main at 57394b0548d1e2dc2dce8d67d84985769df3b8bb (2.x)

Metadata

Metadata

Assignees

No one assigned

    Labels

    spec-2026-07-28Concerns the SDK's implementation of the 2026-07-28 MCP spec revisionv2Affects the v2 line (2.x on main)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions