shareAI-lab/learn-claude-code · error · ValueError
MCP names cannot normalize to an empty string
Error message
MCP names cannot normalize to an empty string
What it means
normalize_mcp_name() replaces every character outside the model's tool-name alphabet with '_' (_DISALLOWED_CHARS substitution). If the input consists entirely of disallowed characters (or is empty), the normalized result is '' — not a usable tool-name component — so it raises ValueError instead of producing a garbage name like 'mcp_____'.
Source
Thrown at s14_mcp_plugin/code.py:207
mcp_clients: dict[str, MCPClient] = {}
mcp_tool_policies: dict[str, str] = {}
_DISALLOWED_CHARS = re.compile(r"[^a-zA-Z0-9_-]")
# Authorization comes from host configuration, never server descriptions.
MCP_HOST_POLICY = {
("docs", "search"): "allow",
("docs", "get_version"): "allow",
("deploy", "status"): "allow",
("deploy", "trigger"): "confirm",
}
def normalize_mcp_name(name: str) -> str:
"""Replace characters outside the model tool-name alphabet."""
normalized = _DISALLOWED_CHARS.sub("_", name)
if not normalized:
raise ValueError("MCP names cannot normalize to an empty string")
return normalized
def _mock_server_docs() -> MCPClient:
server = MCPClient("docs")
server.register(
tool_defs=[
{
"name": "search",
"description": "Search the documentation.",
"inputSchema": {
"type": "object",
"properties": {"query": {"type": "string"}},
"required": ["query"],
},
"annotations": {"readOnlyHint": True},
},
{View on GitHub (pinned to 985456f4ad)
Solutions
- Ensure server and tool names contain at least one allowed character (letter/digit) before registration.
- Skip and log tool defs with empty/all-symbol names instead of registering them.
- Validate config values with a non-empty-after-normalization check at load time.
Example fix
// before
name = normalize_mcp_name(raw_name) // ValueError if raw_name is '***'
// after
if not re.sub(r'[^A-Za-z0-9_-]', '_', raw_name or '').strip('_'):
continue # skip unusable tool name
name = normalize_mcp_name(raw_name) Defensive patterns
Strategy: type-guard
Validate before calling
import re
def normalizes_nonempty(name: str) -> bool:
return bool(re.sub(r'[^A-Za-z0-9_-]', '_', name or '').strip('_')) or bool(re.sub(r'[^A-Za-z0-9_-]', '_', name or '')) Type guard
import re
from typing import TypeGuard
def normalizable_mcp_name(value: object) -> TypeGuard[str]:
if not isinstance(value, str):
return False
return bool(re.sub(r'[^A-Za-z0-9_-]', '_', value)) Prevention
- Require at least one alphanumeric in server and tool names at config load time.
- Skip-and-log unusable tool defs instead of registering them.
- Test normalization of generated names in CI.
When it happens
Trigger: normalize_mcp_name('') (empty server or tool name); normalize_mcp_name('***') or any all-punctuation string; a tool def whose name is only whitespace/CJK/emoji after stripping.
Common situations: Loading MCP server names or tool names from external config where a value is blank or purely symbolic; generated tool names from descriptions; trimming that empties a string.
Related errors
- Every MCP tool needs a non-empty name
- Duplicate MCP tool name on server {self.name!r}
- Missing MCP handlers: {', '.join(missing)}
- MCP tool name is longer than 64 characters: {prefixed}
- Invalid input schema for {origin}
AI-assisted analysis of shareAI-lab/learn-claude-code@985456f4ad (2026-08-14).
Data as JSON: /api/errors/f92772919b44c869.
Report an issue: GitHub.