mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-25 01:02:15 +00:00
fix(mcp): refine upstream OAuth metadata fallback
This commit is contained in:
parent
0daeeab884
commit
8e864f33ee
2 changed files with 37 additions and 8 deletions
|
|
@ -748,7 +748,7 @@ async def fetch_upstream_oauth_protected_resource(
|
|||
|
||||
async_client = get_async_httpx_client(llm_provider=httpxSpecialProvider.Oauth2Check)
|
||||
|
||||
last_error: Optional[Exception] = None
|
||||
network_errors: list[Exception] = []
|
||||
for candidate in candidates:
|
||||
try:
|
||||
response = await async_client.get(
|
||||
|
|
@ -756,13 +756,13 @@ async def fetch_upstream_oauth_protected_resource(
|
|||
headers={"Accept": "application/json"},
|
||||
)
|
||||
except Exception as exc: # network / connect errors
|
||||
last_error = exc
|
||||
if is_network_error(exc):
|
||||
network_errors.append(exc)
|
||||
continue
|
||||
if response.status_code == 200:
|
||||
try:
|
||||
payload = response.json()
|
||||
except Exception as exc:
|
||||
last_error = exc
|
||||
except Exception:
|
||||
continue
|
||||
if isinstance(payload, dict):
|
||||
_OAUTH_METADATA_CACHE[cache_key] = (
|
||||
|
|
@ -771,10 +771,8 @@ async def fetch_upstream_oauth_protected_resource(
|
|||
)
|
||||
return payload
|
||||
|
||||
if last_error is not None and all(
|
||||
is_network_error(last_error) for _ in candidates
|
||||
):
|
||||
raise last_error
|
||||
if len(network_errors) == len(candidates):
|
||||
raise network_errors[-1]
|
||||
|
||||
return None
|
||||
|
||||
|
|
|
|||
|
|
@ -258,6 +258,37 @@ async def test_oauth_protected_resource_passthrough_network_error_returns_502():
|
|||
assert exc_info.value.status_code == 502
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_fetch_upstream_metadata_returns_none_when_not_all_candidates_network_fail():
|
||||
passthrough_server = MCPServer(
|
||||
server_id="passthrough-partial-network",
|
||||
name="jet_knowledge_qa",
|
||||
server_name="jet_knowledge_qa",
|
||||
alias="jet_knowledge_qa",
|
||||
url="https://upstream.example.com/mcp",
|
||||
transport=MCPTransport.http,
|
||||
auth_type=MCPAuth.none,
|
||||
extra_headers=["Authorization"],
|
||||
)
|
||||
|
||||
not_found_response = MagicMock()
|
||||
not_found_response.status_code = 404
|
||||
mock_client = MagicMock()
|
||||
mock_client.get = AsyncMock(
|
||||
side_effect=[not_found_response, httpx.ConnectError("path fallback failed")]
|
||||
)
|
||||
|
||||
with patch.object(
|
||||
discoverable_endpoints, "get_async_httpx_client", return_value=mock_client
|
||||
):
|
||||
result = await discoverable_endpoints.fetch_upstream_oauth_protected_resource(
|
||||
passthrough_server
|
||||
)
|
||||
|
||||
assert result is None
|
||||
assert mock_client.get.await_count == 2
|
||||
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_oauth_protected_resource_gateway_managed_unchanged():
|
||||
"""Regression guard: OAuth2 servers still advertise the gateway as AS."""
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue