nanocoai/nanoclaw · error · Error
server name must be 1-64 characters of letters, digits, "_"
Error message
server name must be 1-64 characters of letters, digits, "_" or "-"
What it means
validateMcpServerName enforces MCP server names of 1-64 chars from [A-Za-z0-9_-] and explicitly rejects "__proto__" (which would set the record's prototype instead of an own key). Called on every intake path: sanitizeStoredMcpServers, add-mcp-server, and config reads.
Source
Thrown at src/container-config.ts:113
* container/agent-runner/src/mcp-tools/self-mod.ts; keep the two in sync.
*/
const MCP_SERVER_NAME_RE = /^[A-Za-z0-9_-]{1,64}$/;
const ENV_KEY_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
/** The owning plugin's name when a stored MCP server entry was stamped from a plugin. */
export function mcpServerPluginOwner(entry: unknown): string | undefined {
if (typeof entry !== 'object' || entry === null) return undefined;
const plugin = (entry as Record<string, unknown>).plugin;
return typeof plugin === 'string' && plugin !== '' ? plugin : undefined;
}
/** Throws unless `name` is a safe MCP server name (1-64 chars of [A-Za-z0-9_-]). */
export function validateMcpServerName(name: string): void {
// "__proto__" passes the regex but assigning servers["__proto__"] sets the
// record's prototype instead of an own key — the server would be silently
// dropped (or worse) on every intake path, so reject it by name.
if (!MCP_SERVER_NAME_RE.test(name) || name === '__proto__') {
throw new Error('server name must be 1-64 characters of letters, digits, "_" or "-"');
}
}
// The Agent Plugins fixed cwd shapes: ./p, ${PLUGIN_ROOT}[/p], ${PLUGIN_DATA}[/p].
const CWD_FORM_RE = /^(?:\.\/|\$\{PLUGIN_ROOT\}(?:\/|$)|\$\{PLUGIN_DATA\}(?:\/|$))/;
/**
* Parse one CLI or approval payload into the persisted MCP config shape.
* Duplicated in container/agent-runner/src/mcp-tools/self-mod.ts
* (parseMcpServerInput) — no shared modules across the host/container
* boundary; keep the two in sync.
*/
export function parseMcpServerConfig(input: Record<string, unknown>): McpServerConfig {
const command = typeof input.command === 'string' && input.command.trim() ? input.command : undefined;
const url = typeof input.url === 'string' && input.url.trim() ? input.url.trim() : undefined;
// A declared transport is honored; absence keeps the legacy CLI inference
// (url → http, command → stdio). "streamable-http" is the Agent PluginsView on GitHub (pinned to 294ef2aee8)
Solutions
- Rename the server to letters/digits/_/- only, max 64 chars (e.g. my-server)
- Never use __proto__ as a name
- Fix the stored container_configs row if a bad name got into the DB via ncl groups config update
Example fix
// before
{"mcpServers": {"my server": {"command": "npx", "args": ["-y", "x"]}}}
// after
{"mcpServers": {"my-server": {"command": "npx", "args": ["-y", "x"]}}} Defensive patterns
Strategy: validation
Validate before calling
if (!/^[A-Za-z0-9_-]{1,64}$/.test(name) || name === '__proto__') throw new Error('bad MCP server name'); Type guard
function isValidMcpServerName(n: string): boolean {
return /^[A-Za-z0-9_-]{1,64}$/.test(n) && n !== '__proto__';
} Prevention
- Slugify server names before inserting into config
- Lint imported MCP configs for name characters
When it happens
Trigger: `ncl groups config add-mcp-server --name "my server!"` or a container config containing a server named with spaces/unicode/dots, or the literal name __proto__.
Common situations: Using a human-readable server name with spaces, or importing an MCP config from another tool whose names use other characters.
Related errors
- type must be "stdio", "http", or "streamable-http"
- Dropping invalid stored MCP server
- Nothing to update — provide at least one of: --provider, --m
- --name is required
- unsupported transport "sse"
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/c53ecbb5b2862b5f.
Report an issue: GitHub.