From 15659f308367f6d8f524897109e07d385eb49532 Mon Sep 17 00:00:00 2001 From: Mrinal Chanshetty Date: Tue, 3 Nov 2026 14:25:22 -0800 Subject: [PATCH] fix(mcp): match exact provider IDs before names and aliases A provider server_id fell through to the name/alias pass, so a grant for one provider registration also opened any server whose alias equals that ID. Return exact provider IDs early, like gateway IDs. --- .../proxy/mcp_server/mcp_server_manager.py | 2 +- tests/unit/proxy/mcp_server/test_catalog.py | 28 +++++++++++++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/litellm/proxy/mcp_server/mcp_server_manager.py b/litellm/proxy/mcp_server/mcp_server_manager.py index 17706fb9a1a..d60042da448 100644 --- a/litellm/proxy/mcp_server/mcp_server_manager.py +++ b/litellm/proxy/mcp_server/mcp_server_manager.py @@ -7536,7 +7536,7 @@ class MCPServerManager: providers: Final = self.catalog.provider_registrations() expanded: Final[set[str]] = set() for identifier in identifiers: - if identifier in registry: + if identifier in registry or identifier in providers: expanded.add(identifier) continue matches: list[str] = [ diff --git a/tests/unit/proxy/mcp_server/test_catalog.py b/tests/unit/proxy/mcp_server/test_catalog.py index 656f604ace0..9bf31a5d250 100644 --- a/tests/unit/proxy/mcp_server/test_catalog.py +++ b/tests/unit/proxy/mcp_server/test_catalog.py @@ -1081,3 +1081,31 @@ async def test_provider_permission_identifiers_and_groups_follow_config_reload(m assert manager.get_all_mcp_server_ids() == set() assert manager.get_allow_all_keys_server_ids() == [] assert await MCPRequestHandler.get_mcp_servers_from_access_groups(["research"]) == [] + + +@pytest.mark.asyncio +async def test_exact_provider_id_grant_ignores_another_registrations_matching_alias( + monkeypatch: pytest.MonkeyPatch, +) -> None: + from litellm.models.mcp_server import LiteLLM_MCPServerTable + from litellm.proxy import proxy_server + from litellm.proxy.mcp_server.mcp_server_manager import MCPServerManager + + granted: Final = LiteLLM_MCPServerTable( + server_id="native-id", execution_mode="provider", transport=None, + url="https://granted.example/mcp", allowed_tools=["search"], + ) + other: Final = LiteLLM_MCPServerTable( + server_id="other-id", alias="native-id", execution_mode="provider", transport=None, + url="https://other.example/mcp", allowed_tools=["delete"], + ) + tables: Final = SimpleNamespace( + litellm_mcpservertable=SimpleNamespace(find_many=AsyncMock(return_value=[granted, other])), + litellm_config=SimpleNamespace(find_unique=AsyncMock(return_value=SimpleNamespace(reload_revision=1))), + ) + monkeypatch.setattr(proxy_server, "prisma_client", SimpleNamespace(db=tables, writer_db=tables)) + monkeypatch.setattr(proxy_server, "general_settings", {}) + manager: Final = MCPServerManager() + async with manager.catalog.operation(): + assert len(await manager.get_all_mcp_servers_unfiltered()) == 2 + assert manager.expand_permission_list(["native-id"]) == ["native-id"]