From 7ba28bb6dd4cc7926c6792b479086891b048af56 Mon Sep 17 00:00:00 2001 From: jibanez-staticduo Date: Wed, 13 May 2026 17:40:04 +0200 Subject: [PATCH] fix(mcp): share invalid MCP client IP sentinel Define a shared fail-closed MCP client IP sentinel and reuse it across Responses utilities, LazyMCP routing, and tests to avoid security-critical string drift. --- litellm/responses/mcp/litellm_proxy_mcp_handler.py | 3 ++- litellm/responses/utils.py | 4 +++- .../proxy/_experimental/mcp_server/test_mcp_server.py | 7 +++++-- .../responses/mcp/test_litellm_proxy_mcp_handler.py | 5 +++-- 4 files changed, 13 insertions(+), 6 deletions(-) diff --git a/litellm/responses/mcp/litellm_proxy_mcp_handler.py b/litellm/responses/mcp/litellm_proxy_mcp_handler.py index 7f3ad81434a..e6e0f47b008 100644 --- a/litellm/responses/mcp/litellm_proxy_mcp_handler.py +++ b/litellm/responses/mcp/litellm_proxy_mcp_handler.py @@ -20,6 +20,7 @@ from litellm.litellm_core_utils.litellm_logging import Logging as LiteLLMLogging from litellm.proxy._experimental.mcp_server.utils import split_server_prefix_from_name from litellm.responses.main import aresponses from litellm.responses.streaming_iterator import BaseResponsesAPIStreamingIterator +from litellm.responses.utils import INVALID_MCP_CLIENT_IP_SENTINEL from litellm.types.llms.openai import ResponsesAPIResponse from litellm.types.utils import ( CallTypes, @@ -463,7 +464,7 @@ class LiteLLM_Proxy_MCP_Handler: ) standard_client_ip = ( - None if client_ip == "__invalid_mcp_client_ip__" else client_ip + None if client_ip == INVALID_MCP_CLIENT_IP_SENTINEL else client_ip ) return await LiteLLM_Proxy_MCP_Handler._get_standard_mcp_tools( user_api_key_auth=user_api_key_auth, diff --git a/litellm/responses/utils.py b/litellm/responses/utils.py index f2ccdc4cc7f..c19dabb0fec 100644 --- a/litellm/responses/utils.py +++ b/litellm/responses/utils.py @@ -32,6 +32,8 @@ from litellm.types.utils import ( Usage, ) +INVALID_MCP_CLIENT_IP_SENTINEL = "__invalid_mcp_client_ip__" + class ResponsesAPIRequestUtils: """Helper utils for constructing ResponseAPI requests""" @@ -900,7 +902,7 @@ class ResponsesAPIRequestUtils: client_ip = secret_fields.get("mcp_client_ip") if isinstance(client_ip, str) and client_ip.strip(): return client_ip.strip() - return "__invalid_mcp_client_ip__" + return INVALID_MCP_CLIENT_IP_SENTINEL class ResponseAPILoggingUtils: diff --git a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server.py b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server.py index 4e210e698eb..10a5d741a7f 100644 --- a/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server.py +++ b/tests/test_litellm/proxy/_experimental/mcp_server/test_mcp_server.py @@ -21,7 +21,10 @@ from litellm.proxy._types import ( MCPTransport, UserAPIKeyAuth, ) -from litellm.responses.utils import ResponsesAPIRequestUtils +from litellm.responses.utils import ( + INVALID_MCP_CLIENT_IP_SENTINEL, + ResponsesAPIRequestUtils, +) from litellm.types.mcp import MCPAuth from litellm.types.mcp_server.mcp_server_manager import MCPServer @@ -967,7 +970,7 @@ def test_verified_mcp_client_ip_returns_value_or_fail_closed(): ) assert ( ResponsesAPIRequestUtils.get_verified_mcp_client_ip({}) - == "__invalid_mcp_client_ip__" + == INVALID_MCP_CLIENT_IP_SENTINEL ) diff --git a/tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py b/tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py index 0155802415e..16080e01d08 100644 --- a/tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py +++ b/tests/test_litellm/responses/mcp/test_litellm_proxy_mcp_handler.py @@ -10,6 +10,7 @@ import importlib from litellm.responses.mcp.litellm_proxy_mcp_handler import ( LiteLLM_Proxy_MCP_Handler, ) +from litellm.responses.utils import INVALID_MCP_CLIENT_IP_SENTINEL from typing import Any, cast from litellm.types.llms.openai import ResponseAPIUsage, ResponsesAPIResponse from litellm.types.utils import ModelResponse @@ -354,7 +355,7 @@ async def test_lazymcp_catalog_uses_fail_closed_client_ip(monkeypatch): client_ip=ResponsesAPIRequestUtils.get_verified_mcp_client_ip(None), ) - assert captured["client_ip"] == "__invalid_mcp_client_ip__" + assert captured["client_ip"] == INVALID_MCP_CLIENT_IP_SENTINEL @pytest.mark.asyncio @@ -950,7 +951,7 @@ async def test_standard_mcp_preserves_missing_client_ip_behavior(monkeypatch): mcp_tools_with_litellm_proxy=[ {"type": "mcp", "server_url": "litellm_proxy/mcp/standard"} ], - client_ip="__invalid_mcp_client_ip__", + client_ip=INVALID_MCP_CLIENT_IP_SENTINEL, ) assert captured["client_ip"] is None