Skip to content

fix(jail): expose the claude MCP config dir inside the fs-jail - #155

Merged
drewstone merged 1 commit into
mainfrom
fix/jail-mcp-config-visibility
Aug 12, 2026
Merged

fix(jail): expose the claude MCP config dir inside the fs-jail#155
drewstone merged 1 commit into
mainfrom
fix/jail-mcp-config-visibility

Conversation

@drewstone

Copy link
Copy Markdown
Owner

Problem

discovery-lab run strong-lead-smoke-b died with:

claude exited 1: Invalid MCP configuration: MCP config file not found: /tmp/cli-bridge-mcp-5F5zD4/mcp-config.json

The bridge materializes the runtime's coordination MCP servers into mcp-config.json under the host /tmp (writeMcpConfigFile, src/backends/profile-support.ts), and passes --mcp-config <path> --strict-mcp-config to claude. The fs-jail mounts a fresh tmpfs over /tmp, so the confined claude cannot see the file and exits 1 before doing any work.

The jail architecture already has the mechanism for exactly this: registerJailReadable re-binds a host config dir read-only AFTER the tmpfs. kimi (src/backends/kimi.ts:145) and opencode (src/backends/opencode.ts:113) call it for their materialized configs, and pi avoids the problem entirely by writing its MCP config inside the workspace (.cli-bridge-pi-mcp- under cwd) — that is why pi leads work daily. claude was the only MCP-consuming backend that never registered its config dir. Codex is covered separately: its MCP stanzas live in the synthetic CODEX_HOME, which #154 seeds writable into the jail.

Fix

One registration in src/backends/claude.ts, the exact kimi/opencode idiom:

if (mcpMaterialized) {
  registerJailReadable(req.jailSpec, dirname(mcpMaterialized.configPath))
}

Proof

  • Reproduced on a local fs-jailed bridge (WORKER_FS_JAIL=1) from unfixed main with the runtime's request shape (profile mcp: { coordination: { command: ... } }): claude exited 1: Error: Invalid MCP configuration: MCP config file not found: /tmp/cli-bridge-mcp-5F0Cjz/mcp-config.json — same failure as smoke-b, and (per fix(jail): seed writable codex/claude homes and acknowledge receipts on failed turns #154) the profile receipt now rides the error so the runtime reports it verbatim instead of a masked transport fault.
  • Same request against this branch: completes with "pong" and the receipt attached.
  • New tests: a jailed claude spawn registers its --mcp-config dir in jailSpec.extraReadablePaths (tests/docker-executor.test.ts); a jailed codex spawn carries its [mcp_servers.*] stanzas in the seed-writable synthetic CODEX_HOME (tests/codex-backend.test.ts).
  • pnpm build clean; pnpm test: 804 passed, 8 skipped, 44 files.

No serving-bridge restart performed — deploy-ready.

🤖 Generated with Claude Code

A jailed claude lead with MCP servers died at spawn. The bridge writes
mcp-config.json to a host /tmp directory, the fs-jail mounts a fresh
tmpfs over /tmp, and the confined claude cannot see the --mcp-config
path. The measured failure on discovery-lab run strong-lead-smoke-b is
'claude exited 1: Invalid MCP configuration: MCP config file not found:
/tmp/cli-bridge-mcp-5F5zD4/mcp-config.json'.

kimi and opencode already register their materialized config dirs
through registerJailReadable, and pi writes its MCP config inside the
workspace. claude was the only backend that skipped the registration.
Register the config dir so the jail re-binds it read-only after the
tmpfs.

Tests prove a jailed claude spawn registers its --mcp-config dir as
jail-readable, and a jailed codex spawn carries its MCP stanzas in the
seeded writable CODEX_HOME.

Verified end to end on a local fs-jailed bridge: the exact failing
request now completes with the profile receipt attached.
@drewstone
drewstone merged commit 5784b4d into main Aug 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant