Skip to content

feat(installer): OpenCode MCP support + fix silent merge-failure bug#46

Merged
aniongithub merged 1 commit into
mainfrom
feat/opencode-installer
May 23, 2026
Merged

feat(installer): OpenCode MCP support + fix silent merge-failure bug#46
aniongithub merged 1 commit into
mainfrom
feat/opencode-installer

Conversation

@aniongithub
Copy link
Copy Markdown
Owner

Adds OpenCode (https://opencode.ai) as an installer-detected MCP client, alongside Claude / GitHub Copilot / VS Code / Cursor.

While wiring it in I also caught — and fixed — a silent-failure bug in the existing merge path that affected all clients, not just OpenCode.

OpenCode support

OpenCode's MCP config shape differs from the other four:

  • top-level key is "mcp" (not "mcpServers")
  • command is a JSON array, not a string + separate args
  • entries carry "enabled": true
  • includes a $schema pointer when we create the file

A new configure_opencode() function in install.sh (and a Set-OpenCodeMcpConfig in install.ps1) emits and merges this shape. Detection mirrors the other clients: the config file already exists, the config directory has been created, or the opencode binary is on PATH. Paths written:

OS File
Linux/macOS ~/.config/opencode/opencode.json (or .jsonc if that's what exists)
Windows %APPDATA%\opencode\opencode.json

SKILL.md also gets dropped into OpenCode's primary skill discovery path (~/.config/opencode/skills/mind-map/SKILL.md, %APPDATA%\opencode\skills\mind-map\SKILL.md). OpenCode would also discover the file via its ~/.claude/skills/ and ~/.agents/skills/ fallbacks — both of which the installer already writes — but writing the primary path is more explicit.

Pre-existing bug fixed

configure_mcp_client was building its python3 merge step by interpolating the JSON entry string into Python source code via shell quoting:

python3 -c "

entry = json.loads('${mcp_entry}')

"

That works for the empty-config "created file" branch, but for any existing config file the Python source becomes:

entry = json.loads('{"type": "local", "command": "/path", "args": [], …}')

…which is a SyntaxError on the embedded double-quotes. The error was redirected to /dev/null, and the script printed a generic ! could not update with no diagnostics. Net effect: anyone with a pre-existing Claude / Copilot / Cursor / VS Code MCP config — i.e. essentially all real-world users — was silently not getting mind-map added.

Fix: pass the JSON entry via an environment variable, which sidesteps the shell-into-Python quoting entirely:

MM_CFG=… MM_ENTRY=… MM_CLIENT=… python3 -c '
import json, os

servers["mind-map"] = json.loads(os.environ["MM_ENTRY"])
'

configure_opencode uses the same pattern from the start.

Verified

Ran end-to-end inside the devcontainer:

  1. OpenCode fresh — creates opencode.json with $schema, mcp, and a clean mind-map entry.
  2. OpenCode merge — pre-populates with a playwright entry and model: setting; both are preserved, mind-map is added alongside.
  3. Claude-shape merge (regression for the silent-failure bug) — pre-populates mcpServers with a foo entry; foo is preserved, mind-map is added.

All three produce correctly-merged JSON.

…ure bug

OpenCode (https://opencode.ai) is now detected and configured alongside
Claude / Copilot / VS Code / Cursor. Its MCP shape differs:

  - top-level key 'mcp' (not 'mcpServers')
  - command is a JSON array (not string + separate args)
  - 'enabled': true is expected
  - schema URL pointer

A new configure_opencode() function emits and merges this shape. Detection
follows the same pattern used for other clients: the config file already
exists, the config directory has been created, or the 'opencode' binary
is on PATH. On Linux/macOS we write ~/.config/opencode/opencode.json; on
Windows %APPDATA%\opencode\opencode.json.

SKILL.md gets dropped into the new client's primary skill discovery path
too (~/.config/opencode/skills/mind-map/SKILL.md and
%APPDATA%\opencode\skills\mind-map\), although OpenCode already finds
SKILL.md via its ~/.claude/skills/ and ~/.agents/skills/ fallback paths
which the installer was already writing.

Also fixes a pre-existing silent-failure bug in configure_mcp_client: the
embedded python3 block interpolated the JSON entry string directly into
Python source via shell quoting. For any existing config file (i.e. any
real-world install where Claude/Copilot/Cursor/VS Code is already set
up), Python raised SyntaxError on the embedded double-quotes, the error
was redirected to /dev/null, and the script reported '! could not
update' with no diagnostics. The fix passes the JSON entry via an
environment variable instead, which sidesteps the quoting altogether.
Verified end-to-end in the devcontainer against both fresh-file and
merge-into-existing scenarios for both the OpenCode and Claude shapes.
@aniongithub aniongithub force-pushed the feat/opencode-installer branch from 3628337 to 627bb33 Compare May 23, 2026 04:38
@aniongithub aniongithub merged commit d258ac1 into main May 23, 2026
1 check passed
@aniongithub aniongithub deleted the feat/opencode-installer branch May 23, 2026 04:43
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