Skip to content

fix(client): validate JSON-null structuredContent against outputSchema - #3346

Draft
epistemedeus wants to merge 1 commit into
modelcontextprotocol:mainfrom
epistemedeus:grok/outputschema-null-structured-content-20260820
Draft

fix(client): validate JSON-null structuredContent against outputSchema#3346
epistemedeus wants to merge 1 commit into
modelcontextprotocol:mainfrom
epistemedeus:grok/outputschema-null-structured-content-20260820

Conversation

@epistemedeus

Copy link
Copy Markdown

Fixes #3345

SEP-2106 allows structuredContent to be JSON null. validate_tool_result treated structured_content is None as a missing field, so a tool that advertised a null-capable outputSchema and returned "structuredContent": null never reached jsonschema validation.

Pydantic stores both omitted and explicit JSON null as None. This uses model_fields_set as the presence check, matching the TypeScript SDK's === undefined (not null / not falsy) check.

Motivation and Context

Declared outputSchema was not validated against a legal JSON-null structuredContent value. Clients rejected a conforming result as missing instead of schema-checking it. Omitted structuredContent still fails closed.

How Has This Been Tested?

uv run --frozen pytest tests/client/test_session_promotions.py tests/interaction/lowlevel/test_tools.py::test_declared_output_schema_with_no_structured_content_is_rejected_by_the_client tests/interaction/lowlevel/test_tools.py::test_call_tool_structured_content_violating_output_schema_is_rejected_by_the_client -q

24 passed, including new cases for:

  • explicit JSON null against {"type": "null"} (accept)
  • explicit JSON null against an object schema (schema mismatch, not missing)
  • omitted field (existing missing-field error)
  • falsy non-null values 0 / false

Breaking Changes

None. Omitted structuredContent still raises the same RuntimeError. Only an explicit JSON null is now schema-validated.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I am assigned to the linked issue (or it is labeled help wanted, or I'm a maintainer)
  • I have disclosed any AI assistance and can explain the change in my own words
  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

Additional context

Not assigned on #3345. Opening as a draft per the small-fix-with-tests shape; CONTRIBUTING may auto-close until a maintainer assigns the issue. Reporter of #3345.

AI assistance: researched and implemented with Grok 4.6; I reviewed the spec text, the TypeScript v2 presence check, Pydantic model_fields_set on parsed CallToolResult, and the new tests.

No protocol change. No new schema surface. Does not duplicate the existing jsonschema check; it only stops the presence check from swallowing JSON null before that check runs.

SEP-2106 allows structuredContent to be JSON null. The client presence
check used `is None`, which also matches an omitted field, so a tool
that advertised a null-capable outputSchema and returned null was
rejected as missing structured content.

Use model_fields_set so omitted still fails closed, explicit null is
schema-validated, and falsy JSON values (0, false, "") stay checked.

Fixes modelcontextprotocol#3345
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.

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

1 participant