Skip to content

Commit 0466636

Browse files
feat: #1167 add opt-in server-prefixed MCP tool names (#3019)
1 parent f903926 commit 0466636

5 files changed

Lines changed: 756 additions & 19 deletions

File tree

docs/mcp.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,8 @@ agent = Agent(
4040
# If None, MCP tool failures are raised as exceptions instead of
4141
# returning model-visible error text.
4242
"failure_error_function": None,
43+
# Prefix local MCP tool names with their server name.
44+
"include_server_in_tool_names": True,
4345
},
4446
)
4547
```
@@ -50,6 +52,7 @@ Notes:
5052
- `failure_error_function` controls how MCP tool call failures are surfaced to the model.
5153
- When `failure_error_function` is unset, the SDK uses the default tool error formatter.
5254
- Server-level `failure_error_function` overrides `Agent.mcp_config["failure_error_function"]` for that server.
55+
- `include_server_in_tool_names` is opt-in. When enabled, each local MCP tool is exposed to the model with a deterministic server-prefixed name, which helps avoid collisions when multiple MCP servers publish tools with the same name. Generated names are ASCII-safe, stay within the function-tool name length limit, and avoid existing local function tool and enabled handoff names on the same agent. The SDK still invokes the original MCP tool name on the original server.
5356

5457
## Shared patterns across transports
5558

src/agents/agent.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,11 @@ class MCPConfig(TypedDict):
150150
default_tool_error_function.
151151
"""
152152

153+
include_server_in_tool_names: NotRequired[bool]
154+
"""If True, local MCP tools are exposed with server-prefixed public names to avoid name
155+
collisions across multiple MCP servers. Defaults to False.
156+
"""
157+
153158

154159
def _initial_model_settings_for_model(model: str | Model | None) -> ModelSettings:
155160
if model is None:
@@ -194,18 +199,48 @@ class AgentBase(Generic[TContext]):
194199
mcp_config: MCPConfig = field(default_factory=lambda: MCPConfig())
195200
"""Configuration for MCP servers."""
196201

202+
async def _get_mcp_tool_reserved_names(
203+
self, run_context: RunContextWrapper[TContext]
204+
) -> set[str]:
205+
reserved_tool_names = {tool.name for tool in self.tools if isinstance(tool, FunctionTool)}
206+
207+
async def _check_handoff_enabled(handoff_obj: Handoff[Any, Any]) -> bool:
208+
attr = handoff_obj.is_enabled
209+
if isinstance(attr, bool):
210+
return attr
211+
res = attr(run_context, self)
212+
if inspect.isawaitable(res):
213+
return bool(await res)
214+
return bool(res)
215+
216+
for handoff_item in getattr(self, "handoffs", ()):
217+
if isinstance(handoff_item, Handoff):
218+
if await _check_handoff_enabled(handoff_item):
219+
reserved_tool_names.add(handoff_item.tool_name)
220+
elif isinstance(handoff_item, AgentBase):
221+
reserved_tool_names.add(Handoff.default_tool_name(handoff_item))
222+
return reserved_tool_names
223+
197224
async def get_mcp_tools(self, run_context: RunContextWrapper[TContext]) -> list[Tool]:
198225
"""Fetches the available tools from the MCP servers."""
199226
convert_schemas_to_strict = self.mcp_config.get("convert_schemas_to_strict", False)
200227
failure_error_function = self.mcp_config.get(
201228
"failure_error_function", default_tool_error_function
202229
)
230+
include_server_in_tool_names = self.mcp_config.get("include_server_in_tool_names", False)
231+
reserved_tool_names = (
232+
await self._get_mcp_tool_reserved_names(run_context)
233+
if include_server_in_tool_names
234+
else None
235+
)
203236
return await MCPUtil.get_all_function_tools(
204237
self.mcp_servers,
205238
convert_schemas_to_strict,
206239
run_context,
207240
self,
208241
failure_error_function=failure_error_function,
242+
include_server_in_tool_names=include_server_in_tool_names,
243+
reserved_tool_names=reserved_tool_names,
209244
)
210245

211246
async def get_all_tools(self, run_context: RunContextWrapper[TContext]) -> list[Tool]:

0 commit comments

Comments
 (0)