Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions src/mcp/server/mcpserver/server.py
Original file line number Diff line number Diff line change
Expand Up @@ -607,6 +607,20 @@ def add_tool(
structured_output=structured_output,
)

def get_tool(self, name: str) -> Tool | None:
"""Get a registered tool by name.

Returns the tool registration (including its mutable `parameters` JSON schema)
so callers can inspect or update a tool without reaching into `_tool_manager`.

Args:
name: The name of the tool to look up

Returns:
The registered tool, or `None` if no tool with that name exists
"""
return self._tool_manager.get_tool(name)

def remove_tool(self, name: str) -> None:
"""Remove a tool from the server by name.

Expand Down
33 changes: 33 additions & 0 deletions tests/server/mcpserver/test_server.py
Original file line number Diff line number Diff line change
Expand Up @@ -2348,6 +2348,39 @@ def greeting() -> str: # pragma: no cover
mcp.remove_prompt("greeting")


def test_get_tool_returns_registered_tool_or_none() -> None:
"""SDK-defined: public get_tool completes add/remove without using _tool_manager."""
mcp = MCPServer()

def echo(text: str) -> str: # pragma: no cover
return text

mcp.add_tool(echo)
tool = mcp.get_tool("echo")
assert tool is not None
assert tool.name == "echo"
assert mcp.get_tool("missing") is None


def test_get_tool_exposes_mutable_parameters_for_schema_updates() -> None:
"""SDK-defined: callers can update a tool's inputSchema via get_tool after registration."""
mcp = MCPServer()

def act(action: str) -> str: # pragma: no cover
return action

mcp.add_tool(act)
tool = mcp.get_tool("act")
assert tool is not None
tool.parameters = {
"type": "object",
"properties": {"action": {"type": "string", "const": "ping"}},
"required": ["action"],
}
assert mcp.get_tool("act") is tool
assert tool.parameters["properties"]["action"]["const"] == "ping"


@pytest.mark.anyio
async def test_middleware_kwarg_and_property_share_the_low_level_chain() -> None:
"""SDK-defined: `MCPServer(middleware=[...])` appends to the low-level chain after
Expand Down
Loading