nexu-io/open-design · error · Error

codex mcp add failed: ${failureDetail(result)}

Error message

codex mcp add failed: ${failureDetail(result)}

What it means

Thrown by installCodexMcp after shelling out to the bundled `codex mcp add` subcommand and getting a non-zero exit code. The error message appends failureDetail(result), which prefers trimmed stderr, then stdout, then `exit <code>`. The daemon delegates config.toml writes to the Codex CLI so it inherits Codex's own merge/dedupe rules, so the failure reason is whatever Codex itself reported.

Source

Thrown at apps/daemon/src/codex-cli.ts:108

export interface CodexInstallSpec {
  // MCP server name as it will appear in ~/.codex/config.toml. We
  // hard-code "open-design" at the route layer but keep the parameter
  // explicit so the helper can later be reused for other server names.
  name: string;
  command: string;
  args: string[];
  env: Record<string, string>;
}

export async function installCodexMcp(spec: CodexInstallSpec): Promise<void> {
  const argv: string[] = ['mcp', 'add', spec.name];
  for (const [key, value] of Object.entries(spec.env)) {
    argv.push('--env', `${key}=${value}`);
  }
  argv.push('--', spec.command, ...spec.args);
  const result = await activeRunner().run(argv);
  if (result.exitCode !== 0) {
    throw new Error(`codex mcp add failed: ${failureDetail(result)}`);
  }
}

export async function uninstallCodexMcp(name: string): Promise<void> {
  const result = await activeRunner().run(['mcp', 'remove', name]);
  if (result.exitCode !== 0) {
    throw new Error(`codex mcp remove failed: ${failureDetail(result)}`);
  }
}

function failureDetail(result: CodexRunnerResult): string {
  return result.stderr.trim() || result.stdout.trim() || `exit ${result.exitCode}`;
}

View on GitHub (pinned to 5be4028344)

Solutions

  1. Read the appended failureDetail in the thrown message — it carries Codex's own stderr.
  2. Run `codex mcp get open-design`; if it already exists, remove it first (`codex mcp remove open-design`) or use the uninstall path.
  3. Confirm the Codex CLI is recent enough to support `mcp add --env K=V -- <cmd> <args...>`.
  4. Verify the spec.command resolves on PATH and spec.args are valid for that command.

Example fix

// before: install fails because name is already registered
codex mcp add open-design --env KEY=val -- /usr/local/bin/od mcp
// after: remove the stale entry, then install
codex mcp remove open-design
codex mcp add open-design --env KEY=val -- /usr/local/bin/od mcp
Defensive patterns

Strategy: try-catch

Validate before calling

// Probe before installing to avoid the duplicate-name failure.
const status = await probeCodexInstall(spec.name);
if (!status.available) {
  throw new Error('codex CLI not found on PATH; cannot install');
}
if (status.installed) {
  await uninstallCodexMcp(spec.name); // clear stale entry first
}
await installCodexMcp(spec);

Try / catch

try {
  await installCodexMcp(spec);
} catch (err) {
  const detail = err instanceof Error ? err.message : String(err);
  if (/already exists|mcp add failed/i.test(detail)) {
    await uninstallCodexMcp(spec.name).catch(() => {});
    await installCodexMcp(spec); // one retry after cleanup
    return;
  }
  throw err;
}

Prevention

When it happens

Trigger: Clicking 'Install to Codex' in Settings when an MCP server with that name is already in ~/.codex/config.toml, when the resolved command/args are invalid, or when the installed Codex CLI version does not support `mcp add` with the `--env`/`--` shape. Also when the codex binary is present but broken.

Common situations: Duplicate server name from a prior install, a Codex CLI downgrade that dropped the subcommand, an invalid command path in the spec, or a TOML merge/validation error inside Codex.

Related errors


AI-assisted analysis of nexu-io/open-design@5be4028344 (2026-08-12). Data as JSON: /api/errors/f32785395ad75987. Report an issue: GitHub.