JuliusBrussee/caveman · error · Error

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

Error message

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

What it means

The mirror of error 328 for uninstall: uninstallAgentNativeCloudMcp() tries removeMcpJson (~/.claude.json mcpServers.caveman-cloud) or uninstallMcpForAgent (codex) and throws when the removal helper reports it could not perform the deletion. The marker file cleanup afterwards only tolerates ENOENT, so a failed removal is fatal rather than silently leaving stale state.

Source

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

}

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(join(homedir(), ".claude.json"), ["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(join(homedir(), ".claude.json"), ["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(homedir(), ".claude", "skills") : join(homedir(), ".codex", "skills");
  return names.map((name) => ({ name, file: join(root, name, "SKILL.md"), body: SKILLS[name]! }));
}

function restoreAgentNativeBundleSkills(skills: AgentNativeBundleSkill[]): void {
  for (const skill of [...skills].reverse()) {
    const before = skill.before_base64 === null ? null : Buffer.from(skill.before_base64, "base64");
    if (before) atomicWriteFile(skill.file, before);
    else {
      try { unlinkSync(skill.file); } catch (error) {
        if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;

View on GitHub (pinned to 27d5a3981a)

Solutions

  1. Verify the agent config file is valid and writable
  2. Close the agent app so it is not rewriting the config mid-uninstall
  3. Manually delete the caveman-cloud entry from mcpServers (Claude) or the [mcp_servers.caveman-cloud] table (Codex) and re-run uninstall to finish marker cleanup
Defensive patterns

Strategy: validation

Validate before calling

function agentConfigRemovable(path: string, isClaude: boolean): boolean {
  try {
    const raw = readFileSync(path, "utf8");
    if (isClaude) JSON.parse(raw);
    accessSync(path, constants.W_OK);
    return true;
  } catch { return false; }
}

Type guard

function isMcpRemoveError(e: unknown): boolean {
  return e instanceof Error && e.message.startsWith("could not remove caveman-cloud MCP for ");
}

Try / catch

try {
  runCavemanUninstall();
} catch (e) {
  if (isMcpRemoveError(e)) {
    // remove the caveman-cloud entry by hand, then re-run uninstall to clean the marker
  } else throw e;
}

Prevention

When it happens

Trigger: Uninstalling the agent-native bundle when ~/.claude.json or ~/.codex/config.toml is unreadable, unwritable, or malformed, so the mcpServers entry cannot be deleted.

Common situations: Read-only home dir; config file corrupted by another tool; running uninstall concurrently with the agent app rewriting its own config.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@27d5a3981a (2026-08-15). Data as JSON: /api/errors/775885188df9fcef. Report an issue: GitHub.