From a86f6e7eb6c6a6e6e26d2c4f4c68af0007639ece Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Wed, 20 May 2026 17:18:22 +0000 Subject: [PATCH] fix(mcp): surface MCPUpstreamAuthError as 401 in SSE/HTTP transport handlers Both handle_sse_mcp and handle_streamable_http_mcp only caught HTTPException to preserve 401 + WWW-Authenticate challenges, but MCPUpstreamAuthError (raised when a pass-through server's upstream rejects a bearer token mid-session) inherits from Exception. It was falling through to the generic handler and surfacing as an opaque 500. Mirror the REST endpoint behavior: translate MCPUpstreamAuthError into an HTTPException(status_code=e.status_code) with the upstream www-authenticate header so standards-compliant MCP clients trigger the upstream OAuth flow. Co-authored-by: Yassin Kortam --- .../proxy/_experimental/mcp_server/server.py | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/litellm/proxy/_experimental/mcp_server/server.py b/litellm/proxy/_experimental/mcp_server/server.py index 6a014ee5e13..322666b273d 100644 --- a/litellm/proxy/_experimental/mcp_server/server.py +++ b/litellm/proxy/_experimental/mcp_server/server.py @@ -36,6 +36,7 @@ from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLogging from litellm.proxy._experimental.mcp_server.auth.user_api_key_auth_mcp import ( MCPRequestHandler, ) +from litellm.proxy._experimental.mcp_server.exceptions import MCPUpstreamAuthError from litellm.proxy._experimental.mcp_server.discoverable_endpoints import ( get_request_base_url, ) @@ -3164,6 +3165,18 @@ if MCP_AVAILABLE: _client_ip, ): await session_manager.handle_request(scope, receive, send) + except MCPUpstreamAuthError as e: + # Pass-through server returned 401 — surface it to the client so + # standards-compliant MCP clients trigger the upstream OAuth flow. + raise HTTPException( + status_code=e.status_code, + detail="Unauthorized", + headers=( + {"www-authenticate": e.www_authenticate} + if e.www_authenticate + else None + ), + ) except HTTPException: # Re-raise HTTP exceptions to preserve status codes and details raise @@ -3237,6 +3250,18 @@ if MCP_AVAILABLE: _sse_client_ip, ): await sse_session_manager.handle_request(scope, receive, send) + except MCPUpstreamAuthError as e: + # Pass-through server returned 401 — surface it to the client so + # standards-compliant MCP clients trigger the upstream OAuth flow. + raise HTTPException( + status_code=e.status_code, + detail="Unauthorized", + headers=( + {"www-authenticate": e.www_authenticate} + if e.www_authenticate + else None + ), + ) except HTTPException: # Re-raise HTTP exceptions to preserve status codes and details # (e.g. 401 + WWW-Authenticate challenges from OAuth pass-through).