nanocoai/nanoclaw · error
${parsed.error}
Error message
${parsed.error} What it means
The self-mod MCP tool `add_mcp_server` rejects the server configuration before submitting it for approval. `parseMcpServerInput` failed to coerce the args into a valid MCP server config (bad/missing transport fields, bad URL, or malformed JSON), so the error string is surfaced verbatim. This is client-side validation inside the agent container, not a host or approval failure.
Source
Thrown at container/agent-runner/src/mcp-tools/self-mod.ts:196
command: { type: 'string', description: 'Command to run the MCP server' },
url: {
type: 'string',
description: 'Streamable HTTP MCP endpoint (HTTPS; plain HTTP only for localhost / host.docker.internal)',
},
args: { type: 'array', items: { type: 'string' }, description: 'Command arguments' },
env: { type: 'object', description: 'Environment variables for the server' },
},
required: ['name'],
},
},
async handler(args) {
const name = typeof args.name === 'string' ? args.name : '';
if (!name) return err('name is required');
if (!MCP_SERVER_NAME_RE.test(name)) {
return err('server name must be 1-64 characters of letters, digits, "_" or "-"');
}
const parsed = parseMcpServerInput(args);
if ('error' in parsed) return err(parsed.error);
const requestId = generateId();
await writeMessageOut({
id: requestId,
kind: 'system',
content: JSON.stringify({
action: 'add_mcp_server',
name,
...parsed.config,
}),
});
log(`add_mcp_server: ${requestId} → "${name}" (${'url' in parsed.config ? 'HTTP' : parsed.config.command})`);
return ok(`MCP server request submitted. You will be notified when admin approves or rejects.`);
},
};
registerTools([installPackages, addMcpServer]);View on GitHub (pinned to 294ef2aee8)
Solutions
- Read the returned message — it names the exact missing/invalid field; fix the args object accordingly
- Check parseMcpServerInput's accepted shapes (stdio: {command,args,env}; http: {url,headers}) and match one exactly
- Validate the config shape in your own code before invoking the tool
- If the shape you used worked before, check for an agent-runner update that tightened the parser
Example fix
// before
await add_mcp_server({ name: 'github', server: { cmd: 'npx -y @modelcontextprotocol/server-github' } });
// after
await add_mcp_server({ name: 'github', server: { command: 'npx', args: ['-y', '@modelcontextprotocol/server-github'], env: { GITHUB_TOKEN: '...' } } }); Defensive patterns
Strategy: validation
Validate before calling
function isValidStdioServer(s) {
return !!s && typeof s.command === 'string' && s.command.length > 0 &&
Array.isArray(s.args ?? []) && typeof (s.env ?? {}) === 'object';
} Type guard
function isMcpServerInput(v: unknown): v is { command: string; args?: string[]; env?: Record<string,string> } {
if (typeof v !== 'object' || v === null) return false;
const o = v as Record<string, unknown>;
return typeof o.command === 'string' && o.command.length > 0;
} Prevention
- Build MCP server configs from a typed object, never by string concatenation
- Mirror the exact shape parseMcpServerInput accepts (stdio vs http) before calling the tool
- Log the raw args next to the error so the malformed field is obvious
When it happens
Trigger: Calling the add_mcp_server MCP tool with args.name valid but args describing the server (command/url, env, args) malformed — e.g. missing `command` for stdio servers, a non-URL `url` for HTTP servers, or wrong types for env/args.
Common situations: Agent constructs the server config from chat text and drops a required field; passing an SSE-style {url} to a stdio shape; env given as an array instead of an object; older callers using a pre-schema field name after an agent-runner update.
Related errors
- --name is required
- server name must be 1-64 characters of letters, digits, "_"
- type must be "stdio", "http", or "streamable-http"
- Dropping invalid stored MCP server
- ${settingsFile} hooks.SessionStart must be an array
AI-assisted analysis of nanocoai/nanoclaw@294ef2aee8 (2026-08-28).
Data as JSON: /api/errors/20da2fcd7b853896.
Report an issue: GitHub.