Compare commits

...

1 commit

Author SHA1 Message Date
zzstoatzz
4f7e739a35 fix: apply prefix to tool name when mounting servers
When mounting a server with a prefix, both the key and name fields
should be updated to include the prefix. Previously only the key was
updated, causing inconsistency between tool.key and tool.name.

This makes tool prefixing consistent with how resources and templates
are already handled.

🤖 Generated with Claude Code

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-22 10:56:04 -05:00
2 changed files with 48 additions and 2 deletions

View file

@ -464,7 +464,12 @@ class FastMCP(Generic[LifespanResultT]):
child_tools = await mounted.server.get_tools()
for key, tool in child_tools.items():
new_key = f"{mounted.prefix}_{key}" if mounted.prefix else key
all_tools[new_key] = tool.model_copy(key=new_key)
all_tools[new_key] = tool.model_copy(
key=new_key,
update={"name": f"{mounted.prefix}_{tool.name}"}
if mounted.prefix
else {},
)
except Exception as e:
logger.warning(
f"Failed to get tools from mounted server {mounted.server.name!r}: {e}"
@ -722,7 +727,9 @@ class FastMCP(Generic[LifespanResultT]):
key = tool.key
if mounted.prefix:
key = f"{mounted.prefix}_{tool.key}"
tool = tool.model_copy(key=key)
tool = tool.model_copy(
key=key, update={"name": f"{mounted.prefix}_{tool.name}"}
)
# Later mounted servers override earlier ones
all_tools[key] = tool
except Exception as e:

View file

@ -972,6 +972,45 @@ class TestAsProxyKwarg:
assert lifespan_check.count("start") >= 2
class TestToolNamePrefixing:
"""Test that tool names are prefixed when mounted."""
async def test_tool_name_prefixing(self):
"""Test that tool names (not just keys) are prefixed when mounted with a prefix."""
# Create a sub-app with a tool
sub_app = FastMCP("SubApp")
@sub_app.tool
def my_tool() -> str:
return "Tool result"
# Create main app and mount sub-app with prefix
main_app = FastMCP("MainApp")
main_app.mount(sub_app, "prefix")
# Get tools from main app
tools = await main_app.get_tools()
# Should have prefixed key
assert "prefix_my_tool" in tools
# The tool name should also be prefixed
tool = tools["prefix_my_tool"]
assert tool.name == "prefix_my_tool"
assert tool.key == "prefix_my_tool"
# Test via client to ensure both discovery and calling work
async with Client(main_app) as client:
# List tools should show prefixed name
tool_list = await client.list_tools()
tool_names = [t.name for t in tool_list]
assert "prefix_my_tool" in tool_names
# Calling with the prefixed name should work
result = await client.call_tool("prefix_my_tool", {})
assert result.data == "Tool result"
class TestResourceNamePrefixing:
"""Test that resource and resource template names get prefixed when mounted."""