{"record":{"id":"924d223b2dda794b","repo":"JuliusBrussee/caveman","slug":"a-display-name-mcp-changes-require-the-ownershi","errorCode":null,"errorMessage":"${a.display_name} MCP changes require the ownership transaction","messagePattern":"(.+?) MCP changes require the ownership transaction","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/cli/src/index.ts","lineNumber":11049,"sourceCode":"function uninstallMcpForAgent(a: AgentProfile, serverName = \"caveman\"): boolean {\n  switch (a.id) {\n    case \"claude\": {\n      const claude = which(\"claude\");\n      if (!claude) return true; // agent itself is gone; dropping the marker is all that's left\n      try {\n        execPortableIgnore(claude, [\"mcp\", \"remove\", serverName]);\n      } catch {\n        // not registered — fine, still a successful uninstall.\n      }\n      return true;\n    }\n    case \"codex\":\n      return removeMcpCodexToml(serverName);\n    case \"opencode\":\n      return removeMcpJson(join(homedir(), \".config\", \"opencode\", \"opencode.json\"), [\"mcp\", serverName]);\n    case \"kilo\":\n    case \"qwen\":\n      throw new Error(`${a.display_name} MCP changes require the ownership transaction`);\n    case \"gemini\":\n      return removeMcpJson(geminiSettingsPath(), [\"mcpServers\", serverName]);\n    case \"hermes\":\n      return removeMcpHermesYaml(serverName);\n    case \"openclaw\":\n      return uninstallMcpOpenClaw(serverName);\n    default:\n      return false;\n  }\n}\n\n// removeMcpCodexToml drops the exact [mcp_servers.<name>] block mcpInstall wrote\n// (header + its command/args lines, up to the next section or EOF).\nfunction removeMcpCodexToml(serverName = \"caveman\"): boolean {\n  const path = join(codexHomeDir(), \"config.toml\");\n  let existing = \"\";\n  try {\n    existing = readFileSync(path, \"utf8\");","sourceCodeStart":11031,"sourceCodeEnd":11067,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/packages/cli/src/index.ts#L11031-L11067","documentation":"For the kilo and qwen agents, MCP add/remove is not allowed through the plain per-agent mutation helpers because these agents use a dedicated ownership transaction (journal + canonical marker path, see errors 483/484) instead of direct config edits. The remove switch-case throws to enforce that invariants are maintained only through the transactional path.","triggerScenarios":"Calling the MCP remove/uninstall path with agent 'kilo' or 'qwen' instead of the transactional ownership flow — i.e. invoking a direct mutation API or CLI subcommand that bypasses the ownership transaction.","commonSituations":"Scripts written for other agents (codex, gemini, opencode) applied to kilo/qwen; older automation predating the ownership-transaction requirement; attempting manual config cleanup with the generic remove command.","solutions":["Use the ownership-transaction command/flow for kilo and qwen MCP changes (the install/uninstall with journaling)","For other agents, keep using the direct remove path — the restriction is agent-specific","Update automation scripts to dispatch kilo/qwen to the transactional API"],"exampleFix":"// before\nremoveMcpAgent({ id: \"kilo\", display_name: \"Kilo\" }, serverName);\n// after\nawait runMcpOwnershipTransaction(\"kilo\", serverName, /* remove */ true);","handlingStrategy":"validation","validationCode":"const TRANSACTIONAL_AGENTS = new Set([\"kilo\", \"qwen\"]);\nif (TRANSACTIONAL_AGENTS.has(agent.id)) {\n  await runMcpOwnershipTransaction(agent.id, serverName);\n} else {\n  removeMcpDirect(agent, serverName);\n}","typeGuard":"function requiresOwnershipTransaction(agentId: string): boolean {\n  return agentId === \"kilo\" || agentId === \"qwen\";\n}","tryCatchPattern":"try {\n  removeMcpForAgent(agent, serverName);\n} catch (e) {\n  if ((e as Error).message.includes(\"ownership transaction\")) {\n    await runMcpOwnershipTransaction(agent.id, serverName);\n  } else throw e;\n}","preventionTips":["Dispatch MCP mutations per-agent; route kilo/qwen through the transactional API","Update legacy scripts that predate the ownership transaction","Prefer the CLI's top-level install/uninstall commands over direct mutation helpers"],"tags":["mcp","unsupported-operation","transaction"],"backgroundTag":"unsupported-operation","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}