mirror of
https://github.com/PrefectHQ/fastmcp.git
synced 2026-08-09 07:09:11 +02:00
* pin pydantic-monty to 0.0.8 * rename tool/prompt/resource base modules to avoid decorator name shadow * add sys.modules shims for old submodule import paths * preserve original module paths in deprecation warnings * clarify when sys.modules shims can be removed
122 lines
3.7 KiB
Python
122 lines
3.7 KiB
Python
from typing import Any
|
|
|
|
import pytest
|
|
from mcp.server.session import ServerSession
|
|
|
|
from fastmcp import Client, FastMCP
|
|
from fastmcp.tools.base import Tool
|
|
|
|
|
|
async def test_tool_exclude_args():
|
|
"""Test that tool args are excluded."""
|
|
mcp = FastMCP("Test Server")
|
|
|
|
@mcp.tool(exclude_args=["state"])
|
|
def echo(message: str, state: dict[str, Any] | None = None) -> str:
|
|
"""Echo back the message provided."""
|
|
if state:
|
|
# State was read
|
|
pass
|
|
return message
|
|
|
|
tools = await mcp.list_tools()
|
|
assert len(tools) == 1
|
|
assert "state" not in tools[0].parameters["properties"]
|
|
|
|
|
|
async def test_tool_exclude_args_without_default_value_raises_error():
|
|
"""Test that excluding args without default values raises ValueError"""
|
|
mcp = FastMCP("Test Server")
|
|
|
|
with pytest.raises(ValueError):
|
|
|
|
@mcp.tool(exclude_args=["state"])
|
|
def echo(message: str, state: dict[str, Any] | None) -> str:
|
|
"""Echo back the message provided."""
|
|
if state:
|
|
# State was read
|
|
pass
|
|
return message
|
|
|
|
|
|
async def test_add_tool_method_exclude_args():
|
|
"""Test that tool exclude_args work with the add_tool method."""
|
|
mcp = FastMCP("Test Server")
|
|
|
|
def create_item(
|
|
name: str, value: int, state: dict[str, Any] | None = None
|
|
) -> dict[str, Any]:
|
|
"""Create a new item."""
|
|
if state:
|
|
# State was read
|
|
pass
|
|
return {"name": name, "value": value}
|
|
|
|
tool = Tool.from_function(
|
|
create_item,
|
|
name="create_item",
|
|
exclude_args=["state"],
|
|
)
|
|
mcp.add_tool(tool)
|
|
|
|
# Check tool via public API
|
|
tools = await mcp.list_tools()
|
|
assert len(tools) == 1
|
|
assert "state" not in tools[0].parameters["properties"]
|
|
|
|
|
|
async def test_tool_functionality_with_exclude_args():
|
|
"""Test that tool functionality is preserved when using exclude_args."""
|
|
mcp = FastMCP("Test Server")
|
|
|
|
def create_item(
|
|
name: str, value: int, state: dict[str, Any] | None = None
|
|
) -> dict[str, Any]:
|
|
"""Create a new item."""
|
|
if state:
|
|
# state was read
|
|
pass
|
|
return {"name": name, "value": value}
|
|
|
|
tool = Tool.from_function(
|
|
create_item,
|
|
name="create_item",
|
|
exclude_args=["state"],
|
|
)
|
|
mcp.add_tool(tool)
|
|
|
|
# Use the tool to verify functionality is preserved
|
|
async with Client(mcp) as client:
|
|
result = await client.call_tool(
|
|
"create_item", {"name": "test_item", "value": 42}
|
|
)
|
|
assert result.data == {"name": "test_item", "value": 42}
|
|
|
|
|
|
async def test_exclude_args_with_non_serializable_type():
|
|
"""Test that exclude_args works even when the excluded parameter type can't be serialized.
|
|
|
|
This test ensures that exclude_args works correctly when the excluded parameter
|
|
has a type that Pydantic cannot serialize (like ServerSession). The bug was that
|
|
get_cached_typeadapter would try to serialize all parameters before compress_schema
|
|
could exclude them, causing a PydanticSchemaGenerationError.
|
|
"""
|
|
|
|
def my_tool(message: str, session: ServerSession | None = None) -> str:
|
|
"""A tool that takes a non-serializable Session parameter."""
|
|
return message
|
|
|
|
# This should not raise an error even though ServerSession can't be serialized
|
|
tool = Tool.from_function(
|
|
my_tool,
|
|
name="my_tool",
|
|
exclude_args=["session"],
|
|
)
|
|
|
|
# Verify the tool was created successfully
|
|
assert tool is not None
|
|
assert tool.name == "my_tool"
|
|
|
|
# Verify the session parameter is excluded from the schema
|
|
assert "session" not in tool.parameters["properties"]
|
|
assert "message" in tool.parameters["properties"]
|