Skip to content

fix(transport): skip outputSchema validation for isError tool responses#4136

Open
kimsehwan96 wants to merge 1 commit intoIBM:mainfrom
kimsehwan96:fix/skip-output-validation-on-iserror
Open

fix(transport): skip outputSchema validation for isError tool responses#4136
kimsehwan96 wants to merge 1 commit intoIBM:mainfrom
kimsehwan96:fix/skip-output-validation-on-iserror

Conversation

@kimsehwan96
Copy link
Copy Markdown
Contributor

@kimsehwan96 kimsehwan96 commented Apr 13, 2026

🔗 Related Issue

Closes #4135


📝 Summary

When an upstream MCP tool with outputSchema defined returns an error (isError: true) without structuredContent, the MCP Python SDK's server-side validation replaces the original error message with a generic "outputSchema defined but no structured output returned".

This hides the actual error cause from the user.

This PR bypasses the SDK validation by returning a CallToolResult(isError=True) directly when is_error is True, which triggers the SDK's early-return path and skips outputSchema validation. This uses the same pattern already established in the codebase (lines 1451, 1468).

The root cause is in the MCP Python SDK v1.x (mcp/server/lowlevel/server.py), where outputSchema validation runs unconditionally regardless of isError.


🏷️ Type of Change

  • Bug fix
  • Feature / Enhancement
  • Documentation
  • Refactor
  • Chore (deps, CI, tooling)
  • Other (describe below)

🧪 Verification

Check Command Status
Lint suite make lint pass
Unit tests make test pass
Coverage ≥ 80% make coverage pass

✅ Checklist

  • Code formatted (make black isort pre-commit)
  • Tests added/updated for changes
  • Documentation updated (if applicable)
  • No secrets or credentials committed

📓 Notes (optional)

Implementation detail

The fix is placed after the structuredContent check in streamablehttp_transport.py:call_tool():

  1. if structured → return (unstructured, structured) # SDK validates against outputSchema
  2. if is_error is True → return CallToolResult(isError=True) # SDK early-return, no validation
  3. return unstructured # normal path

This ordering is intentional: if an error response does include structuredContent, the existing validation path is preserved. We have not observed any MCP server returning both isError: true and structuredContent simultaneously, and the MCP spec does not define this combination. If it does occur, validating the structured content is arguably the correct behavior — the server explicitly provided it, so schema conformance should be checked.

is_error is True (strict identity check)

We use getattr(result, "is_error", None) with is True rather than a truthy check. This prevents false positives when result is a MagicMock in unit tests (where unset attributes return truthy MagicMock objects).

Manual E2E verification

To validate this fix end-to-end, we added a lookup_calculation tool to the existing output_schema_test_server that raises ToolError for unknown IDs (producing isError: true with outputSchema defined). Using the docker-compose stack:

  • Before fix: "Output validation error: outputSchema defined but no structured output returned" ❌
  • After fix: "Calculation 'nonexistent-id' not found. Only 'calc-001' is available." ✅

The test server change is not included in this PR — unit tests provide sufficient coverage for the transport-layer logic. The E2E setup can be formalized in a follow-up if needed.

When an upstream MCP tool returns an error (isError: true) without
structuredContent, the MCP Python SDK's server-side outputSchema
validation replaces the original error message with a generic
"outputSchema defined but no structured output returned" error.

This bypasses the SDK validation by returning a CallToolResult directly
when is_error is True, using the same pattern already established in
the codebase (lines 1451, 1468).

Closes IBM#4135

Signed-off-by: kimsehwan96 <sktpghks138@gmail.com>
@kimsehwan96 kimsehwan96 force-pushed the fix/skip-output-validation-on-iserror branch from bfb154d to 5482207 Compare April 13, 2026 01:16
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.

[BUG]: outputSchema validation not skipped for isError:true tool results, hiding actual error messages

1 participant