#!/usr/bin/env python3 """Combine a shared MCP-server config with a port-substituted template for one AI coding-agent client. Invoked per workspace by manage.sh's `write-instance-mcp-configs` (JSON clients) and by `start-coding-agent` (Codex). Each supported client ships a `.devenv/shared/.{json,toml}` (workspace-independent entries, e.g. Playwright) and a `.devenv/templates/.{json,toml}` (per-workspace entries with `${PENPOT_MCP_PORT}` / `${SERENA_MCP_PORT}` placeholders). This script combines the two for the target client. Two output modes are supported: json Deep-merge two JSON documents under a configurable top-level key (`mcpServers` for Claude Code, `mcp` for opencode, `servers` for VS Code Copilot) and write the result to . Same-name entries in the template override entries in shared. With --merge-into-existing, any pre-existing file is loaded as the lowest-precedence layer first, so entries the developer already had are preserved (ours win on name collision). This is used for VS Code's auto-discovered `.vscode/mcp.json`, which on ws0 IS the live repo's file and may hold the developer's own servers; the Claude/opencode outputs live in a dedicated, gitignored `.devenv/mcp/` path and are written without the flag (a clean overwrite). codex-args Deep-merge the two TOML chunks and print one `dotted.key=` assignment per line to stdout (no file). The caller wraps each line in a `codex -c` flag. Codex has no way to load an MCP config from an arbitrary file path (CODEX_HOME would relocate auth/history too), so rather than writing the auto-discovered `.codex/config.toml` we inject our servers as ephemeral per-invocation overrides. This never touches the developer's project- or user-level Codex config. In both modes, `${VAR}` placeholders inside *either* chunk are resolved from the current environment (only template chunks carry placeholders in practice, but the substitution is uniform either way) using Python's `os.path.expandvars`. Undefined placeholders are left as `${VAR}` literal text -- callers (i.e. manage.sh) are responsible for exporting the variables before invoking the script. Usage: merge-mcp-config.py --format json --key [--merge-into-existing] \