Repository navigation
cli: write Cursor, OpenCode, VS Code and Gemini CLI configs through add-mcp - #15
chenchenSimular wants to merge 2 commits into
Conversation
…dd-mcp add-mcp (Apache-2.0, pinned at 2.6.1) now owns where these clients keep their MCP servers and in what shape, behind our own interface (src/config-writer.js). It runs in a child process with the CLI context's environment, because it resolves paths from HOME and env once at import. Our layer keeps what is specific to box: the "only replace a box entry whose URL is ours" guard, refusing files we cannot parse, box-control migration, backups, and reading the result back (restoring the file if it is not what we asked for). Codex and Hermes keep their own writers: add-mcp drops Codex comments and per-server settings, and writes Hermes entries without auth: oauth, so `hermes mcp login` refuses them. Also: - Gemini CLI is a new client, verified by the install matrix. - OpenCode stops with manual steps when XDG_CONFIG_HOME points away from ~/.config, where add-mcp would write a file OpenCode never reads. - A config that cannot be written (EACCES/EPERM) gets a clear message; for Codex it prints the Codex app's Settings steps. - The Codex sign-in hint no longer assumes `codex` is on PATH. Refs #14 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
From review of #15: - add-mcp writes in place, so a crashed or timed-out worker, a full disk or a failed box-control removal could leave a damaged config with no backup. The previous text is now saved before add-mcp runs and put back on any failure; a backup is kept only when the file changed. - OpenCode: a file with an empty `mcp.servers` map (the newer layout) failed connect, because we expected box under `mcp`. Mirror add-mcp's choice of key. - The worker no longer inherits BOX_TOKEN / MCP_BOX_API_KEY. Refs #14 Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
|
Decision: we won't adopt add-mcp. We keep our own writers and will revisit if upstream fixes the issues below. Spike result (add-mcp 2.6.1, our fixtures plus the real-client matrix):
Gaps we would have had to wrap for every client: it overwrites a foreign Upstream correctness issues sit unanswered: #121 (Zed path), #122 (TOML), #130 (Claude Code What carries over without add-mcp, in a new PR: Gemini CLI as a client (on our own writer), clear EACCES/EPERM errors with the Codex app steps, and a Codex sign-in hint that doesn't assume |
Closes #14
Why
npx @simular-ai/box connectcarried its own writer for every client's MCP config. add-mcp (Apache-2.0, npmadd-mcp) already tracks where 25 clients keep their servers and in what shape, on macOS, Linux and Windows. This PR moves the clients where add-mcp's output is equivalent or better onto it, behind our own interface, and keeps box-specific behavior in our layer.Spike: add-mcp 2.6.1 vs our writers
Run against our test fixtures (
cli/test/fixtures/*) in a temp HOME withupsertServer(agent, 'box', {type: 'http', url})/removeServer, then against the real clients.~/.cursor/mcp.json){url}(same)mcpServersmap is re-indented as a wholeCode/User/mcp.jsonunder Application Support /%APPDATA%/ XDG){type: "http", url}(same)~/.config/opencode/opencode.jsoncor.json, whichever exists (new file:.jsonc; ours:.json). IgnoresXDG_CONFIG_HOMEandOPENCODE_CONFIG{type: "remote", url, enabled: true}(same); writesmcp.servers.boxwhen the file uses OpenCode's newer layout (ours did not)mcpmap re-indentedXDG_CONFIG_HOMEpoints away from~/.config~/.gemini/settings.json{type: "http", url};gemini mcp listshowsbox: … (http)$CODEX_HOME/config.toml)type = "http"startup_timeout_sec) and subtables ([mcp_servers.box.tools.*]approvals) are dropped$HERMES_HOME,%LOCALAPPDATA%\hermes, plus Hermes profiles (active_profile), which ours does not follow{url}only: noauth: oauth, sohermes mcp login boxrefuses it ("not configured for OAuth"); no key mode~/.claude.jsondirectly{type: "http", url}claude plugin installBehavior add-mcp does not have, all of it kept in our layer (
src/clients/add-mcp-client.js):boxthat is not ours (e.g. box.com)--nameto install next to it;removeleaves it*.box-backup-<time>of the previous content, only when the file changedwriteFileSyncin place)box-controlentries.env0600What changed
cli/src/config-writer.js: our interface (inspect,apply). add-mcp runs in a child process (add-mcp-worker.js) with the CLI context's environment, because it resolves HOME and env overrides once at import. Unit tests keep their temp HOME, and the paths add-mcp writes are the ones the rest of the CLI reads. Cost: about 40 ms per call, two calls per client on connect.cli/src/clients/add-mcp-client.jsreplacesjson-client.js;cursor.js,vscode.js,opencode.jsuse it;gemini-cli.jsis new.formats.js: the JSON upsert/remove writers are gone (TOML, YAML, .env and the strict JSON parser stay).cli.js: a config that can't be written (EACCES/EPERM, "Access is denied") gets a clear message; Codex adds the Codex app steps (Settings → MCP servers → Add server → Streamable HTTP → URL → Save → restart → Authenticate).codex.js: with nocodexon PATH (the Codex app alone), the sign-in hint points at the app's Settings instead ofcodex mcp login.gemini-cli(@google/gemini-cli@0.66.0) on Linux, macOS and Windows.Deleted vs kept:
json-client.js(87 lines) and the JSON writers informats.js(~45 lines) are gone; the new wrapper, worker and adapter are ~210 lines, so line count goes up. What we no longer maintain is the per-client path and shape knowledge for the moved clients; adding a client add-mcp already knows is now a ~15-line file (gemini-cli.js).Supply chain
add-mcppinned exactly at2.6.1(published 2026-11-01). It adds 6 packages:@clack/prompts@0.9.1(+@clack/core),@iarna/toml,chalk,commander, plusjsonc-parserandyamlwe already had. No install scripts anywhere in the tree;npm audit --omit=dev: 0 vulnerabilities.Tests
mcp.servers, restore + no stray backup when add-mcp fails, Gemini CLI round trip, OpenCode XDG stop, EACCES on Codex's config prints the app steps, Codex hint withoutcodexon PATH. Tests that hard-coded VS Code's Linux path now ask the client for its location.gemini-cli,opencode,codexOK. The full Linux/macOS/Windows matrix runs in CI on this PR.Review
Independent review (simular-code-review + secure-coding invariant review): no blocking findings. Fixed in the second commit:
mcp.serversmap (newer layout) failed connect. The key choice now mirrors add-mcp's.BOX_TOKEN/MCP_BOX_API_KEY.Not changed (judgment calls): add-mcp's own dependencies are caret ranges, so npx users resolve a floating tree, as with our existing deps (option: ship an
npm-shrinkwrap.json). The child-process worker exists only because add-mcp reads HOME at import; an upstream "resolve per call" option would remove it.Not done (follow-ups)
active_profile), which add-mcp follows and we don't.XDG_CONFIG_HOMEfor OpenCode, keepauth: oauthfor Hermes, format-preserving Codex TOML edits, OpenClaw, and a "replace only if the URL matches" option. Then Codex and Hermes can move too.🤖 Generated with Claude Code