Skip to content

Commit f9a7dcc

Browse files
committed
feat(mcpserver): expose public get_tool(name) on MCPServer
Add MCPServer.get_tool to retrieve a registered tool by name without using the private _tool_manager, completing the add/remove CRUD surface. Fixes #3162
1 parent a4f4ccd commit f9a7dcc

2 files changed

Lines changed: 47 additions & 0 deletions

File tree

src/mcp/server/mcpserver/server.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -607,6 +607,20 @@ def add_tool(
607607
structured_output=structured_output,
608608
)
609609

610+
def get_tool(self, name: str) -> Tool | None:
611+
"""Get a registered tool by name.
612+
613+
Returns the tool registration (including its mutable `parameters` JSON schema)
614+
so callers can inspect or update a tool without reaching into `_tool_manager`.
615+
616+
Args:
617+
name: The name of the tool to look up
618+
619+
Returns:
620+
The registered tool, or `None` if no tool with that name exists
621+
"""
622+
return self._tool_manager.get_tool(name)
623+
610624
def remove_tool(self, name: str) -> None:
611625
"""Remove a tool from the server by name.
612626

tests/server/mcpserver/test_server.py

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2348,6 +2348,39 @@ def greeting() -> str: # pragma: no cover
23482348
mcp.remove_prompt("greeting")
23492349

23502350

2351+
def test_get_tool_returns_registered_tool_or_none() -> None:
2352+
"""SDK-defined: public get_tool completes add/remove without using _tool_manager."""
2353+
mcp = MCPServer()
2354+
2355+
def echo(text: str) -> str: # pragma: no cover
2356+
return text
2357+
2358+
mcp.add_tool(echo)
2359+
tool = mcp.get_tool("echo")
2360+
assert tool is not None
2361+
assert tool.name == "echo"
2362+
assert mcp.get_tool("missing") is None
2363+
2364+
2365+
def test_get_tool_exposes_mutable_parameters_for_schema_updates() -> None:
2366+
"""SDK-defined: callers can update a tool's inputSchema via get_tool after registration."""
2367+
mcp = MCPServer()
2368+
2369+
def act(action: str) -> str: # pragma: no cover
2370+
return action
2371+
2372+
mcp.add_tool(act)
2373+
tool = mcp.get_tool("act")
2374+
assert tool is not None
2375+
tool.parameters = {
2376+
"type": "object",
2377+
"properties": {"action": {"type": "string", "const": "ping"}},
2378+
"required": ["action"],
2379+
}
2380+
assert mcp.get_tool("act") is tool
2381+
assert tool.parameters["properties"]["action"]["const"] == "ping"
2382+
2383+
23512384
@pytest.mark.anyio
23522385
async def test_middleware_kwarg_and_property_share_the_low_level_chain() -> None:
23532386
"""SDK-defined: `MCPServer(middleware=[...])` appends to the low-level chain after

0 commit comments

Comments
 (0)