Yeachan-Heo/oh-my-codex · warning · Error
Unknown ${descriptor.commandName} tool: ${parsed.toolName} $
Error message
Unknown ${descriptor.commandName} tool: ${parsed.toolName}
${buildDescriptorHelp(descriptor)} What it means
executeDescriptorCommand resolves the requested tool name (after alias mapping via descriptor.aliases) against the descriptor's registered tool set. If the resolved name is not in descriptor.tools, it throws with the command name, the requested tool name, and the full generated help text listing valid tools.
Source
Thrown at src/cli/mcp-parity.ts:149
} catch {
return text;
}
}
async function executeDescriptorCommand(
args: string[],
loadDescriptor: DescriptorLoader,
): Promise<McpParityExecutionResult> {
const descriptor = await loadDescriptor();
const parsed = parseMcpCliArgs(args);
if (parsed.help || !parsed.toolName) {
return { ok: true, help: buildDescriptorHelp(descriptor) };
}
const toolName = descriptor.aliases?.[parsed.toolName] ?? parsed.toolName;
const allowedTools = new Set(descriptor.tools.map((tool) => tool.name));
if (!allowedTools.has(toolName)) {
throw new Error(
`Unknown ${descriptor.commandName} tool: ${parsed.toolName}\n${buildDescriptorHelp(descriptor)}`,
);
}
const result = await descriptor.handle(
{
params: {
name: toolName,
arguments: parsed.input,
},
},
descriptor.handleOptions,
);
const payload = extractPayload(result);
return result.isError
? { ok: false, error: payload }
: { ok: true, data: payload };
}View on GitHub (pinned to 3ad79a8a6f)
Solutions
- Read the help text included in the error message — it enumerates every valid tool name
- Fix the typo / use the exact tool name from the help output
- Verify you're on the version whose tool set you expect (check changelog or --version)
- If an alias is expected, confirm it still exists in descriptor.aliases for your version
Example fix
# before
mycli mcp run-tool serach --input '{"q":"x"}'
# after
mycli mcp run-tool search --input '{"q":"x"}' Defensive patterns
Strategy: try-catch
Validate before calling
const validTools = new Set(['search', 'get', 'list']); // from descriptor help
if (!validTools.has(requestedTool)) {
console.error(`Unknown tool. Valid: ${[...validTools].join(', ')}`);
process.exit(2);
} Type guard
function isKnownTool(name: string, descriptor: { tools: { name: string }[]; aliases?: Record<string, string> }): boolean {
const resolved = descriptor.aliases?.[name] ?? name;
return descriptor.tools.some((t) => t.name === resolved);
} Try / catch
try { await executeDescriptorCommand(descriptor, args); }
catch (e) {
if (/Unknown \S+ tool:/.test(String(e))) { console.error(e.message); process.exit(2); } // message embeds full help
throw e;
} Prevention
- Derive tool names programmatically from the descriptor/help, not hardcoded strings
- Watch changelogs for tool renames across versions
When it happens
Trigger: Calling `mcp <command> <toolName>` where toolName is not registered and not an alias — typo'd names, tools from a different/older descriptor, or plugins that failed to load their tools.
Common situations: Typos (serch vs search); upgrading/downgrading versions where tool names changed; docs referencing tools not present in the installed build; alias removed between releases.
Related errors
- Unknown MCP target: ${firstArg} ${MCP_SERVE_USAGE}
- Unexpected arguments: ${args.slice(1).join(" ")} ${MCP_SERVE
- Unknown adapt argument: ${arg}
- Unknown adapt target: ${target}. Supported targets: ${suppor
- Unknown adapt subcommand: ${subcommand}. Supported subcomman
AI-assisted analysis of Yeachan-Heo/oh-my-codex@3ad79a8a6f (2026-08-27).
Data as JSON: /api/errors/2e28d12c6244d91c.
Report an issue: GitHub.