mirror of
https://github.com/tiennm99/litellm.git
synced 2026-06-17 18:48:36 +00:00
Validation to mcp server name (#12515)
* added validation * add helper util
This commit is contained in:
@@ -25,6 +25,7 @@ from litellm.proxy._experimental.mcp_server.utils import (
|
||||
get_server_name_prefix_tool_mcp,
|
||||
is_tool_name_prefixed,
|
||||
normalize_server_name,
|
||||
validate_mcp_server_name,
|
||||
)
|
||||
from litellm.proxy._types import (
|
||||
LiteLLM_MCPServerTable,
|
||||
@@ -78,6 +79,7 @@ class MCPServerManager:
|
||||
"""
|
||||
verbose_logger.debug("Loading MCP Servers from config-----")
|
||||
for server_name, server_config in mcp_servers_config.items():
|
||||
validate_mcp_server_name(server_name)
|
||||
_mcp_info: dict = server_config.get("mcp_info", None) or {}
|
||||
mcp_info = MCPInfo(**_mcp_info)
|
||||
mcp_info["server_name"] = server_name
|
||||
|
||||
@@ -74,3 +74,26 @@ def is_tool_name_prefixed(tool_name: str) -> bool:
|
||||
True if tool name is prefixed, False otherwise
|
||||
"""
|
||||
return MCP_TOOL_PREFIX_SEPARATOR in tool_name
|
||||
|
||||
def validate_mcp_server_name(server_name: str, raise_http_exception: bool = False) -> None:
|
||||
"""
|
||||
Validate that MCP server name does not contain '-' (hyphen).
|
||||
|
||||
Args:
|
||||
server_name: The server name to validate
|
||||
raise_http_exception: If True, raises HTTPException instead of generic Exception
|
||||
|
||||
Raises:
|
||||
Exception or HTTPException: If server name contains '-'
|
||||
"""
|
||||
if server_name and '-' in server_name:
|
||||
error_message = f"Server name cannot contain '-' (hyphen). Please use '_' (underscore) instead. Found: {server_name}"
|
||||
if raise_http_exception:
|
||||
from fastapi import HTTPException
|
||||
from starlette import status
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail={"error": error_message}
|
||||
)
|
||||
else:
|
||||
raise Exception(error_message)
|
||||
|
||||
@@ -24,6 +24,7 @@ import litellm
|
||||
from litellm._logging import verbose_logger, verbose_proxy_logger
|
||||
from litellm.constants import LITELLM_PROXY_ADMIN_NAME
|
||||
from litellm.proxy.auth.model_checks import get_mcp_server_ids
|
||||
from litellm.proxy._experimental.mcp_server.utils import validate_mcp_server_name
|
||||
|
||||
router = APIRouter(prefix="/v1/mcp", tags=["mcp"])
|
||||
MCP_AVAILABLE: bool = True
|
||||
@@ -344,6 +345,10 @@ if MCP_AVAILABLE:
|
||||
"Database not connected. Connect a database to your proxy"
|
||||
)
|
||||
|
||||
# Server name validation: disallow '-'
|
||||
if payload.alias:
|
||||
validate_mcp_server_name(payload.alias, raise_http_exception=True)
|
||||
|
||||
# AuthZ - restrict only proxy admins to create mcp servers
|
||||
if LitellmUserRoles.PROXY_ADMIN != user_api_key_dict.user_role:
|
||||
raise HTTPException(
|
||||
@@ -484,6 +489,10 @@ if MCP_AVAILABLE:
|
||||
"Database not connected. Connect a database to your proxy - https://docs.litellm.ai/docs/simple_proxy#managing-auth---virtual-keys"
|
||||
)
|
||||
|
||||
# Server name validation: disallow '-'
|
||||
if payload.alias:
|
||||
validate_mcp_server_name(payload.alias, raise_http_exception=True)
|
||||
|
||||
# Authz - restrict only admins to delete mcp servers
|
||||
if LitellmUserRoles.PROXY_ADMIN != user_api_key_dict.user_role:
|
||||
raise HTTPException(
|
||||
|
||||
@@ -254,3 +254,41 @@ async def test_create_mcp_server_auth_failure():
|
||||
# Verify the exception details
|
||||
assert exc_info.value.status_code == 403
|
||||
assert "permission" in str(exc_info.value.detail)
|
||||
|
||||
@pytest.mark.asyncio
|
||||
async def test_create_mcp_server_invalid_alias():
|
||||
"""
|
||||
Test that creating an MCP server with a '-' in the alias fails with the correct error.
|
||||
"""
|
||||
with mock.patch("litellm.proxy.management_endpoints.mcp_management_endpoints.MCP_AVAILABLE", True), \
|
||||
mock.patch("litellm.proxy.management_endpoints.mcp_management_endpoints.get_prisma_client_or_throw") as mock_get_prisma, \
|
||||
mock.patch("litellm.proxy.management_endpoints.mcp_management_endpoints.get_mcp_server") as mock_get_server:
|
||||
|
||||
from litellm.proxy.management_endpoints.mcp_management_endpoints import add_mcp_server
|
||||
from fastapi import HTTPException
|
||||
|
||||
mock_prisma = mock.Mock()
|
||||
mock_get_prisma.return_value = mock_prisma
|
||||
|
||||
# Set up test data with invalid alias
|
||||
server_id = str(uuid.uuid4())
|
||||
mcp_server_request = generate_mcpserver_create_request(server_id=server_id)
|
||||
mcp_server_request.alias = "invalid-alias" # This should trigger the validation error
|
||||
|
||||
# Mock that server does not exist
|
||||
mock_get_server.return_value = None
|
||||
|
||||
user_auth = UserAPIKeyAuth(
|
||||
api_key=TEST_MASTER_KEY,
|
||||
user_id="test-user",
|
||||
user_role=LitellmUserRoles.PROXY_ADMIN
|
||||
)
|
||||
|
||||
with pytest.raises(HTTPException) as exc_info:
|
||||
await add_mcp_server(
|
||||
payload=mcp_server_request,
|
||||
user_api_key_dict=user_auth
|
||||
)
|
||||
|
||||
assert exc_info.value.status_code == 400
|
||||
assert "Server name cannot contain '-' (hyphen). Please use '_' (underscore) instead." in str(exc_info.value.detail)
|
||||
|
||||
@@ -145,7 +145,7 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
||||
label={
|
||||
<span className="text-sm font-medium text-gray-700 flex items-center">
|
||||
MCP Server Name
|
||||
<Tooltip title="Best practice: Use a descriptive name that indicates the server's purpose (e.g., 'GitHub Integration', 'Email Service')">
|
||||
<Tooltip title="Best practice: Use a descriptive name that indicates the server's purpose (e.g., 'GitHub_MCP', 'Email_Service'). Hyphens '-' are not allowed; use underscores '_' instead.">
|
||||
<InfoCircleOutlined className="ml-2 text-blue-400 hover:text-blue-600 cursor-help" />
|
||||
</Tooltip>
|
||||
</span>
|
||||
@@ -153,10 +153,16 @@ const CreateMCPServer: React.FC<CreateMCPServerProps> = ({
|
||||
name="alias"
|
||||
rules={[
|
||||
{ required: false, message: "Please enter a server name" },
|
||||
{
|
||||
validator: (_, value) =>
|
||||
value && value.includes('-')
|
||||
? Promise.reject("Server name cannot contain '-' (hyphen). Please use '_' (underscore) instead.")
|
||||
: Promise.resolve(),
|
||||
},
|
||||
]}
|
||||
>
|
||||
<TextInput
|
||||
placeholder="e.g., GitHub MCP, Zapier MCP, etc."
|
||||
placeholder="e.g., GitHub_MCP, Zapier_MCP, etc."
|
||||
className="rounded-lg border-gray-300 focus:border-blue-500 focus:ring-blue-500"
|
||||
/>
|
||||
</Form.Item>
|
||||
|
||||
@@ -110,7 +110,12 @@ const MCPServerEdit: React.FC<MCPServerEditProps> = ({ mcpServer, accessToken, o
|
||||
<TabPanels className="mt-6">
|
||||
<TabPanel>
|
||||
<Form form={form} onFinish={handleSave} initialValues={mcpServer} layout="vertical">
|
||||
<Form.Item label="MCP Server Name" name="alias">
|
||||
<Form.Item label="MCP Server Name" name="alias" rules={[{
|
||||
validator: (_, value) =>
|
||||
value && value.includes('-')
|
||||
? Promise.reject("Server name cannot contain '-' (hyphen). Please use '_' (underscore) instead.")
|
||||
: Promise.resolve(),
|
||||
}]}>
|
||||
<TextInput />
|
||||
</Form.Item>
|
||||
<Form.Item label="Description" name="description">
|
||||
|
||||
Reference in New Issue
Block a user