Skip to content
Merged
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
9 changes: 8 additions & 1 deletion mellea/stdlib/tools/mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@ class MCPToolSpec:
Holds everything needed to inspect or instantiate a `MelleaTool` without
keeping a live session open.

Reassign `name` and `description` before calling `as_mellea_tool` to
disambiguate tools that share a name across multiple servers, or to give the
model better selection hints. Reassigning `name` only changes the name shown
to the model; the original server-side name is preserved and used for the
actual tool invocation.

Args:
name (str): Tool name as registered on the server.
description (str): Human-readable description from the server.
Expand All @@ -75,6 +81,7 @@ def __init__(
) -> None:
"""Store the spec fields and the transport config."""
self.name = name
self._server_tool_name = name
self.description = description
self.input_schema = input_schema
self._connection = connection
Expand All @@ -93,7 +100,7 @@ def as_mellea_tool(self) -> MelleaTool:
"""
return MelleaTool(
self.name,
_make_sync_call(self._connection, self.name),
_make_sync_call(self._connection, self._server_tool_name),
{
"type": "function",
"function": {
Expand Down
25 changes: 25 additions & 0 deletions test/stdlib/tools/test_mcp.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,31 @@ async def test_produces_mellea_tool_with_correct_name(self, connection):
assert isinstance(tool, MelleaTool)
assert tool.name == "get_me"

@pytest.mark.asyncio
async def test_reassigned_name_calls_original_server_name(self, connection):
"""Renaming a spec to disambiguate still invokes the server-side name."""
called_with: list[str] = []

async def _capture(tool_name, *, arguments):
called_with.append(tool_name)
return _call_result()

session = _make_session(_make_mcp_tool("get_me"))
session.call_tool = _capture

with _mock_open_session(session):
specs = await discover_mcp_tools(connection)

# A user reassigns name to avoid a collision with another server's tool.
specs[0].name = "github_get_me"

with _mock_open_session(session):
tool = specs[0].as_mellea_tool()
assert tool.name == "github_get_me"
tool.run()

assert called_with == ["get_me"]

@pytest.mark.asyncio
async def test_json_schema_structure(self, connection):
schema = {"type": "object", "properties": {"q": {"type": "string"}}}
Expand Down
Loading