File size: 2,305 Bytes
bacf327
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
d0abf98
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
from fastmcp import FastMCP
from fastmcp.tools.tool_transform import ToolTransformConfig


async def test_tool_transformation_in_tool_manager():
    """Test that tool transformations are applied in the tool manager."""
    mcp = FastMCP("Test Server")

    @mcp.tool()
    def echo(message: str) -> str:
        """Echo back the message provided."""
        return message

    mcp.add_tool_transformation("echo", ToolTransformConfig(name="echo_transformed"))

    tools_dict = await mcp._tool_manager.get_tools()
    tools = list(tools_dict.values())
    assert len(tools) == 1
    assert "echo_transformed" in tools_dict
    assert tools_dict["echo_transformed"].name == "echo_transformed"


async def test_transformed_tool_filtering():
    """Test that tool transformations are applied in the tool manager."""
    mcp = FastMCP("Test Server", include_tags={"enabled_tools"})

    @mcp.tool()
    def echo(message: str) -> str:
        """Echo back the message provided."""
        return message

    tools = list(await mcp._list_tools())
    assert len(tools) == 0

    mcp.add_tool_transformation(
        "echo", ToolTransformConfig(name="echo_transformed", tags={"enabled_tools"})
    )

    tools = list(await mcp._list_tools())
    assert len(tools) == 1


async def test_transformed_tool_structured_output_without_annotation():
    """Test that transformed tools generate structured output when original tool has no return annotation.

    Ref: https://github.com/jlowin/fastmcp/issues/1369
    """
    from fastmcp.client import Client

    mcp = FastMCP("Test Server")

    @mcp.tool()
    def tool_without_annotation(message: str):  # No return annotation
        """A tool without return type annotation."""
        return {"result": "processed", "input": message}

    # Create a transformed tool
    mcp.add_tool_transformation(
        "tool_without_annotation", ToolTransformConfig(name="transformed_tool")
    )

    # Test with client to verify structured output is populated
    async with Client(mcp) as client:
        result = await client.call_tool("transformed_tool", {"message": "test"})

        # Structured output should be populated even without return annotation
        assert result.data is not None
        assert result.data == {"result": "processed", "input": "test"}