Spaces:
Running
Running
Jeremiah Lowin commited on
Commit ·
dce143d
1
Parent(s): 5a29d74
Update tool manager param to key
Browse files
src/fastmcp/server/server.py
CHANGED
|
@@ -186,7 +186,7 @@ class FastMCP(Generic[LifespanResultT]):
|
|
| 186 |
self._mcp_server.list_resource_templates()(self._mcp_list_resource_templates)
|
| 187 |
|
| 188 |
def get_tools(self) -> dict[str, Tool]:
|
| 189 |
-
"""Get all registered tools,
|
| 190 |
return self._tool_manager.get_tools()
|
| 191 |
|
| 192 |
def list_tools(self) -> list[Tool]:
|
|
|
|
| 186 |
self._mcp_server.list_resource_templates()(self._mcp_list_resource_templates)
|
| 187 |
|
| 188 |
def get_tools(self) -> dict[str, Tool]:
|
| 189 |
+
"""Get all registered tools, indexed by registered key."""
|
| 190 |
return self._tool_manager.get_tools()
|
| 191 |
|
| 192 |
def list_tools(self) -> list[Tool]:
|
src/fastmcp/tools/tool_manager.py
CHANGED
|
@@ -41,7 +41,7 @@ class ToolManager:
|
|
| 41 |
return self._tools.get(name)
|
| 42 |
|
| 43 |
def get_tools(self) -> dict[str, Tool]:
|
| 44 |
-
"""Get all registered tools,
|
| 45 |
return self._tools
|
| 46 |
|
| 47 |
def list_tools(self) -> list[Tool]:
|
|
@@ -50,7 +50,7 @@ class ToolManager:
|
|
| 50 |
|
| 51 |
def list_mcp_tools(self) -> list[MCPTool]:
|
| 52 |
"""List all registered tools in the format expected by the low-level MCP server."""
|
| 53 |
-
return [tool.to_mcp_tool(name=
|
| 54 |
|
| 55 |
def add_tool_from_fn(
|
| 56 |
self,
|
|
@@ -63,34 +63,34 @@ class ToolManager:
|
|
| 63 |
tool = Tool.from_function(fn, name=name, description=description, tags=tags)
|
| 64 |
return self.add_tool(tool)
|
| 65 |
|
| 66 |
-
def add_tool(self, tool: Tool,
|
| 67 |
"""Register a tool with the server."""
|
| 68 |
-
|
| 69 |
-
existing = self._tools.get(
|
| 70 |
if existing:
|
| 71 |
if self.duplicate_behavior == "warn":
|
| 72 |
-
logger.warning(f"Tool already exists: {
|
| 73 |
-
self._tools[
|
| 74 |
elif self.duplicate_behavior == "replace":
|
| 75 |
-
self._tools[
|
| 76 |
elif self.duplicate_behavior == "error":
|
| 77 |
-
raise ValueError(f"Tool already exists: {
|
| 78 |
elif self.duplicate_behavior == "ignore":
|
| 79 |
return existing
|
| 80 |
else:
|
| 81 |
-
self._tools[
|
| 82 |
return tool
|
| 83 |
|
| 84 |
async def call_tool(
|
| 85 |
self,
|
| 86 |
-
|
| 87 |
arguments: dict[str, Any],
|
| 88 |
context: Context[ServerSessionT, LifespanContextT] | None = None,
|
| 89 |
) -> Any:
|
| 90 |
"""Call a tool by name with arguments."""
|
| 91 |
-
tool = self.get_tool(
|
| 92 |
if not tool:
|
| 93 |
-
raise ToolError(f"Unknown tool: {
|
| 94 |
|
| 95 |
return await tool.run(arguments, context=context)
|
| 96 |
|
|
@@ -110,5 +110,5 @@ class ToolManager:
|
|
| 110 |
"""
|
| 111 |
for name, tool in tool_manager._tools.items():
|
| 112 |
prefixed_name = f"{prefix}{name}" if prefix else name
|
| 113 |
-
self.add_tool(tool,
|
| 114 |
logger.debug(f'Imported tool "{tool.name}" as "{prefixed_name}"')
|
|
|
|
| 41 |
return self._tools.get(name)
|
| 42 |
|
| 43 |
def get_tools(self) -> dict[str, Tool]:
|
| 44 |
+
"""Get all registered tools, indexed by registered key."""
|
| 45 |
return self._tools
|
| 46 |
|
| 47 |
def list_tools(self) -> list[Tool]:
|
|
|
|
| 50 |
|
| 51 |
def list_mcp_tools(self) -> list[MCPTool]:
|
| 52 |
"""List all registered tools in the format expected by the low-level MCP server."""
|
| 53 |
+
return [tool.to_mcp_tool(name=key) for key, tool in self._tools.items()]
|
| 54 |
|
| 55 |
def add_tool_from_fn(
|
| 56 |
self,
|
|
|
|
| 63 |
tool = Tool.from_function(fn, name=name, description=description, tags=tags)
|
| 64 |
return self.add_tool(tool)
|
| 65 |
|
| 66 |
+
def add_tool(self, tool: Tool, key: str | None = None) -> Tool:
|
| 67 |
"""Register a tool with the server."""
|
| 68 |
+
key = key or tool.name
|
| 69 |
+
existing = self._tools.get(key)
|
| 70 |
if existing:
|
| 71 |
if self.duplicate_behavior == "warn":
|
| 72 |
+
logger.warning(f"Tool already exists: {key}")
|
| 73 |
+
self._tools[key] = tool
|
| 74 |
elif self.duplicate_behavior == "replace":
|
| 75 |
+
self._tools[key] = tool
|
| 76 |
elif self.duplicate_behavior == "error":
|
| 77 |
+
raise ValueError(f"Tool already exists: {key}")
|
| 78 |
elif self.duplicate_behavior == "ignore":
|
| 79 |
return existing
|
| 80 |
else:
|
| 81 |
+
self._tools[key] = tool
|
| 82 |
return tool
|
| 83 |
|
| 84 |
async def call_tool(
|
| 85 |
self,
|
| 86 |
+
key: str,
|
| 87 |
arguments: dict[str, Any],
|
| 88 |
context: Context[ServerSessionT, LifespanContextT] | None = None,
|
| 89 |
) -> Any:
|
| 90 |
"""Call a tool by name with arguments."""
|
| 91 |
+
tool = self.get_tool(key)
|
| 92 |
if not tool:
|
| 93 |
+
raise ToolError(f"Unknown tool: {key}")
|
| 94 |
|
| 95 |
return await tool.run(arguments, context=context)
|
| 96 |
|
|
|
|
| 110 |
"""
|
| 111 |
for name, tool in tool_manager._tools.items():
|
| 112 |
prefixed_name = f"{prefix}{name}" if prefix else name
|
| 113 |
+
self.add_tool(tool, key=prefixed_name)
|
| 114 |
logger.debug(f'Imported tool "{tool.name}" as "{prefixed_name}"')
|
tests/tools/test_tool_manager.py
CHANGED
|
@@ -585,7 +585,7 @@ class TestCustomToolNames:
|
|
| 585 |
tool = Tool.from_function(fn, name="my_tool")
|
| 586 |
manager = ToolManager()
|
| 587 |
# Store it under a different name
|
| 588 |
-
manager.add_tool(tool,
|
| 589 |
# The tool is accessible under the storage name
|
| 590 |
stored = manager.get_tool("proxy_tool")
|
| 591 |
assert stored is not None
|
|
@@ -682,7 +682,7 @@ class TestCustomToolNames:
|
|
| 682 |
|
| 683 |
tool = Tool.from_function(fn, name="my_tool")
|
| 684 |
manager = ToolManager()
|
| 685 |
-
manager.add_tool(tool,
|
| 686 |
mcp_tools = manager.list_mcp_tools()
|
| 687 |
assert len(mcp_tools) == 1
|
| 688 |
assert mcp_tools[0].name == "proxy_tool"
|
|
|
|
| 585 |
tool = Tool.from_function(fn, name="my_tool")
|
| 586 |
manager = ToolManager()
|
| 587 |
# Store it under a different name
|
| 588 |
+
manager.add_tool(tool, key="proxy_tool")
|
| 589 |
# The tool is accessible under the storage name
|
| 590 |
stored = manager.get_tool("proxy_tool")
|
| 591 |
assert stored is not None
|
|
|
|
| 682 |
|
| 683 |
tool = Tool.from_function(fn, name="my_tool")
|
| 684 |
manager = ToolManager()
|
| 685 |
+
manager.add_tool(tool, key="proxy_tool")
|
| 686 |
mcp_tools = manager.list_mcp_tools()
|
| 687 |
assert len(mcp_tools) == 1
|
| 688 |
assert mcp_tools[0].name == "proxy_tool"
|