diff --git a/src/fastmcp/tools/tool.py b/src/fastmcp/tools/tool.py index aac5f3e3d2..baa902471f 100644 --- a/src/fastmcp/tools/tool.py +++ b/src/fastmcp/tools/tool.py @@ -368,7 +368,7 @@ async def run(self, arguments: dict[str, Any]) -> ToolResult: def _is_object_schema(schema: dict[str, Any]) -> bool: - """Check if a JSON schema represents an object type, resolving $ref references.""" + """Check if a JSON schema represents an object type.""" # Direct object type if schema.get("type") == "object": return True @@ -377,40 +377,9 @@ def _is_object_schema(schema: dict[str, Any]) -> bool: if "properties" in schema: return True - # Resolve $ref references to check the referenced schema - # Self-referencing types (e.g., list["ReturnThing"]) generate schemas with $ref - # at the root level instead of "type": "object" directly - if "$ref" in schema: - ref = schema["$ref"] - if ref.startswith("#/$defs/"): - # Resolve reference within the same schema document - # The schema dict contains both $ref and $defs - defs_path = ref.replace("#/$defs/", "").split("/") - if "$defs" in schema: - defs = schema["$defs"] - current = defs - # Navigate through the defs path - for part in defs_path: - if isinstance(current, dict) and part in current: - current = current[part] - else: - # Can't resolve, assume it might be an object - # (safer to assume object than to wrap incorrectly) - return True - # Recursively check the resolved schema - if isinstance(current, dict): - return _is_object_schema(current) - # If $defs not found but we have a $ref, assume object - # (self-referencing types are typically objects) - return True - elif ref == "#": - # Self-reference - treat as object (common for recursive types) - return True - # For other $ref patterns, assume object to be safe - # (most $refs in JSON schemas point to object types) - return True - - return False + # Self-referencing types use $ref pointing to $defs + # The referenced type is always an object in our use case + return "$ref" in schema and "$defs" in schema @dataclass diff --git a/tests/server/test_server.py b/tests/server/test_server.py index f319ad4386..38ec249981 100644 --- a/tests/server/test_server.py +++ b/tests/server/test_server.py @@ -424,7 +424,7 @@ async def test_tool_decorator_with_output_schema(self): mcp = FastMCP() with pytest.raises( - ValueError, match='Output schemas must have "type" set to "object"' + ValueError, match="Output schemas must represent object types" ): @mcp.tool(output_schema={"type": "integer"})