From a55d06321c334d6fdb76d6bac2ff96abbedcac19 Mon Sep 17 00:00:00 2001 From: Ishaan Jaffer Date: Mon, 23 Mar 2026 12:45:51 -0700 Subject: [PATCH] fix(mcp): admin toolset visibility, in-place tool name mutation, test helper coercion --- .../_experimental/mcp_server/mcp_server_manager.py | 13 ++++++++++--- .../mcp_management_endpoints.py | 11 +++++------ .../mcp_server/test_mcp_toolset_scope.py | 2 +- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py index 9f241837dd4..7966bd632e7 100644 --- a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py +++ b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py @@ -1193,9 +1193,16 @@ class MCPServerManager: if not add_prefix: prefix = get_server_prefix(server) sep = MCP_TOOL_PREFIX_SEPARATOR - for t in tools: - if t.name.startswith(f"{prefix}{sep}"): - t.name = t.name[len(prefix) + len(sep) :] + tools = [ + ( + t.model_copy( + update={"name": t.name[len(prefix) + len(sep) :]} + ) + if t.name.startswith(f"{prefix}{sep}") + else t + ) + for t in tools + ] return tools else: tools = await self._fetch_tools_with_timeout(client, server.name) diff --git a/litellm/proxy/management_endpoints/mcp_management_endpoints.py b/litellm/proxy/management_endpoints/mcp_management_endpoints.py index 3c32df966a6..1b59f573383 100644 --- a/litellm/proxy/management_endpoints/mcp_management_endpoints.py +++ b/litellm/proxy/management_endpoints/mcp_management_endpoints.py @@ -2103,16 +2103,15 @@ if MCP_AVAILABLE: ) is_admin = _user_has_admin_view(user_api_key_dict) op = user_api_key_dict.object_permission - # mcp_toolsets=None means the field was never set. - # For admins: None → no restriction → return all. - # For non-admins: None → no toolsets explicitly granted → return nothing. + # mcp_toolsets=None or [] both mean "not restricted by toolsets". + # For admins: either value → no restriction → return all. + # For non-admins: either value → no toolsets explicitly granted → return nothing. + # (An admin whose DB row has mcp_toolsets=[] should still see all toolsets.) raw_toolsets = getattr(op, "mcp_toolsets", None) if op else None - if raw_toolsets is None: + if not raw_toolsets: if is_admin: return await list_mcp_toolsets(prisma_client) return [] - if not raw_toolsets: - return [] return await list_mcp_toolsets(prisma_client, toolset_ids=raw_toolsets) @router.get( diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_toolset_scope.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_toolset_scope.py index c9732a53a70..5e85e560835 100644 --- a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_toolset_scope.py +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_toolset_scope.py @@ -22,7 +22,7 @@ def _make_auth( object_permission_id="test", mcp_servers=mcp_servers, mcp_tool_permissions=mcp_tool_permissions or {}, - mcp_toolsets=mcp_toolsets or [], + mcp_toolsets=mcp_toolsets, ) return UserAPIKeyAuth( api_key="sk-test",