diff --git a/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py b/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py index 3139b679e5c..86e97b55a8e 100644 --- a/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py +++ b/litellm/proxy/_experimental/mcp_server/discoverable_endpoints.py @@ -2416,7 +2416,7 @@ def _build_oauth_authorization_server_response( _raise_unless_oauth2_discovery_server(mcp_server, mcp_server_name, "not an OAuth authorization server") return { - "issuer": f"{request_base_url}/{mcp_server_name}" if mcp_server_name else request_base_url, + "issuer": request_base_url, # point to your proxy "authorization_endpoint": authorization_endpoint, "token_endpoint": token_endpoint, "response_types_supported": ["code"], @@ -2464,14 +2464,7 @@ async def oauth_authorization_server_mcp(request: Request, mcp_server_name: str # Alias for standard OpenID discovery @router.get("/.well-known/openid-configuration") async def openid_configuration(request: Request): - response: Final = await oauth_authorization_server_mcp(request) - if not isinstance(response, dict): - return response - - request_base_url: Final = get_request_base_url(request) - # OIDC verifiers derive this URL from their configured issuer (the proxy origin), - # so keep the origin issuer here even when root resolution scoped the metadata. - unscoped_response: Final = {**response, "issuer": request_base_url} + response = await oauth_authorization_server_mcp(request) # If MCPJWTSigner is active, augment the discovery doc with JWKS fields so # MCP servers and gateways (e.g. AWS Bedrock AgentCore Gateway) can resolve @@ -2483,15 +2476,17 @@ async def openid_configuration(request: Request): signer: Final = get_mcp_jwt_signer() if signer is not None: - return { - **unscoped_response, - "jwks_uri": f"{request_base_url}/.well-known/jwks.json", - "id_token_signing_alg_values_supported": ["RS256"], - } + request_base_url: Final = get_request_base_url(request) + if isinstance(response, dict): + response = { + **response, + "jwks_uri": f"{request_base_url}/.well-known/jwks.json", + "id_token_signing_alg_values_supported": ["RS256"], + } except ImportError: pass - return unscoped_response + return response @router.get("/.well-known/jwks.json") 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 6bfd83b82b8..9bc84b43fc5 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 @@ -8163,40 +8163,8 @@ async def test_bare_origin_discovery_resolves_single_server_not_aggregate(): ) # per-server, not aggregate: the single server's name is in the endpoints assert "/test_oauth/authorize" in authorization_response["authorization_endpoint"] - expected_issuer = "https://llm.example.com/test_oauth" - assert authorization_response["issuer"] == expected_issuer - assert resource_response["authorization_servers"] == [expected_issuer] - finally: - global_mcp_server_manager.registry.clear() - - -@pytest.mark.asyncio -async def test_openid_configuration_alias_keeps_origin_issuer_on_root_resolution(): - """OIDC verifiers derive /.well-known/openid-configuration from their configured issuer - (the proxy origin), so the alias must keep the origin issuer even when single-server - root resolution scopes the underlying authorization-server metadata.""" - from fastapi import Request - - from litellm.proxy._experimental.mcp_server.discoverable_endpoints import ( - openid_configuration, - ) - from litellm.proxy._experimental.mcp_server.mcp_server_manager import ( - global_mcp_server_manager, - ) - - global_mcp_server_manager.registry.clear() - oauth2_server = _create_oauth2_server() - global_mcp_server_manager.registry[oauth2_server.server_id] = oauth2_server - - mock_request = MagicMock(spec=Request) - mock_request.base_url = "https://llm.example.com/" - mock_request.headers = {} - - try: - response = await openid_configuration(mock_request) - assert isinstance(response, dict) - assert response["issuer"] == "https://llm.example.com" - assert "/test_oauth/authorize" in response["authorization_endpoint"] + assert authorization_response["issuer"] == "https://llm.example.com" + assert resource_response["authorization_servers"] == ["https://llm.example.com/test_oauth"] finally: global_mcp_server_manager.registry.clear()