Skip to content

Commit 5a9340a

Browse files
authored
fastmcp: allow passing Tool directly to FastMCP constructor (#699)
1 parent e33cd41 commit 5a9340a

File tree

3 files changed

+47
-4
lines changed

3 files changed

+47
-4
lines changed

src/mcp/server/fastmcp/server.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@
3737
from mcp.server.fastmcp.exceptions import ResourceError
3838
from mcp.server.fastmcp.prompts import Prompt, PromptManager
3939
from mcp.server.fastmcp.resources import FunctionResource, Resource, ResourceManager
40-
from mcp.server.fastmcp.tools import ToolManager
40+
from mcp.server.fastmcp.tools import Tool, ToolManager
4141
from mcp.server.fastmcp.utilities.logging import configure_logging, get_logger
4242
from mcp.server.fastmcp.utilities.types import Image
4343
from mcp.server.lowlevel.helper_types import ReadResourceContents
@@ -141,6 +141,8 @@ def __init__(
141141
auth_server_provider: OAuthAuthorizationServerProvider[Any, Any, Any]
142142
| None = None,
143143
event_store: EventStore | None = None,
144+
*,
145+
tools: list[Tool] | None = None,
144146
**settings: Any,
145147
):
146148
self.settings = Settings(**settings)
@@ -155,7 +157,7 @@ def __init__(
155157
),
156158
)
157159
self._tool_manager = ToolManager(
158-
warn_on_duplicate_tools=self.settings.warn_on_duplicate_tools
160+
tools=tools, warn_on_duplicate_tools=self.settings.warn_on_duplicate_tools
159161
)
160162
self._resource_manager = ResourceManager(
161163
warn_on_duplicate_resources=self.settings.warn_on_duplicate_resources

src/mcp/server/fastmcp/tools/tool_manager.py

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,19 @@
1919
class ToolManager:
2020
"""Manages FastMCP tools."""
2121

22-
def __init__(self, warn_on_duplicate_tools: bool = True):
22+
def __init__(
23+
self,
24+
warn_on_duplicate_tools: bool = True,
25+
*,
26+
tools: list[Tool] | None = None,
27+
):
2328
self._tools: dict[str, Tool] = {}
29+
if tools is not None:
30+
for tool in tools:
31+
if warn_on_duplicate_tools and tool.name in self._tools:
32+
logger.warning(f"Tool already exists: {tool.name}")
33+
self._tools[tool.name] = tool
34+
2435
self.warn_on_duplicate_tools = warn_on_duplicate_tools
2536

2637
def get_tool(self, name: str) -> Tool | None:

tests/server/fastmcp/test_tool_manager.py

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,8 @@
66

77
from mcp.server.fastmcp import Context, FastMCP
88
from mcp.server.fastmcp.exceptions import ToolError
9-
from mcp.server.fastmcp.tools import ToolManager
9+
from mcp.server.fastmcp.tools import Tool, ToolManager
10+
from mcp.server.fastmcp.utilities.func_metadata import ArgModelBase, FuncMetadata
1011
from mcp.server.session import ServerSessionT
1112
from mcp.shared.context import LifespanContextT
1213
from mcp.types import ToolAnnotations
@@ -31,6 +32,35 @@ def add(a: int, b: int) -> int:
3132
assert tool.parameters["properties"]["a"]["type"] == "integer"
3233
assert tool.parameters["properties"]["b"]["type"] == "integer"
3334

35+
def test_init_with_tools(self, caplog):
36+
def add(a: int, b: int) -> int:
37+
return a + b
38+
39+
class AddArguments(ArgModelBase):
40+
a: int
41+
b: int
42+
43+
fn_metadata = FuncMetadata(arg_model=AddArguments)
44+
45+
original_tool = Tool(
46+
name="add",
47+
description="Add two numbers.",
48+
fn=add,
49+
fn_metadata=fn_metadata,
50+
is_async=False,
51+
parameters=AddArguments.model_json_schema(),
52+
context_kwarg=None,
53+
annotations=None,
54+
)
55+
manager = ToolManager(tools=[original_tool])
56+
saved_tool = manager.get_tool("add")
57+
assert saved_tool == original_tool
58+
59+
# warn on duplicate tools
60+
with caplog.at_level(logging.WARNING):
61+
manager = ToolManager(True, tools=[original_tool, original_tool])
62+
assert "Tool already exists: add" in caplog.text
63+
3464
@pytest.mark.anyio
3565
async def test_async_function(self):
3666
"""Test registering and running an async function."""

0 commit comments

Comments
 (0)