JuliusBrussee/caveman · error

could not install caveman-cloud MCP for

Error message

could not install caveman-cloud MCP for ${agent}

What it means

installAgentNativeCloudMcp tries to register the caveman-cloud MCP server for the target agent ('claude' via the global MCP JSON config, 'codex' via installMcpForAgent). If the agent-specific installer reports it could not write the config, this error is thrown before the success marker is written.

Solutions

  1. Verify the agent (claude/codex) is installed and discoverable by the CLI.
  2. Check the agent's global config file for invalid JSON and fix or regenerate it.
  3. Fix permissions on the agent config file/directory.
  4. Run the agent once to create its config, then retry the MCP install.

Example fix

// before: claude_desktop_config.json is invalid JSON
// after
mv claude_desktop_config.json claude_desktop_config.json.bak
claude --version   # regenerates config
caveman install   # retry MCP registration
Defensive patterns

Strategy: validation

Validate before calling

const cfgPath = claudeGlobalConfigPath();
if (!existsSync(cfgPath)) throw new Error(`run claude once to create ${cfgPath}`);
JSON.parse(readFileSync(cfgPath, 'utf8')); // throws on malformed config

Try / catch

try { setupCloudMcp('claude') } catch (e) { if (String(e.message).startsWith('could not install caveman-cloud MCP')) { fixAgentConfig(); setupCloudMcp('claude'); } }

Prevention

When it happens

Trigger: installMcpJson(claudeGlobalConfigPath(), ...) or installMcpForAgent(findAgent(agent)!, ...) returns false — typically because the agent config file could not be written/parsed/updated, or findAgent(agent) could not resolve the agent installation.

Common situations: Claude/Codex config file (e.g. claude_desktop_config.json) malformed or read-only; agent CLI not installed so findAgent fails; config directory missing or read-only.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/153f4bea7b056507. Report an issue: GitHub.

Appendix: source

Thrown at packages/cli/src/index.ts:2691

    exact_shape: keys.length === 2 && keys[0] === "args" && keys[1] === "command",
  };
}

function agentNativeCloudMcpMatches(agent: "claude" | "codex", mcp: { command: string; args: string[] }): boolean {
  if (agent === "codex") return codexMcpRegistrationMatches("caveman-cloud", mcp);
  const actual = claudeMcpRegistration("caveman-cloud");
  return actual.present && actual.exact_shape && actual.command === mcp.command && JSON.stringify(actual.args) === JSON.stringify(mcp.args);
}

function installAgentNativeCloudMcp(agent: "claude" | "codex", mcp: { command: string; args: string[] }): void {
  if (agentNativeCloudMcpMatches(agent, mcp)) {
    writeMcpServerMarker(agent, "caveman-cloud", mcp, "caveman_context");
    return;
  }
  const installed = agent === "claude"
    ? installMcpJson(claudeGlobalConfigPath(), ["mcpServers", "caveman-cloud"], { command: mcp.command, args: mcp.args })
    : installMcpForAgent(findAgent(agent)!, mcp, "caveman-cloud");
  if (!installed) throw new Error(`could not install caveman-cloud MCP for ${agent}`);
  writeMcpServerMarker(agent, "caveman-cloud", mcp, "caveman_context");
}

function uninstallAgentNativeCloudMcp(agent: "claude" | "codex"): void {
  const removed = agent === "claude"
    ? removeMcpJson(claudeGlobalConfigPath(), ["mcpServers", "caveman-cloud"])
    : uninstallMcpForAgent(findAgent(agent)!, "caveman-cloud");
  if (!removed) throw new Error(`could not remove caveman-cloud MCP for ${agent}`);
  try { unlinkSync(mcpServerMarkerPath(agent, "caveman-cloud")); } catch (error) {
    if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
  }
}

function agentNativeSkillFiles(agent: "claude" | "codex"): Array<{ name: string; file: string; body: string }> {
  const names = AGENT_SKILL_SUITES["agent-native"] ?? [];
  const root = agent === "claude" ? join(claudeConfigDir(), "skills") : join(codexHomeDir(), "skills");
  return names.map((name) => ({ name, file: join(root, name, "SKILL.md"), body: SKILLS[name]! }));
}

View on GitHub (pinned to 3ee70a1026)