From df076ce24cb4d82b602f97ac08a01242543e0554 Mon Sep 17 00:00:00 2001 From: yucheng Date: Sat, 26 Sep 2026 10:01:42 +0000 Subject: [PATCH] fix(mcp): keep the exact-name fallback in the challenge resolver and reformat get_mcp_server_answering_to now falls back to get_mcp_server_by_name when no published prefix form matches, preserving the exact-name lookup the preemptive path had before the router-equivalent resolver. Applies ruff format to caller_sign_in.py and agent_365.py per the lint gate. Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- litellm/proxy/_experimental/mcp_server/caller_sign_in.py | 4 +--- .../proxy/_experimental/mcp_server/mcp_server_manager.py | 5 +++-- .../guardrails/guardrail_hooks/agent_365/agent_365.py | 9 ++++++--- 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/litellm/proxy/_experimental/mcp_server/caller_sign_in.py b/litellm/proxy/_experimental/mcp_server/caller_sign_in.py index 9d9b8b7297e..95476bd7c20 100644 --- a/litellm/proxy/_experimental/mcp_server/caller_sign_in.py +++ b/litellm/proxy/_experimental/mcp_server/caller_sign_in.py @@ -107,9 +107,7 @@ def caller_sign_in_for(server: MCPServer, user_api_key_auth: UserAPIKeyAuth | No contribution for contribution in ( *( - ( - CallerSignIn(issuers=jwt_auth_issuers(), scopes=tuple(server.scopes or ())), - ) + (CallerSignIn(issuers=jwt_auth_issuers(), scopes=tuple(server.scopes or ())),) if server.auth_type == MCPAuth.oauth2_token_exchange else () ), diff --git a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py index c38d156dd46..1bb3cedbd02 100644 --- a/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py +++ b/litellm/proxy/_experimental/mcp_server/mcp_server_manager.py @@ -7193,7 +7193,8 @@ class MCPServerManager: def get_mcp_server_answering_to(self, name: str, client_ip: str | None = None) -> MCPServer | None: """The server a scoped ``/mcp/{name}`` connect resolves to, matched the way the router matches - it: case-insensitive over server_id, name and every published prefix form.""" + it: case-insensitive over server_id, name and every published prefix form, then the exact + name lookup as the fallback.""" return next( ( server @@ -7201,7 +7202,7 @@ class MCPServerManager: if server_answers_to_name(server, name) ), None, - ) + ) or self.get_mcp_server_by_name(name, client_ip=client_ip) def get_filtered_registry(self, client_ip: str | None = None) -> dict[str, MCPServer]: """ diff --git a/litellm/proxy/guardrails/guardrail_hooks/agent_365/agent_365.py b/litellm/proxy/guardrails/guardrail_hooks/agent_365/agent_365.py index e5397a7269d..cc2df181574 100644 --- a/litellm/proxy/guardrails/guardrail_hooks/agent_365/agent_365.py +++ b/litellm/proxy/guardrails/guardrail_hooks/agent_365/agent_365.py @@ -445,9 +445,12 @@ class Agent365Guardrail(CustomGuardrail): "user_api_key_team_metadata": user_api_key_auth.team_metadata, # pyright: ignore[reportUnknownMemberType] # UserAPIKeyAuth.team_metadata is a raw dict } } - if self.should_run_guardrail( # pyright: ignore[reportUnknownMemberType, reportUnknownArgumentType] # should_run_guardrail takes an untyped data dict - data=probe, event_type=GuardrailEventHooks.pre_mcp_call - ) is not True: + if ( + self.should_run_guardrail( # pyright: ignore[reportUnknownMemberType, reportUnknownArgumentType] # should_run_guardrail takes an untyped data dict + data=probe, event_type=GuardrailEventHooks.pre_mcp_call + ) + is not True + ): return None return CallerSignIn( issuers=(ENTRA_ISSUER_TEMPLATE.format(tenant_id=self.tenant_id),),