diff --git a/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py b/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py index eeadeb290f3..ef42fef312d 100644 --- a/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py @@ -865,7 +865,6 @@ async def exchange_token_with_server( ) raise token_response = response.json() - access_token = token_response["access_token"] # Validate token response against server-configured rules before any storage. # This rejects tokens from wrong Slack workspaces, Atlassian orgs, etc. @@ -912,7 +911,7 @@ async def exchange_token_with_server( return await _mint_bridge_delegate_token_response(request, mcp_server, token_response) result = { - "access_token": access_token, + "access_token": token_response["access_token"], "token_type": token_response.get("token_type", "Bearer"), } diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_discoverable_endpoints.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_discoverable_endpoints.py index e69d94d9615..5826d1f28b6 100644 --- a/tests/test_litellm/proxy/_experimental/mcp_server/test_discoverable_endpoints.py +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_discoverable_endpoints.py @@ -4449,6 +4449,23 @@ async def test_oauth_delegate_bridge_token_exchange_fails_closed_without_litellm assert exc.value.detail["error"] == "invalid_request" +@pytest.mark.asyncio +async def test_oauth_delegate_bridge_token_exchange_missing_access_token_is_502_not_keyerror(): + """When the upstream token response has no access_token, a dcr_bridge oauth_delegate exchange + returns a clean 502 rather than raising a KeyError. The eager access_token extraction used to run + before the bridge branch, so a missing token raised KeyError and _bridge_grant_from_token_response's + nil guard (which maps to 502) was dead code; the extraction now lives on the non-bridge path only.""" + from litellm.types.mcp import MCPAuth + + server = _bridge_server(auth_type=MCPAuth.oauth_delegate) + upstream = {"token_type": "Bearer", "expires_in": 3600} + + with pytest.raises(HTTPException) as exc: + await _exchange_for_bridge_server(server, upstream, key_hash="hashed-litellm-key-77") + + assert exc.value.status_code == 502 + + @pytest.mark.asyncio async def test_true_passthrough_bridge_token_exchange_returns_raw_upstream_token(): """Only oauth_delegate mints. A true_passthrough dcr_bridge server relays the raw upstream token