Skip to content

fix: forward CHOIR_AGENT_TOKEN to codex mcp-stdio via env_vars#688

Merged
brickfrog merged 2 commits into
mainfrom
main.codex-mcp-env-forward-1783622562303-2649617-0
Jul 9, 2026
Merged

fix: forward CHOIR_AGENT_TOKEN to codex mcp-stdio via env_vars#688
brickfrog merged 2 commits into
mainfrom
main.codex-mcp-env-forward-1783622562303-2649617-0

Conversation

@brickfrog

@brickfrog brickfrog commented Jul 9, 2026

Copy link
Copy Markdown
Owner

Summary

Codex leaves' choir mcp-stdio subprocesses launched with zero CHOIR_* env vars: codex's MCP stdio launcher builds each server's environment from scratch (env_clear() + a DEFAULT_ENV_VARS whitelist in rmcp-client's create_env_for_mcp_server; shell_environment_policy only governs shell/exec tool calls, not MCP subprocesses), and choir's codex MCP entry (codex_mcp_override_args) configured no per-server env forwarding. Registration then had no CHOIR_AGENT_TOKEN and the server rejected every codex leaf (choir-ghl9, P0). This adds a names-only mcp_servers.choir.env_vars=["CHOIR_AGENT_TOKEN"] override so codex forwards the token from its own environment — on this MCP override surface the token value never rides argv (the pre-existing token exports in launch_env_prefix/TL init command strings are a separate, out-of-scope surface).

Codex 0.144.0 config-schema findings (task step 1)

  • codex mcp add --help exposes --env <KEY=VALUE> → the mcp_servers.<name>.env value map (rejected here: it would embed the secret in argv).
  • Official docs (learn.chatgpt.com/docs/extend/mcp, the developers.openai.com/codex/mcp redirect target) document both: "env" (optional): Environment variables to set for the server. and "env_vars" (optional): Environment variables to allow and forward.env_vars entries are names whose values are read from codex's local environment.
  • Verified against the installed binary (codex-cli 0.144.0): codex mcp -c 'mcp_servers.x.env_vars=["CHOIR_AGENT_TOKEN"]' list accepts the field and shows CHOIR_AGENT_TOKEN=***** (value resolved from codex's env, masked). Also ran the exact full override shape choir now emits (command/args/env_vars/cwd) — parses clean. Unknown fields are silently ignored, so the masked-value display is the positive proof the field is live. TL audit additionally confirmed the mechanism against codex-rs source (rmcp-client/src/utils.rs + stdio_server_launcher.rs).

Why only CHOIR_AGENT_TOKEN (task step 3)

Audited the mcp-stdio registration path: agent identity, role, parent/branch/workspace, terminal target, and listen_uds all come from the per-leaf .choir/config.local.toml (written at spawn; mcp_servers.choir.cwd points at the worktree) plus the --role/--name args already in the server argv. The CHOIR_* env identity vars are only a fallback for when that file lacks identity (local_cfg_from_env_lookup), which never applies to spawned codex leaves. The token (format_registration_request, src/transport/transport.mbt:84) is the single env-only input, so it is the entire forward list — no blanket CHOIR_* glob.

What changed

  • src/workspace/launch.mbt: codex_mcp_override_args emits -c mcp_servers.choir.env_vars=["CHOIR_AGENT_TOKEN"].
  • src/workspace/workspace_test.mbt: new test asserts the env_vars entry is present for all roles and that no argv element carries a CHOIR_AGENT_TOKEN= assignment or an mcp_servers.choir.env./env= value map.
  • .choir/config.toml: rewrote the [model.codex] comment — the outage was model-independent (not gpt-5.6-luna) and the scrub comes from codex's MCP launcher whitelist, not shell_environment_policy; model/effort values unchanged.

Verification

  • moon test --target native: 2267 passed, 0 failed (RED first: the new test failed before the fix).
  • moon run src/bin/choir_lint --target native: pass.
  • End-to-end verification (spawning a real codex leaf and checking its mcp-stdio /proc environ / registration success) is for the TL after merge — leaves cannot fork_wave.

Verification

Generated by Choir from commands executed in the leaf workspace.

  • moon test --target native
    • exit: 0
    • head: 4a52d6e
    • output tail:
----- BEG4
IN MOON TEST RESULT -----
{"type":"start","file":"exec_test.mbt","index":9}
----- END MOON TEST RESULT -----
Total tests: 2267, passed: 2267, failed: 0.
  • moon run src/bin/choir_lint --target native

@brickfrog

Copy link
Copy Markdown
Owner Author

Choir: GitHub Actions rollup reports all checks successful on the latest head — re-check review/merge policy on GitHub (not an approval or merge signal by itself).

@brickfrog

Copy link
Copy Markdown
Owner Author

Choir: GitHub Actions rollup reports all checks successful on the latest head — re-check review/merge policy on GitHub (not an approval or merge signal by itself).

@brickfrog brickfrog merged commit d92bdf6 into main Jul 9, 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