This commit is contained in:
Yug 2026-04-30 22:24:34 +05:30
parent 62d647f61a
commit 47017e4812
4 changed files with 22 additions and 13 deletions

View file

@ -1229,13 +1229,13 @@ class MCPServerManager:
if server.command:
base_command = os.path.basename(server.command)
# Strip .exe/.cmd/.bat/.com suffix for Windows compatibility
base_command_no_ext = base_command
base_command_no_ext = base_command.lower()
for ext in [".exe", ".cmd", ".bat", ".com"]:
if base_command.lower().endswith(ext):
base_command_no_ext = base_command[: -len(ext)].lower()
break
if (
base_command not in MCP_STDIO_ALLOWED_COMMANDS
base_command.lower() not in MCP_STDIO_ALLOWED_COMMANDS
and base_command_no_ext not in MCP_STDIO_ALLOWED_COMMANDS
):
raise HTTPException(

View file

@ -88,8 +88,13 @@ def _resolve_model_from_preferences(
# Fall back to first available model
if available_model_names:
return available_model_names[0]
# Last resort - use LiteLLM default or return None
return getattr(litellm, "default_mcp_sampling_model", None) or "gpt-4o-mini"
# Last resort - use LiteLLM default or raise error
default_sampling_model = getattr(litellm, "default_mcp_sampling_model", None)
if default_sampling_model:
return default_sampling_model
raise ValueError(
"No model could be resolved for MCP sampling. Please configure 'default_mcp_sampling_model' in your LiteLLM configuration."
)
def _convert_mcp_content_to_openai(

View file

@ -1217,13 +1217,13 @@ class NewMCPServerRequest(LiteLLMPydanticObjectBase):
# Validate command against allowlist to prevent arbitrary execution
base_command = os.path.basename(values["command"])
# Strip .exe/.cmd/.bat/.com suffix for Windows compatibility
base_command_no_ext = base_command
base_command_no_ext = base_command.lower()
for ext in [".exe", ".cmd", ".bat", ".com"]:
if base_command.lower().endswith(ext):
base_command_no_ext = base_command[: -len(ext)].lower()
base_command_no_ext = base_command.lower()[: -len(ext)].lower()
break
if (
base_command not in MCP_STDIO_ALLOWED_COMMANDS
base_command.lower() not in MCP_STDIO_ALLOWED_COMMANDS
and base_command_no_ext not in MCP_STDIO_ALLOWED_COMMANDS
):
raise ValueError(
@ -1294,13 +1294,13 @@ class UpdateMCPServerRequest(LiteLLMPydanticObjectBase):
# Validate command against allowlist to prevent arbitrary execution
base_command = os.path.basename(values["command"])
# Strip .exe/.cmd/.bat/.com suffix for Windows compatibility
base_command_no_ext = base_command
base_command_no_ext = base_command.lower()
for ext in [".exe", ".cmd", ".bat", ".com"]:
if base_command.lower().endswith(ext):
base_command_no_ext = base_command[: -len(ext)].lower()
base_command_no_ext = base_command.lower()[: -len(ext)].lower()
break
if (
base_command not in MCP_STDIO_ALLOWED_COMMANDS
base_command.lower() not in MCP_STDIO_ALLOWED_COMMANDS
and base_command_no_ext not in MCP_STDIO_ALLOWED_COMMANDS
):
raise ValueError(

View file

@ -7,7 +7,7 @@ from contextlib import asynccontextmanager
from litellm.proxy._experimental.mcp_server.server import (
handle_sse_mcp_endpoint,
handle_sse_post_messages,
_captured_session_id_var,
_captured_session_id_container_var,
_session_id_auth_storage,
)
from litellm.proxy._types import UserAPIKeyAuth
@ -29,7 +29,9 @@ async def test_session_id_capture_and_binding():
@asynccontextmanager
async def mock_connect_sse(scope, receive, send):
# Directly set the ContextVar to simulate our capturing dict's behavior
_captured_session_id_var.set(session_id)
container = _captured_session_id_container_var.get()
if container is not None:
container["session_id"] = session_id
yield (AsyncMock(), AsyncMock())
mock_sse.connect_sse = MagicMock(side_effect=mock_connect_sse)
@ -174,7 +176,9 @@ async def test_anonymous_session_still_works():
@asynccontextmanager
async def mock_connect_sse(scope, receive, send):
_captured_session_id_var.set(session_id)
container = _captured_session_id_container_var.get()
if container is not None:
container["session_id"] = session_id
yield (AsyncMock(), AsyncMock())
mock_sse.connect_sse = MagicMock(side_effect=mock_connect_sse)