You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
When a tool handler returns unstructured content for an error case, the low-level server's call_tool decorator validates the output against outputSchema before checking if the response is an error.
This prevents tools with outputSchema from reporting errors via isError: true, as the validation fails with "outputSchema defined but no structured output returned", replacing the original error message.
This was already fixed in the TypeScript SDK via modelcontextprotocol/typescript-sdk#654 / PR #655 (2025-06-24), but the equivalent fix has not been applied to the Python SDK v1.x branch.
The issue is in src/mcp/server/lowlevel/server.py, the call_tool decorator handler:
Line ~560: outputSchema validation runs unconditionally — should skip when the result is an error
Line ~575: isError=False is hardcoded — there is no path for the handler to signal an error through unstructured content while outputSchema is defined
Example Code
frommcp.server.lowlevelimportServerfrommcpimporttypesserver=Server("test")
@server.call_tool()asyncdefcall_tool(name: str, arguments: dict):
# Tool has outputSchema but needs to return an error# This gets blocked by outputSchema validationreturn [types.TextContent(type="text", text="Resource not found")]
Fix at src/mcp/server/mcpserver/utilities/func_metadata.py:106 — gate the output_model.model_validate(...) call on not result.is_error, matching the TypeScript SDK's resolution in typescript-sdk#655.
Regression test mirroring that PR: register a tool with output_schema, return CallToolResult(is_error=True), assert the unstructured error content reaches the client unmodified.
v1.x backport as a follow-up PR (src/mcp/server/fastmcp/utilities/func_metadata.py:115, same change with the v1.x camelCase fields).
One thing I noticed but think is out of scope for this issue — src/mcp/client/session.py:336 has the same pattern client-side: it raises RuntimeError("Tool ... has an output schema but did not return structured content") without first checking result.is_error. Different surface, same bug shape. Happy to file a separate issue once this PR is in.
Activity
fix(server): allow tools with outputSchema to surface errors via unst…
fix: skip output schema validation when tool returns is_error=True
fix: skip output schema validation when tool returns isError=True
fix: skip output schema validation when tool returns is_error=True
fix: skip output schema validation when tool returns isError=True
fix: skip output schema validation when tool returns isError=True
fix: skip output schema validation when tool returns is_error=True
RanjithHiremath commentedon Apr 26, 2026
Hi, would like to take this one. Plan:
src/mcp/server/mcpserver/utilities/func_metadata.py:106— gate theoutput_model.model_validate(...)call onnot result.is_error, matching the TypeScript SDK's resolution in typescript-sdk#655.output_schema, returnCallToolResult(is_error=True), assert the unstructured error content reaches the client unmodified.src/mcp/server/fastmcp/utilities/func_metadata.py:115, same change with the v1.x camelCase fields).One thing I noticed but think is out of scope for this issue —
src/mcp/client/session.py:336has the same pattern client-side: it raisesRuntimeError("Tool ... has an output schema but did not return structured content")without first checkingresult.is_error. Different surface, same bug shape. Happy to file a separate issue once this PR is in.