diff --git a/litellm/proxy/management_endpoints/mcp_management_endpoints.py b/litellm/proxy/management_endpoints/mcp_management_endpoints.py index e3f39864b76..ad2c87750da 100644 --- a/litellm/proxy/management_endpoints/mcp_management_endpoints.py +++ b/litellm/proxy/management_endpoints/mcp_management_endpoints.py @@ -146,6 +146,7 @@ if MCP_AVAILABLE: MCPUserCredentialResponse, NewMCPServerRequest, RejectMCPServerRequest, + SpecialHeaders, SpecialMCPServerName, UpdateMCPServerRequest, UserAPIKeyAuth, @@ -1457,7 +1458,7 @@ if MCP_AVAILABLE: servers only (browser OAuth). When present, global-registry access follows admin / allowlist rules via ``_get_cached_temporary_mcp_server_or_404``. - Only non-empty **string** ``Authorization`` values trigger a full auth + Only non-empty **string** auth header values trigger a full auth pipeline import (tests and mocks may attach MagicMock headers). """ try: @@ -1465,13 +1466,23 @@ if MCP_AVAILABLE: except Exception: return None raw: object = None - for key in ("authorization", "Authorization"): - try: - candidate = headers.get(key) - except Exception: - candidate = None - if isinstance(candidate, str) and candidate.strip(): - raw = candidate + for header_name in ( + SpecialHeaders.openai_authorization.value, + SpecialHeaders.azure_authorization.value, + SpecialHeaders.anthropic_authorization.value, + SpecialHeaders.google_ai_studio_authorization.value, + SpecialHeaders.azure_apim_authorization.value, + SpecialHeaders.custom_litellm_api_key.value, + ): + for key in (header_name, header_name.lower()): + try: + candidate = headers.get(key) + except Exception: + candidate = None + if isinstance(candidate, str) and candidate.strip(): + raw = candidate + break + if isinstance(raw, str): break if not isinstance(raw, str) or not raw.strip(): return None diff --git a/tests/test_litellm/proxy/management_endpoints/test_mcp_management_endpoints.py b/tests/test_litellm/proxy/management_endpoints/test_mcp_management_endpoints.py index f144afcff53..5d6f0435d8d 100644 --- a/tests/test_litellm/proxy/management_endpoints/test_mcp_management_endpoints.py +++ b/tests/test_litellm/proxy/management_endpoints/test_mcp_management_endpoints.py @@ -1551,6 +1551,27 @@ class TestTemporaryMCPSessionEndpoints: assert "permission" in str(exc_info.value) + @pytest.mark.asyncio + async def test_try_resolve_mcp_oauth_broker_user_accepts_api_key_header(self): + from litellm.proxy.management_endpoints.mcp_management_endpoints import ( + _try_resolve_mcp_oauth_broker_user, + ) + + request = MagicMock() + request.headers = {"api-key": "sk-alt-header"} + user_auth = generate_mock_user_api_key_auth( + user_role=LitellmUserRoles.INTERNAL_USER, + ) + + with patch( + "litellm.proxy.auth.user_api_key_auth.user_api_key_auth_from_request_headers", + AsyncMock(return_value=user_auth), + ) as auth_mock: + result = await _try_resolve_mcp_oauth_broker_user(request) + + assert result is user_auth + auth_mock.assert_awaited_once_with(request) + @pytest.mark.asyncio async def test_mcp_authorize_proxies_to_discoverable_endpoint(self): from litellm.proxy.management_endpoints.mcp_management_endpoints import (