JuliusBrussee/caveman · error · Error

caveman-mcp not found; run `caveman setup --install`

Error message

caveman-mcp not found; run `caveman setup --install`

What it means

Thrown by nativeMcpBinaryRequired when the bundled/installed caveman-mcp binary cannot be found or probed as compatible. The CLI's native MCP mode depends on this companion binary being installed; without it, MCP management cannot proceed. A related error covers a found binary that lacks the required mcp_recovery capability version.

Solutions

  1. Run `caveman setup --install` to install/update the caveman-mcp binary
  2. If a partial install exists, reinstall: remove the old binary and re-run setup
  3. Verify the install location is on PATH or in the expected plugin directory
  4. Check the probe: if the error mentions missing mcp_recovery capability, the binary is outdated — reinstall to update it

Example fix

// before
$ caveman mcp list
caveman-mcp not found; run `caveman setup --install`
// after
$ caveman setup --install
$ caveman mcp list
Defensive patterns

Strategy: try-catch

Validate before calling

import { execFileSync } from "node:child_process";
function cavemanMcpInstalled(): boolean {
  try { execFileSync("caveman-mcp", ["--version"], { stdio: "ignore" }); return true; } catch { return false;
  }
}

Type guard

null

Try / catch

try {
  runNativeMcpCommand();
} catch (e) {
  if (String(e.message).includes("caveman-mcp not found")) {
    execFileSync("caveman", ["setup", "--install"], { stdio: "inherit" });
    runNativeMcpCommand();
  }
}

Prevention

When it happens

Trigger: probeMcpBinary() returns a falsy/compatible=false result because the caveman-mcp executable is not on the expected install path or PATH during native MCP operations.

Common situations: Fresh clone or CI environment where `caveman setup --install` was never run; the binary was deleted by a cleanup script; npm global install missing; running from a different machine/container without setup.

Understand the failure class

Background: "not installed", "pip install", "required for": how missing-dependency errors surface across open-source libraries — this error's family across 34 libraries.

Related errors


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

Appendix: source

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

function durableUnlink(path: string): void {
  try {
    unlinkSync(path);
    fsyncParentDirectory(path);
  } catch (error) {
    if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
  }
}

function parseJsonFileObject(path: string, bytes: Buffer | null): Record<string, unknown> {
  if (!bytes || bytes.length === 0) return {};
  const parsed = JSON.parse(bytes.toString("utf8"));
  if (!parsed || typeof parsed !== "object" || Array.isArray(parsed)) throw new Error(`${path} is not a JSON object`);
  return parsed as Record<string, unknown>;
}

function nativeMcpBinaryRequired(): string {
  const compatible = probeMcpBinary();
  if (!compatible) throw new Error("caveman-mcp not found; run `caveman setup --install`");
  if (!compatible.probe.current) throw new Error(`caveman-mcp ${compatible.probe.version} lacks current mcp_recovery capability; run \`caveman setup --install\``);
  return compatible.binary;
}

function nativeProxyBinaryRequired(gw: string): void {
  if (wrapMode(gw) !== "local") return;
  const binary = resolveGoBin("caveman-proxy", "CAVEMAN_PROXY_BIN");
  if (!binary) throw new Error("caveman-proxy not found; run `caveman setup --install`");
  const probe = probeVersionedBinary(binary, "native_runtime_v1");
  if (!probe.current) throw new Error(`caveman-proxy ${probe.version} lacks current native_runtime_v1 capability; run \`caveman setup --install\``);
}

function nativeHostProbe(agent: AgentProfile): { binary: string | null; launchable: boolean; version: string | null; error: string | null } {
  const binary = which(binOf(agent));
  if (!binary) return { binary: null, launchable: false, version: null, error: "binary_not_found" };
  try {
    const invocation = portableInvocation(binary, ["--version"]);
    const out = spawnSync(invocation.command, invocation.args, { encoding: "utf8", timeout: 3000 });

View on GitHub (pinned to 3ee70a1026)