WriteMCPConfig translates a single canonical MCP config into each CLI’s expected file path + format. This page documents the per-CLI schema so operators can debug MCP issues directly.
Quick reference
Schema differences
Stdio servers (local subprocess)
However the launch line reaches Crewship — the CLI’sintegration add --command, the
web integration form’s args field, or the MCP config editor — it is split into
command + args by a quote-aware tokenizer, not a naive whitespace split:
- Single quotes group and are fully literal inside (
'echo hi there'→ one token). - Double quotes group; inside them a backslash escapes only
"and\, so"C:\Program Files\nodejs\npx.exe"survives as one token with its backslashes. - An unquoted backslash escapes only a following space, tab, quote, or backslash;
otherwise it stays literal (
C:\npx.exeneeds no quoting). - An executable path containing spaces must be quoted, or validation rejects the command as a crammed launch line.
""is kept as an intentional empty argument; an unterminated quote consumes the rest of the input as one token (it is not an error).- There is no shell: no variable expansion, globbing, tilde/brace expansion, or
operators (
|,&&, redirects). Env vars belong in theenvfield.
command + args:
command is an array (binary + args together), env field is environment:
HTTP servers (remote)
Claude / Cursor / Droid —url + headers:
httpUrl (current) or legacy url (SSE):
type: remote:
Common pitfalls
1. Cursor MCP is currently inert in --print mode
cursor-agent --print does not invoke MCP servers at runtime even with --approve-mcps set — the binary lists registered servers via cursor-agent mcp list but never actually calls them in headless mode (forum #143045, #148397, confirmed against latest builds). The Crewship adapter reflects this honestly: adapter_cursor.go returns SupportsMCP() == false, which means the orchestrator skips WriteMCPConfig entirely — no .cursor/mcp.json is written. The --approve-mcps flag itself stays wired conditionally: BuildCommand still appends it whenever any MCP source is configured, so the moment upstream fixes headless MCP and SupportsMCP is flipped to true, MCP-equipped agents light up without a second commit. If a future Cursor release wires MCP into --print, flip SupportsMCP and the rest of the pipeline (config write, table row above) lights up automatically.
2. Codex doesn’t interpolate ${VAR}
If you write env = { LINEAR_TOKEN = "${LINEAR_TOKEN}" } to Codex’s config, Codex passes the LITERAL string "${LINEAR_TOKEN}" as the env var to spawned MCP servers — they get the raw ${LINEAR_TOKEN} string instead of the secret. Crewship’s writer omits ${VAR}-style entries from the env block; Codex inherits container env instead.
3. OpenCode {env:VAR} syntax
Cursor’s ${env:VAR} and Anthropic’s ${VAR} are NOT recognised by OpenCode. Crewship’s translateEnvRefsToOpenCode converts standard forms — including substrings like "Bearer ${LINEAR_TOKEN}" (the dominant Authorization header pattern).
4. Codex config in $HOME, not project root
Codex’s project-scoped .codex/config.toml is only loaded for “trusted” projects, with trust established interactively. Headless invocations skip it. Crewship writes to /crew/agents/<slug>/.codex/config.toml (HOME) so Codex picks it up unconditionally.
Verifying MCP config
crews/agents.mcp_config_json, agent keys winning over crew keys) and
the integration-table bindings (workspace/crew servers plus per-agent bindings, each
line showing origin, transport, endpoint or command, and the bound credential). Useful
for spot-checking env-var translation, file paths, and per-CLI schema differences
before exec.
Adding an MCP server
Crew settings → MCP Servers → Add. Crewship merges crew + agent configs and writes per-adapter viamcp_writers.go. Standard input format is the Anthropic/Claude shape — every other adapter’s format is generated from it via the shared normaliseMCPInputs helper.