mirror of
https://github.com/BerriAI/litellm.git
synced 2026-09-22 00:31:44 +00:00
fix uvx mcp servers
This commit is contained in:
parent
cd9c511df6
commit
79f4d899d4
3 changed files with 44 additions and 0 deletions
|
|
@ -133,6 +133,11 @@ MCP_OAUTH2_TOKEN_CACHE_DEFAULT_TTL = int(
|
|||
# npm/npx needs a writable cache dir; in containers the default (~/.npm)
|
||||
# may not exist or be read-only. /tmp is always writable.
|
||||
MCP_NPM_CACHE_DIR = os.getenv("MCP_NPM_CACHE_DIR", "/tmp/.npm_mcp_cache")
|
||||
|
||||
# Default uv cache directory for uvx-based STDIO MCP servers.
|
||||
# uvx needs a writable cache dir; in containers the default (~/.cache/uv)
|
||||
# may not exist or be read-only, causing uvx to fail when downloading packages.
|
||||
MCP_UV_CACHE_DIR = os.getenv("MCP_UV_CACHE_DIR", "/tmp/.uv_mcp_cache")
|
||||
MCP_OAUTH2_TOKEN_CACHE_MIN_TTL = int(os.getenv("MCP_OAUTH2_TOKEN_CACHE_MIN_TTL", "10"))
|
||||
|
||||
# MCP timeout defaults (seconds). Override via env vars for slow/custom MCP servers.
|
||||
|
|
|
|||
|
|
@ -38,6 +38,7 @@ from litellm.constants import (
|
|||
MCP_METADATA_TIMEOUT,
|
||||
MCP_NPM_CACHE_DIR,
|
||||
MCP_STDIO_ALLOWED_COMMANDS,
|
||||
MCP_UV_CACHE_DIR,
|
||||
MCP_TOOL_LISTING_TIMEOUT,
|
||||
)
|
||||
from litellm.exceptions import BlockedPiiEntityError, GuardrailRaisedException
|
||||
|
|
@ -1123,6 +1124,11 @@ class MCPServerManager:
|
|||
# or be read-only, causing npx to fail with ENOENT.
|
||||
if "NPM_CONFIG_CACHE" not in resolved_env:
|
||||
resolved_env["NPM_CONFIG_CACHE"] = MCP_NPM_CACHE_DIR
|
||||
# Ensure uvx-based STDIO MCP servers have a writable cache dir.
|
||||
# In containers the default (~/.cache/uv) may not exist
|
||||
# or be read-only, causing uvx to fail when downloading packages.
|
||||
if "UV_CACHE_DIR" not in resolved_env:
|
||||
resolved_env["UV_CACHE_DIR"] = MCP_UV_CACHE_DIR
|
||||
# Defense-in-depth: block commands not in the allowlist.
|
||||
# The Pydantic validator blocks new servers; this catches legacy
|
||||
# config/DB records predating the allowlist.
|
||||
|
|
|
|||
|
|
@ -160,6 +160,39 @@ class TestMCPServerManager:
|
|||
client2 = await manager._create_mcp_client(server_with_cache)
|
||||
assert client2.stdio_config["env"]["NPM_CONFIG_CACHE"] == "/custom/cache"
|
||||
|
||||
async def test_create_mcp_client_stdio_injects_uv_cache_dir(self):
|
||||
"""Test that _create_mcp_client injects UV_CACHE_DIR for uvx when not already set,
|
||||
and preserves user-provided UV_CACHE_DIR when present."""
|
||||
from litellm.constants import MCP_UV_CACHE_DIR
|
||||
|
||||
manager = MCPServerManager()
|
||||
|
||||
# Case 1: UV_CACHE_DIR not set -> should be injected
|
||||
server_no_cache = MCPServer(
|
||||
server_id="stdio-uvx-1",
|
||||
name="test_uvx_server",
|
||||
url=None,
|
||||
transport=MCPTransport.stdio,
|
||||
command="uvx",
|
||||
args=["mcp-server-fetch"],
|
||||
env={},
|
||||
)
|
||||
client = await manager._create_mcp_client(server_no_cache)
|
||||
assert client.stdio_config["env"]["UV_CACHE_DIR"] == MCP_UV_CACHE_DIR
|
||||
|
||||
# Case 2: UV_CACHE_DIR already set -> should NOT be overwritten
|
||||
server_with_cache = MCPServer(
|
||||
server_id="stdio-uvx-2",
|
||||
name="test_uvx_server_custom",
|
||||
url=None,
|
||||
transport=MCPTransport.stdio,
|
||||
command="uvx",
|
||||
args=["mcp-server-fetch"],
|
||||
env={"UV_CACHE_DIR": "/custom/uv_cache"},
|
||||
)
|
||||
client2 = await manager._create_mcp_client(server_with_cache)
|
||||
assert client2.stdio_config["env"]["UV_CACHE_DIR"] == "/custom/uv_cache"
|
||||
|
||||
def test_build_stdio_env_only_accepts_x_prefixed_placeholders(self):
|
||||
"""Ensure only ${X-*} placeholders are substituted from headers."""
|
||||
manager = MCPServerManager()
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue