{"record":{"id":"f32785395ad75987","repo":"nexu-io/open-design","slug":"codex-mcp-add-failed-failuredetail-result","errorCode":null,"errorMessage":"codex mcp add failed: ${failureDetail(result)}","messagePattern":"codex mcp add failed: (.+?)","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"apps/daemon/src/codex-cli.ts","lineNumber":108,"sourceCode":"export interface CodexInstallSpec {\n  // MCP server name as it will appear in ~/.codex/config.toml. We\n  // hard-code \"open-design\" at the route layer but keep the parameter\n  // explicit so the helper can later be reused for other server names.\n  name: string;\n  command: string;\n  args: string[];\n  env: Record<string, string>;\n}\n\nexport async function installCodexMcp(spec: CodexInstallSpec): Promise<void> {\n  const argv: string[] = ['mcp', 'add', spec.name];\n  for (const [key, value] of Object.entries(spec.env)) {\n    argv.push('--env', `${key}=${value}`);\n  }\n  argv.push('--', spec.command, ...spec.args);\n  const result = await activeRunner().run(argv);\n  if (result.exitCode !== 0) {\n    throw new Error(`codex mcp add failed: ${failureDetail(result)}`);\n  }\n}\n\nexport async function uninstallCodexMcp(name: string): Promise<void> {\n  const result = await activeRunner().run(['mcp', 'remove', name]);\n  if (result.exitCode !== 0) {\n    throw new Error(`codex mcp remove failed: ${failureDetail(result)}`);\n  }\n}\n\nfunction failureDetail(result: CodexRunnerResult): string {\n  return result.stderr.trim() || result.stdout.trim() || `exit ${result.exitCode}`;\n}\n","sourceCodeStart":90,"sourceCodeEnd":122,"githubUrl":"https://github.com/nexu-io/open-design/blob/5be4028344c2eb4c667c5a97bda8f750c5597ef7/apps/daemon/src/codex-cli.ts#L90-L122","documentation":"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.","triggerScenarios":"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.","commonSituations":"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.","solutions":["Read the appended failureDetail in the thrown message — it carries Codex's own stderr.","Run `codex mcp get open-design`; if it already exists, remove it first (`codex mcp remove open-design`) or use the uninstall path.","Confirm the Codex CLI is recent enough to support `mcp add --env K=V -- <cmd> <args...>`.","Verify the spec.command resolves on PATH and spec.args are valid for that command."],"exampleFix":"// before: install fails because name is already registered\ncodex mcp add open-design --env KEY=val -- /usr/local/bin/od mcp\n// after: remove the stale entry, then install\ncodex mcp remove open-design\ncodex mcp add open-design --env KEY=val -- /usr/local/bin/od mcp","handlingStrategy":"try-catch","validationCode":"// Probe before installing to avoid the duplicate-name failure.\nconst status = await probeCodexInstall(spec.name);\nif (!status.available) {\n  throw new Error('codex CLI not found on PATH; cannot install');\n}\nif (status.installed) {\n  await uninstallCodexMcp(spec.name); // clear stale entry first\n}\nawait installCodexMcp(spec);","typeGuard":null,"tryCatchPattern":"try {\n  await installCodexMcp(spec);\n} catch (err) {\n  const detail = err instanceof Error ? err.message : String(err);\n  if (/already exists|mcp add failed/i.test(detail)) {\n    await uninstallCodexMcp(spec.name).catch(() => {});\n    await installCodexMcp(spec); // one retry after cleanup\n    return;\n  }\n  throw err;\n}","preventionTips":["Call probeCodexInstall(name) first and skip or uninstall when already registered.","Pin a Codex CLI version that supports the `mcp add --env K=V -- <cmd>` shape.","Surface failureDetail verbatim to the user — it carries Codex's own diagnostic."],"tags":["codex","mcp","cli","integration","spawn"],"backgroundTag":null,"analyzedSha":"5be4028344c2eb4c667c5a97bda8f750c5597ef7","analyzedAt":"2026-08-12T12:03:58.812Z","schemaVersion":2},"datasetVersion":"2026-08-12T18:17:37.767Z"}