Skip to content

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

Closed
SAY-5 wants to merge 2 commits into
modelcontextprotocol:v1.xfrom
SAY-5:fix/lowlevel-tool-error-with-outputschema
Closed

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

Conversation

@SAY-5

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

Copy link
Copy Markdown

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

SAY-5 commented Apr 27, 2026 •

Copy link
Copy Markdown
Author

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.

@maxisbey

maxisbey commented Oct 5, 2026

Copy link
Copy Markdown
Contributor

Thanks for the PR, and sorry it sat here without a proper review. The 1.x line only takes critical and security fixes now, and this one is below that bar.

We're closing most of the open PR backlog. v2 is out and changed a lot of the SDK, so many older PRs no longer apply as written, and we're a small team that realistically doesn't have the capacity to work through the rest.

If this still matters to you on v2, the most useful thing you can do is open an issue (or comment on the existing one) with your use case and a repro. Hearing why it matters to you is what we use to decide what to prioritise.

AI Disclaimer

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.

2 participants