Skip to content

Commit b6029c4

Browse files
committed
fix: preserve FastMCP tool error results
1 parent 6213787 commit b6029c4

2 files changed

Lines changed: 18 additions & 2 deletions

File tree

src/mcp/server/fastmcp/utilities/func_metadata.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ def convert_result(self, result: Any) -> Any:
112112
the structured output.
113113
"""
114114
if isinstance(result, CallToolResult):
115-
if self.output_schema is not None:
115+
if self.output_schema is not None and not result.isError:
116116
assert self.output_model is not None, "Output model must be set if output schema is defined"
117117
self.output_model.model_validate(result.structuredContent)
118118
return result

tests/server/fastmcp/test_func_metadata.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
from pydantic import BaseModel, Field
1414

1515
from mcp.server.fastmcp.utilities.func_metadata import func_metadata
16-
from mcp.types import CallToolResult
16+
from mcp.types import CallToolResult, TextContent
1717

1818

1919
class SomeInputModelA(BaseModel):
@@ -878,6 +878,22 @@ def func_returning_annotated_tool_call_result() -> Annotated[CallToolResult, Per
878878
meta.convert_result(func_returning_annotated_tool_call_result())
879879

880880

881+
def test_tool_call_result_annotated_error_skips_structured_validation():
882+
class PersonClass(BaseModel):
883+
name: str
884+
885+
def func_returning_tool_error() -> Annotated[CallToolResult, PersonClass]: # pragma: no cover
886+
return CallToolResult(content=[TextContent(type="text", text="Division by zero")], isError=True)
887+
888+
meta = func_metadata(func_returning_tool_error)
889+
result = meta.convert_result(func_returning_tool_error())
890+
891+
assert isinstance(result, CallToolResult)
892+
assert result.isError is True
893+
assert result.structuredContent is None
894+
assert result.content[0].text == "Division by zero"
895+
896+
881897
def test_tool_call_result_in_optional_is_rejected():
882898
"""Test that Optional[CallToolResult] raises InvalidSignature"""
883899

0 commit comments

Comments
 (0)