Merge pull request #437 from davenpi/feat/remove-tool

feat: add support for removing tools from server
This commit is contained in:
Jeremiah Lowin 2025-05-13 18:36:18 -04:00 committed by GitHub
commit 08d54ef65b
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 65 additions and 0 deletions

View file

@ -454,6 +454,18 @@ class FastMCP(Generic[LifespanResultT]):
)
self._cache.clear()
def remove_tool(self, name: str) -> None:
"""Remove a tool from the server.
Args:
name: The name of the tool to remove
Raises:
NotFoundError: If the tool is not found
"""
self._tool_manager.remove_tool(name)
self._cache.clear()
def tool(
self,
name: str | None = None,

View file

@ -94,6 +94,20 @@ class ToolManager:
self._tools[key] = tool
return tool
def remove_tool(self, key: str) -> None:
"""Remove a tool from the server.
Args:
key: The key of the tool to remove
Raises:
NotFoundError: If the tool is not found
"""
if key in self._tools:
del self._tools[key]
else:
raise NotFoundError(f"Unknown tool: {key}")
async def call_tool(
self, key: str, arguments: dict[str, Any]
) -> list[TextContent | ImageContent | EmbeddedResource]:

View file

@ -72,6 +72,25 @@ class TestTools:
assert len(mcp_tools) == 1
assert mcp_tools[0].name == "custom_name"
async def test_remove_tool_successfully(self):
"""Test that FastMCP.remove_tool removes the tool from the registry."""
mcp = FastMCP()
@mcp.tool(name="adder")
def add(a: int, b: int) -> int:
return a + b
mcp_tools = await mcp.get_tools()
assert "adder" in mcp_tools
mcp.remove_tool("adder")
mcp_tools = await mcp.get_tools()
assert "adder" not in mcp_tools
with pytest.raises(NotFoundError, match="Unknown tool: adder"):
await mcp._mcp_call_tool("adder", {"a": 1, "b": 2})
class TestToolDecorator:
async def test_no_tools_before_decorator(self):

View file

@ -100,6 +100,26 @@ class TestAddTools:
):
manager.add_tool_from_fn(lambda x: x)
def test_remove_tool_successfully(self):
"""Test removing an added tool by key."""
manager = ToolManager()
def add(a: int, b: int) -> int:
return a + b
manager.add_tool_from_fn(add)
assert manager.get_tool("add") is not None
manager.remove_tool("add")
with pytest.raises(NotFoundError):
manager.get_tool("add")
def test_remove_tool_missing_key(self):
"""Test removing a tool that does not exist raises NotFoundError."""
manager = ToolManager()
with pytest.raises(NotFoundError, match=f"Unknown tool: {'missing'}"):
manager.remove_tool("missing")
def test_warn_on_duplicate_tools(self, caplog):
"""Test warning on duplicate tools."""
manager = ToolManager(duplicate_behavior="warn")