BerriAI/litellm · error · HTTPException
MCP Security: request references unregistered MCP server(s):
Error message
MCP Security: request references unregistered MCP server(s): {', '.join(sorted(unregistered))}. Only servers registered on this gateway are allowed. What it means
The MCP security guardrail inspects request tools of type mcp whose server_url uses the litellm_proxy:// prefix, extracts the server name, and compares it against the gateway's MCP server registry (global_mcp_server_manager, fed by the mcp_servers config). Unregistered names trigger HTTPException 400 with the sorted list when on_violation is 'block', or just a warning log when 'alert'.
Source
Thrown at litellm/proxy/guardrails/guardrail_hooks/mcp_security/mcp_security_guardrail.py:60
cache: Any,
data: dict,
call_type: str,
) -> Exception | str | dict | None:
if self.should_run_guardrail(data=data, event_type=GuardrailEventHooks.pre_call) is not True:
return data
unregistered: Final = self._find_unregistered_mcp_servers(data)
if not unregistered:
return data
message: Final = (
f"MCP Security: request references unregistered MCP server(s): "
f"{', '.join(sorted(unregistered))}. "
f"Only servers registered on this gateway are allowed."
)
if self.on_violation == "block":
raise HTTPException(
status_code=400,
detail={
"error": "Violated guardrail policy",
"guardrail": "mcp_security",
"unregistered_servers": sorted(unregistered),
"detection_message": message,
},
)
else:
verbose_proxy_logger.warning(message)
return data
@staticmethod
def _extract_mcp_server_names_from_tools(tools: list[dict]) -> set[str]:
"""Extract MCP server names from tools with type=mcp and litellm_proxy server_url."""
server_names: Final[set[str]] = set()
for tool in tools:View on GitHub (pinned to 77b7c6c40c)
Solutions
- Register the referenced server under mcp_servers in the gateway config with the exact name clients use
- Fix the client's tool definition so server_url uses the registered name (check spelling/case)
- If evaluation without blocking is wanted, set on_violation: 'alert' so violations only log
- Remove stale tool references from clients after deleting a server from the registry
Example fix
# before - request references a server the gateway never registered
tools = [{"type": "mcp", "server_url": "litellm_proxy://filesystem"}]
# after - name matches the mcp_servers registry entry (config: mcp_servers: {fs: {...}})
tools = [{"type": "mcp", "server_url": "litellm_proxy://fs"}] Defensive patterns
Strategy: validation
Validate before calling
def validate_mcp_tool_servers(tools: list[dict], registered: set[str]) -> None:
prefix = "litellm_proxy://"
referenced = {
t["server_url"][len(prefix):]
for t in tools
if isinstance(t, dict) and t.get("type") == "mcp"
and isinstance(t.get("server_url"), str)
and t["server_url"].startswith(prefix)
}
unknown = referenced - registered
assert not unknown, f"tools reference unregistered MCP servers: {sorted(unknown)}; registered: {sorted(registered)}"
# registered = set of keys under mcp_servers in the gateway config
validate_mcp_tool_servers(request_tools, registered_server_names) Type guard
def references_registered_servers_only(tools: object, registered: set[str]) -> bool:
if not isinstance(tools, list):
return True
prefix = "litellm_proxy://"
for t in tools:
if isinstance(t, dict) and t.get("type") == "mcp" and isinstance(t.get("server_url"), str):
url = t["server_url"]
if url.startswith(prefix) and url[len(prefix):] not in registered:
return False
return True Prevention
- Derive client tool definitions from the gateway's mcp_servers config (single source of truth) instead of hand-writing names
- After renaming or removing a server, sweep clients for stale litellm_proxy:// references
- Use on_violation: 'alert' while onboarding to observe violations in logs before enforcing blocks
When it happens
Trigger: A request whose tools include {type: mcp, server_url: litellm_proxy://<name>} where <name> is not defined under mcp_servers in the proxy config - typo'd name, server removed but clients still send it, or requests crafted against servers this gateway never hosted.
Common situations: Renaming/removing an MCP server in config while client SDKs keep the old name; per-team gateways where a request assumes another gateway's servers; typo between config and client tool definitions; multi-environment drift (server exists in staging, not prod).
Related errors
- Content blocked: {context_label} argument matched a masking
- Content blocked: {context_label} arguments exceed the maximu
- invalid_request
- ip_filtering
- missing_parameter
AI-assisted analysis of BerriAI/litellm@77b7c6c40c (2026-08-18).
Data as JSON: /api/errors/586d52324728fc6d.
Report an issue: GitHub.