Spaces:
Running
Running
File size: 5,297 Bytes
3685b24 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | """Test deprecated output_schema=False behavior (deprecated in 2.11.4)."""
import warnings
import pytest
from fastmcp import FastMCP
from fastmcp.tools import Tool
class TestDeprecatedOutputSchemaFalse:
"""Test that output_schema=False is deprecated but still works."""
async def test_tool_decorator_output_schema_false_deprecated(self):
"""Test that @mcp.tool(output_schema=False) shows deprecation warning."""
mcp = FastMCP()
with pytest.warns(
DeprecationWarning, match="output_schema=False is deprecated"
):
@mcp.tool(output_schema=False) # type: ignore[arg-type]
def simple_tool() -> int:
"""A simple tool."""
return 42
# Verify the tool was created with None as output_schema
tool = mcp._tool_manager._tools["simple_tool"]
assert tool.output_schema is None
async def test_tool_from_function_output_schema_false_deprecated(self):
"""Test that Tool.from_function(output_schema=False) shows deprecation warning."""
def my_function() -> str:
"""A simple function."""
return "hello"
with pytest.warns(
DeprecationWarning, match="output_schema=False is deprecated"
):
tool = Tool.from_function(my_function, output_schema=False) # type: ignore[arg-type]
# Verify the tool was created with None as output_schema
assert tool.output_schema is None
async def test_tool_from_tool_output_schema_false_deprecated(self):
"""Test that Tool.from_tool(output_schema=False) shows deprecation warning."""
# Create a parent tool
def parent_function() -> dict[str, str]:
"""A parent function."""
return {"status": "ok"}
parent_tool = Tool.from_function(parent_function)
with pytest.warns(
DeprecationWarning, match="output_schema=False is deprecated"
):
transformed_tool = Tool.from_tool(parent_tool, output_schema=False) # type: ignore[arg-type]
# Verify the tool was created with None as output_schema
assert transformed_tool.output_schema is None
async def test_output_schema_false_functionality_preserved(self):
"""Test that output_schema=False still works functionally like output_schema=None."""
mcp = FastMCP()
# Create two tools - one with False, one with None
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
@mcp.tool(output_schema=False) # type: ignore[arg-type]
def tool_with_false() -> dict[str, str]:
"""Tool with output_schema=False."""
return {"result": "false"}
@mcp.tool(output_schema=None)
def tool_with_none() -> dict[str, str]:
"""Tool with output_schema=None."""
return {"result": "none"}
# Both should have None as output_schema
assert mcp._tool_manager._tools["tool_with_false"].output_schema is None
assert mcp._tool_manager._tools["tool_with_none"].output_schema is None
# Both should work the same way
result_false = await mcp._tool_manager._tools["tool_with_false"].run({})
result_none = await mcp._tool_manager._tools["tool_with_none"].run({})
# Both should return structured content for dict-like objects
assert result_false.structured_content == {"result": "false"}
assert result_none.structured_content == {"result": "none"}
async def test_output_schema_false_with_scalar_return(self):
"""Test that output_schema=False works with scalar returns (no structured content)."""
mcp = FastMCP()
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
@mcp.tool(output_schema=False) # type: ignore[arg-type]
def scalar_tool() -> int:
"""Tool returning a scalar."""
return 42
tool = mcp._tool_manager._tools["scalar_tool"]
assert tool.output_schema is None
result = await tool.run({})
# Scalar values don't produce structured content
assert result.structured_content is None
assert len(result.content) == 1
assert result.content[0].text == "42" # type: ignore[attr-defined]
async def test_transform_with_output_schema_false(self):
"""Test that transformation with output_schema=False still works."""
# Create a parent tool
def parent_function(x: int) -> dict[str, int]:
"""A parent function."""
return {"value": x * 2}
parent_tool = Tool.from_function(parent_function)
with warnings.catch_warnings():
warnings.simplefilter("ignore", DeprecationWarning)
# Transform with output_schema=False
transformed = Tool.from_tool(
parent_tool,
name="doubled",
output_schema=False, # type: ignore[arg-type]
)
assert transformed.output_schema is None
# Tool should still work
result = await transformed.run({"x": 5})
assert result.structured_content == {"value": 10}
|