From ec1116be799ca9ed5cd3de70e6b86198b60939f6 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Wed, 4 Mar 2026 17:46:34 -0800 Subject: [PATCH] fix(mcp): apply tool overrides after permission filtering; reverse-map display names in tools/call --- .../proxy/_experimental/mcp_server/server.py | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/litellm/proxy/_experimental/mcp_server/server.py b/litellm/proxy/_experimental/mcp_server/server.py index 32332b60f75..b131800e950 100644 --- a/litellm/proxy/_experimental/mcp_server/server.py +++ b/litellm/proxy/_experimental/mcp_server/server.py @@ -40,6 +40,8 @@ from litellm.proxy._experimental.mcp_server.utils import ( LITELLM_MCP_SERVER_DESCRIPTION, LITELLM_MCP_SERVER_NAME, LITELLM_MCP_SERVER_VERSION, + add_server_prefix_to_name, + get_server_prefix, ) from litellm.proxy._types import UserAPIKeyAuth from litellm.proxy.auth.ip_address_utils import IPAddressUtils @@ -1007,7 +1009,6 @@ if MCP_AVAILABLE: raw_headers=raw_headers, ) filtered_tools = filter_tools_by_allowed_tools(tools, server) - filtered_tools = apply_tool_overrides(filtered_tools, server) filtered_tools = await filter_tools_by_key_team_permissions( tools=filtered_tools, @@ -1015,6 +1016,10 @@ if MCP_AVAILABLE: user_api_key_auth=user_api_key_auth, ) + # Apply display-name/description overrides last so that + # permission filtering always works against original names. + filtered_tools = apply_tool_overrides(filtered_tools, server) + verbose_logger.debug( f"Successfully fetched {len(tools)} tools from server {server.name}, {len(filtered_tools)} after filtering" ) @@ -1473,6 +1478,26 @@ if MCP_AVAILABLE: return managed_resource_templates + def _resolve_display_name_to_original( + name: str, + allowed_mcp_servers: List[MCPServer], + ) -> str: + """Translate a display-name override back to the original prefixed tool name. + + When a client received a customised display name from tools/list (e.g. + "Get Pet") it will call tools/call with that same string. We need to + reverse-map it to the original prefixed name (e.g. + "petstore_mcp-getPetById") before any routing or permission logic runs. + """ + for server in allowed_mcp_servers: + display_map = server.tool_name_to_display_name or {} + for unprefixed_name, display_name in display_map.items(): + if display_name == name: + return add_server_prefix_to_name( + unprefixed_name, get_server_prefix(server) + ) + return name + async def execute_mcp_tool( name: str, arguments: Dict[str, Any], @@ -1509,6 +1534,10 @@ if MCP_AVAILABLE: # Track resolved MCP server for both permission checks and dispatch mcp_server: Optional[MCPServer] = None + # If the client called with a display-name override (e.g. "Get Pet"), + # translate it back to the original prefixed name before any routing. + name = _resolve_display_name_to_original(name, allowed_mcp_servers) + # Remove prefix from tool name for logging and processing original_tool_name, server_name = split_server_prefix_from_name(name)