diff --git a/litellm/proxy/_experimental/mcp_server/mcp_debug.py b/litellm/proxy/_experimental/mcp_server/mcp_debug.py index ccce0aaf615..06b17bc59c9 100644 --- a/litellm/proxy/_experimental/mcp_server/mcp_debug.py +++ b/litellm/proxy/_experimental/mcp_server/mcp_debug.py @@ -410,7 +410,7 @@ def _safe_text(value: str, limit: int = _BODY_PREVIEW_CHARS) -> str: def safe_upstream_url(url: httpx.URL) -> str: - return _safe_text(str(url.copy_with(username="", password="", query=None, fragment=None))) + return _safe_text(str(url.copy_with(username="", password="", path="/", query=None, fragment=None))) def _sensitive_field(key: str) -> bool: diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/outbound_credentials/test_client_credentials.py b/tests/test_litellm/proxy/_experimental/mcp_server/outbound_credentials/test_client_credentials.py index 1550b812a87..774cd022703 100644 --- a/tests/test_litellm/proxy/_experimental/mcp_server/outbound_credentials/test_client_credentials.py +++ b/tests/test_litellm/proxy/_experimental/mcp_server/outbound_credentials/test_client_credentials.py @@ -518,7 +518,7 @@ async def test_token_exchange_failure_diagnostics(mode, monkeypatch, caplog): assert not caplog.text elif mode in {"timeout", "connect"}: assert isinstance(result, TokenEndpointUnreachable) - assert "POST https://idp/token failed" in caplog.text + assert "POST https://idp/ failed" in caplog.text else: - assert "POST https://idp/token -> HTTP" in caplog.text + assert "POST https://idp/ -> HTTP" in caplog.text assert {"denied":"denied", "invalid":"invalid response", "missing":"no access token"}[mode] in caplog.text diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_debug.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_debug.py index dced871e146..14e14882f3f 100644 --- a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_debug.py +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_debug.py @@ -233,7 +233,7 @@ class TestDescribeUpstreamHttpFailure: ) described = describe_upstream_http_failure(exc) assert described is not None - assert "POST https://upstream.example/apis/mcp -> HTTP 500" in described + assert "POST https://upstream.example/ -> HTTP 500" in described assert '{"method":"initialize"' in described assert 'response body: {"error":"boom"}' in described @@ -545,3 +545,15 @@ async def test_streamed_error_redacts_reflected_credentials_before_capture(): assert detail is not None and "invalid_client" in detail and "Rejected" in detail assert secret not in detail and "REDACTED" in detail assert await response.aread() == raw + + +@pytest.mark.parametrize("path", ["/credential-path-value/mcp", "/oauth/credential-path-value/token"]) +def test_failure_diagnostics_omit_credential_bearing_url_paths(path): + request = httpx.Request("POST", "https://upstream.example" + path) + response = httpx.Response(401, request=request, json={"error": "access_denied"}) + error = httpx.HTTPStatusError("denied", request=request, response=response) + diagnostic = describe_upstream_http_failure(error) + assert diagnostic is not None + assert "credential-path-value" not in diagnostic + assert "POST https://upstream.example/ -> HTTP 401" in diagnostic + assert "access_denied" in diagnostic diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_oauth_passthrough_tools.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_oauth_passthrough_tools.py index f8e4cd0c6ae..3f5d4ad83ea 100644 --- a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_oauth_passthrough_tools.py +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_oauth_passthrough_tools.py @@ -456,7 +456,7 @@ async def test_fetch_tools_logs_upstream_request_details_on_500(caplog): with pytest.raises(MCPServerListError): await manager._fetch_tools_with_timeout(mock_client, "sample_docs") - assert "POST https://upstream/apis/mcp -> HTTP 500" in caplog.text + assert "POST https://upstream/ -> HTTP 500" in caplog.text assert '"method":"initialize"' in caplog.text assert "upstream-token-0123456789" not in caplog.text @@ -473,5 +473,5 @@ async def test_client_creation_failure_logs_sanitized_exchange(monkeypatch, capl with caplog.at_level(logging.WARNING, logger="LiteLLM"): with pytest.raises(MCPServerListError): await manager._get_tools_from_server(server) - assert "POST https://upstream/mcp -> HTTP 500" in caplog.text + assert "POST https://upstream/ -> HTTP 500" in caplog.text assert "missing_scope" in caplog.text and "query-secret" not in caplog.text