Skip to content

fix(server): allow tools with outputSchema to surface errors via unstructured content#2447

Open
SAY-5 wants to merge 2 commits intomodelcontextprotocol:v1.xfrom
SAY-5:fix/lowlevel-tool-error-with-outputschema
Open

fix(server): allow tools with outputSchema to surface errors via unstructured content#2447
SAY-5 wants to merge 2 commits intomodelcontextprotocol:v1.xfrom
SAY-5:fix/lowlevel-tool-error-with-outputschema

Conversation

@SAY-5
Copy link
Copy Markdown

@SAY-5 SAY-5 commented Apr 15, 2026

Per #2429, a low-level tool with an outputSchema cannot return a tool-execution failure (e.g. "Resource not found") via unstructured TextContent because the call_tool decorator unconditionally validates the result against outputSchema and replaces the original error message with a hard "outputSchema defined but no structured output returned" error.

This PR mirrors the TypeScript SDK fix in modelcontextprotocol/typescript-sdk#655: when an outputSchema-bound tool returns no structured content, treat the unstructured payload as a tool-error result (isError=True) instead of replacing it. Tools that do return structured output keep their existing validation contract, and the explicit CallToolResult-returning path is unchanged.

Closes #2429

SAY-5 added 2 commits April 14, 2026 23:07
…ructured content

Per modelcontextprotocol#2429, a low-level tool with an `outputSchema` cannot return a
tool-execution failure (e.g. "Resource not found") via unstructured
`TextContent` because the call_tool decorator unconditionally validates
the result against `outputSchema` and replaces the original error
message with a hard "outputSchema defined but no structured output
returned" error.

Mirror the TypeScript SDK fix (modelcontextprotocol/typescript-sdk#655):
when an outputSchema-bound tool returns no structured content, treat
the unstructured payload as a tool-error result (`isError=True`)
instead of replacing it. Tools that *do* return structured output keep
their existing validation contract, and the explicit
`CallToolResult`-returning path is unchanged.

Github-Issue:modelcontextprotocol#2429
…w behavior

CI flagged that the existing test_content_only_with_output_schema_error
asserted the old contract (replace tool output with a generic
'outputSchema validation' message). This PR's whole point is to NOT
do that, so the assertion was guaranteed to flip.

Renames the test to test_content_only_with_output_schema_surfaces_error
and updates assertions to verify the new contract:
- isError = True (so callers can branch on it)
- the tool's original unstructured TextContent payload is preserved
  verbatim (so callers see the tool's own error message, e.g.
  'Resource not found', instead of a generic SDK validation string)
- structuredContent stays None

Verified locally with `python -m pytest tests/server/test_lowlevel_output_validation.py` → 9 passed.

Signed-off-by: SAY-5 <say.apm35@gmail.com>
@SAY-5
Copy link
Copy Markdown
Author

SAY-5 commented Apr 27, 2026

Pushed 5239245 updating test_content_only_with_output_schema_error (now renamed *_surfaces_error) to assert the new contract — isError=True plus the tool's original unstructured TextContent preserved verbatim. pytest tests/server/test_lowlevel_output_validation.py runs all 9 cases green locally.

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.

1 participant