feat(cli): vouch install-mcp <host> — one-command adapter writer (8 hosts) - #180
Conversation
…osts) Closes vouchdev#179. Generalises the single-host claude-code adapter plan (docs/superpowers/plans/2026-05-27-claude-code-adapter.md) into a catalogue-driven installer that supports eight MCP hosts out of the box and accepts a new host as a single-file PR (just drop an adapters/<host>/install.yaml manifest plus the host's template files). What ships: * src/vouch/install_adapter.py — manifest-driven writer. Reads adapters/<host>/install.yaml; for each declared file copies it into target, or appends a fenced block if the manifest marks the entry fenced_append. Three result channels: written / appended / skipped. Idempotent: re-running on a tree the writer already touched returns everything in `skipped`, nothing in `written`. * vouch install-mcp <host> [--tier T1|T2|T3|T4] [--path .] [--list] — CLI surface. --list enumerates the catalogue (8 hosts, ≥6 required). --tier defaults to T4 (full install); --tier T1 stops at MCP wire. --target is accepted as an alias for --path per the issue spec. * 8 host manifests + templates: claude-code T1 .mcp.json + T2 CLAUDE.md + T3 4 slash commands + T4 .claude/settings.json (read-only kb_* auto-allow + SessionStart hook firing `vouch status --json`) claude-desktop project-local stub + paste-ready user-global JSON, because Claude Desktop's config is user-global only cursor T1 .cursor/mcp.json + T2 AGENTS.md fenced snippet continue T1 .continue/config.yaml (mcpServers block) codex T1 .codex/config.toml windsurf T1 .codeium/windsurf/mcp_config.json cline T1 .cline/mcp_servers.json + T2 .vscode/settings.json fragment (workspace-scoped Cline config) zed T1 .zed/settings.json with context_servers block * tests/test_install_adapter.py — 23 tests. Catalogue (≥6 hosts, sorted, unique, every manifest parseable). claude-code reference tiers T1+T4 + idempotency + CLAUDE.md fence-append + fence-skip semantics. Per-host T1 smoke test parameterised over the 7 non-claude-code hosts. CLI surface (--list, default tier T4, --path, clean error on bad host). * CHANGELOG entry. Acceptance against issue vouchdev#179: ✓ vouch install-mcp --list enumerates ≥6 hosts (ships 8) ✓ Each writer drops files into the correct per-host path; existing files are left alone (fenced append for CLAUDE.md/AGENTS.md only) ✓ Test pack runs each host's writer against a tmp dir and asserts the expected files appear (per-host T1 parametrize + claude-code T4) Out of scope (per issue): auto-detecting which host is running, and an uninstall command (manually delete or revert via git). ruff clean, mypy clean, 383 pytest passed (PR was 360, +23 new tests).
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
the manifest-driven shape here is the right call — the three-channel one question, not a blocker: the manifest gets strict structural validation (every shape of bad YAML is caught with a host-named error, which is great), but semantically the writer trusts whatever paths a contributor puts in tiny / non-blocking: T4 ship it 🙏 |
|
LGTM |
|
Raise the separated PR for the comment |
Summary
Closes #179. Generalises the single-host claude-code adapter plan (
docs/superpowers/plans/2026-05-27-claude-code-adapter.md) into a catalogue-driven installer with 8 supported MCP hosts out of the box, where adding a new host is a single-file PR.Root cause
Adoption today is "follow the README, write
.mcp.jsonby hand, copy CLAUDE.md, hope you got it right." Each host (Claude Code, Cursor, Windsurf, Zed, Cline, JetBrains, Claude Desktop) has a slightly different config-file path. The existing plan covered the writer for one host (claude-code); issue #179 asks to generalise it to a catalogue.Fix
Manifest-driven writer.
src/vouch/install_adapter.pyreads a YAML manifest per host (adapters/<host>/install.yaml) declaring which template files land at which paths, under which adoption tier:kb_*auto-allow)Tiers stack:
--tier T4runs everything available;--tier T1stops at MCP wire. Each manifest declares only the tiers its host has templates for; the writer treats absent tiers as no-ops.Idempotent.
install()returns three channels —written,appended,skipped. Re-running on the same target tree returns everything inskipped. CLAUDE.md/AGENTS.md snippets are appended inside a<!-- BEGIN vouch --> ... <!-- END vouch -->fence on first write; on re-run the writer sees the fence and treats it asskippedinstead of duplicating the block.CLI.
vouch install-mcpadds:Catalogue (8 hosts; #179 acceptance was ≥6):
claude-code.mcp.jsonCLAUDE.md.claude/settings.jsonclaude-desktopclaude-desktop/claude_desktop_config.json(paste-ready)cursor.cursor/mcp.jsonAGENTS.mdcontinue.continue/config.yamlcodex.codex/config.tomlwindsurf.codeium/windsurf/mcp_config.jsoncline.cline/mcp_servers.json.vscode/settings.jsonzed.zed/settings.json(context_servers)claude-desktopis the asymmetric one — Claude Desktop's MCP config is user-global, not project-local. The writer drops a paste-ready JSON + README under<target>/claude-desktop/so the user can review and copy it themselves, rather than reaching into~/Library/Application Support/from a project-scoped command (which would conflict with #179's explicit "uninstall + auto-detection out of scope").Test Plan
tests/test_install_adapter.py(23 new)pytest— 383 passed (PR was 360, +23 new, no regressions)--list, T1 install, idempotent re-run) confirmed in shellTest coverage
test_available_adapters_lists_at_least_six_hoststest_available_adapters_is_sorted_and_uniquetest_every_adapter_has_a_parseable_manifesttest_install_claude_code_t1_writes_only_mcp_jsontest_install_claude_code_t4_writes_all_tierstest_install_claude_code_is_idempotentwritten, fullskippedtest_install_claude_md_appends_when_existing_unfencedtest_install_claude_md_skips_when_already_fencedtest_install_unknown_adapter_raises/_unknown_tier_raisestest_each_host_writes_its_t1_file[...]× 7test_install_returns_dataclass_with_three_channelstest_cli_install_mcp_list_enumerates_hosts--listshows ≥6test_cli_install_mcp_claude_code_writes_into_path--pathhonoredtest_cli_install_mcp_unknown_host_is_clean_errortest_cli_install_mcp_second_run_shows_skippedtest_cli_install_mcp_default_tier_is_t4Output
Out of scope (per #179)
Closes #179