Skip to content

feat: add install command for one-click MCP client setup#177

Merged
ichoosetoaccept merged 1 commit intomainfrom
02-18-feat-add-install-command-for-one-click-mcp-client-setup
Feb 18, 2026
Merged

feat: add install command for one-click MCP client setup#177
ichoosetoaccept merged 1 commit intomainfrom
02-18-feat-add-install-command-for-one-click-mcp-client-setup

Conversation

@ichoosetoaccept
Copy link
Member

@ichoosetoaccept ichoosetoaccept commented Feb 17, 2026

Description

Adds a codereviewbuddy install <client> CLI command for one-click MCP client registration. Instead of manually editing JSON config files, users can now run a single command.

Supported clients

Command Method
codereviewbuddy install claude-desktop Writes to claude_desktop_config.json
codereviewbuddy install claude-code Runs claude mcp add CLI
codereviewbuddy install cursor Opens cursor:// deeplink
codereviewbuddy install windsurf Writes to ~/.codeium/windsurf/mcp_config.json
codereviewbuddy install windsurf-next Writes to ~/.codeium/windsurf-next/mcp_config.json
codereviewbuddy install mcp-json Prints JSON config to stdout

Features

  • Generates uvx --prerelease=allow codereviewbuddy@latest as the server command
  • --env KEY=VALUE flags for environment variables (e.g. reviewer config)
  • --env-file .env to load env vars from a dotenv file
  • mcp-json --copy to copy config to clipboard
  • Uses FastMCP's update_config_file() to safely merge into existing configs

Files

  • src/codereviewbuddy/install.py — new module with install subcommands
  • src/codereviewbuddy/cli.py — registers install_app subcommand group
  • tests/test_install.py — 38 tests covering all clients, env handling, error paths
  • README.md — added "Quick setup" section before manual config instructions

Checklist

  • Tests added/updated
  • Documentation updated (if applicable)
  • poe check passes
  • Commit messages follow conventional commits

Copy link
Member Author

ichoosetoaccept commented Feb 17, 2026

@greptile-apps
Copy link

greptile-apps bot commented Feb 17, 2026

Greptile Summary

Adds a codereviewbuddy install <client> CLI command for one-click MCP client registration, supporting Claude Desktop, Claude Code, Cursor, Windsurf, Windsurf Next, and generic JSON output. The implementation reuses FastMCP's StdioMCPServer model and update_config_file() for config-file clients, shells out to claude mcp add for Claude Code, and opens deeplinks for Cursor.

  • install.py: New 365-line module with well-factored shared helpers (_build_server_config, _write_config_file) and per-client subcommands. Supports --env and --env-file flags for env var injection. Optional pyperclip dependency for clipboard support.
  • cli.py: Registers the install_app subcommand group on the main cyclopts app — minimal, clean integration.
  • tests/test_install.py: Comprehensive test suite with 38 tests covering all clients, env handling, error paths, and edge cases with proper mocking.
  • README.md: New "Quick setup" section with install examples added before the existing manual config instructions.
  • Two minor style suggestions: the Cursor deeplink payload includes an empty env dict (unlike the mcp-json output which omits it), and _find_claude_command only checks stdout for the version string.

Confidence Score: 4/5

  • This PR is safe to merge — well-tested new feature with no functional bugs, only minor style suggestions.
  • Score of 4 reflects a clean, well-structured feature addition with comprehensive test coverage (38 tests). The two style comments are non-blocking improvements. The code correctly handles cross-platform paths, error conditions, and graceful degradation for optional dependencies (dotenv, pyperclip).
  • src/codereviewbuddy/install.py deserves the most attention as the only new production code file (365 lines), though it is well-covered by tests.

Important Files Changed

Filename Overview
src/codereviewbuddy/install.py New 365-line module implementing install subcommands for 6 MCP clients. Well-structured with shared helpers for config building and file writing. Uses FastMCP's StdioMCPServer/update_config_file for config-file clients, subprocess for Claude Code CLI, and deeplinks for Cursor. Minor style suggestions around deeplink payload and version detection robustness.
src/codereviewbuddy/cli.py Minimal change: adds mid-module import and registration of install_app subcommand group. Follows existing cyclopts patterns used elsewhere in the file.
tests/test_install.py Comprehensive test suite with 38 tests covering all install clients, env handling, error paths, and edge cases. Good use of tmp_path, mocker fixtures, and proper mocking of subprocess/filesystem operations.
README.md Adds a "Quick setup (recommended)" section above the existing manual configuration, with clear examples for all supported clients and env var usage. Existing manual config section preserved under a new "Manual configuration" subheading.

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["codereviewbuddy install &lt;client&gt;"] --> B{"Client type?"}
    B -->|claude-desktop| C["_get_claude_desktop_config_path()"]
    B -->|windsurf / windsurf-next| D["_get_windsurf_config_path()"]
    B -->|claude-code| E["_find_claude_command()"]
    B -->|cursor| F["Build deeplink URL"]
    B -->|mcp-json| G["Generate JSON"]

    C --> H["_build_server_config()"]
    D --> H
    H --> I["_write_config_file()"]
    I --> J["update_config_file() from FastMCP"]

    E --> K{"Claude CLI found?"}
    K -->|Yes| L["_build_server_config()"]
    L --> M["subprocess: claude mcp add"]
    K -->|No| N["Exit with error"]

    F --> O["_build_server_config()"]
    O --> P["base64 encode config"]
    P --> Q["_open_deeplink()"]

    G --> R["_build_server_config()"]
    R --> S{"--copy flag?"}
    S -->|Yes| T["pyperclip.copy()"]
    S -->|No| U["print JSON to stdout"]
Loading

Last reviewed commit: 72bb818

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, 3 comments

Edit Code Review Agent Settings | Greptile

@ichoosetoaccept ichoosetoaccept force-pushed the 02-17-build-copier-update-from-template-0.29.1 branch from 03f4e4a to f79a621 Compare February 17, 2026 23:32
@ichoosetoaccept ichoosetoaccept force-pushed the 02-18-feat-add-install-command-for-one-click-mcp-client-setup branch from 2f36cc7 to 336ec8f Compare February 17, 2026 23:32
Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

@ichoosetoaccept ichoosetoaccept force-pushed the 02-18-feat-add-install-command-for-one-click-mcp-client-setup branch from 336ec8f to 53b89c2 Compare February 17, 2026 23:52
@ichoosetoaccept ichoosetoaccept force-pushed the 02-17-build-copier-update-from-template-0.29.1 branch from f79a621 to 44747e2 Compare February 17, 2026 23:52
Copy link
Member Author

ichoosetoaccept commented Feb 18, 2026

Merge activity

  • Feb 18, 7:17 AM UTC: A user started a stack merge that includes this pull request via Graphite.
  • Feb 18, 7:18 AM UTC: Graphite rebased this pull request as part of a merge.
  • Feb 18, 7:19 AM UTC: @ichoosetoaccept merged this pull request with Graphite.

@ichoosetoaccept ichoosetoaccept changed the base branch from 02-17-build-copier-update-from-template-0.29.1 to graphite-base/177 February 18, 2026 07:17
@ichoosetoaccept ichoosetoaccept changed the base branch from graphite-base/177 to main February 18, 2026 07:17
@ichoosetoaccept ichoosetoaccept force-pushed the 02-18-feat-add-install-command-for-one-click-mcp-client-setup branch from 53b89c2 to 72bb818 Compare February 18, 2026 07:18
@ichoosetoaccept ichoosetoaccept merged commit c2bf2dc into main Feb 18, 2026
7 checks passed
@ichoosetoaccept ichoosetoaccept deleted the 02-18-feat-add-install-command-for-one-click-mcp-client-setup branch February 18, 2026 07:19
@blacksmith-sh
Copy link

blacksmith-sh bot commented Feb 18, 2026

Found 9 test failures on Blacksmith runners:

Failures

Test View Logs
coverage: platform linux, python 3.14/3-final-0 View Logs
TestClaudeDesktopCommand/test_installs_to_config_file View Logs
TestWindsurfCommands/test_windsurf_install View Logs
TestWindsurfCommands/test_windsurf_next_install View Logs
TestWriteConfigFile/test_creates_new_config View Logs
TestWriteConfigFile/test_creates_parent_dirs View Logs
TestWriteConfigFile/test_handles_empty_file View Logs
TestWriteConfigFile/test_preserves_existing_servers View Logs
TestWriteConfigFile/test_updates_existing_entry View Logs

Fix in Cursor

Copy link

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

4 files reviewed, 2 comments

Edit Code Review Agent Settings | Greptile

Comment on lines +264 to +265
config_json = server_config.model_dump_json(exclude_none=True)
config_b64 = base64.urlsafe_b64encode(config_json.encode()).decode()
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor deeplink includes empty env in payload

model_dump_json(exclude_none=True) will serialize "env": {} into the base64 payload when no env vars are provided, since an empty dict is not None. The mcp-json command at line 348 explicitly omits env when empty (if server_config.env:), creating an inconsistency between the two output paths. Consider using exclude_defaults=True or filtering the dict to keep the deeplink payload clean:

Suggested change
config_json = server_config.model_dump_json(exclude_none=True)
config_b64 = base64.urlsafe_b64encode(config_json.encode()).decode()
config_json = server_config.model_dump_json(exclude_none=True, exclude_defaults=True)
Prompt To Fix With AI
This is a comment left during a code review.
Path: src/codereviewbuddy/install.py
Line: 264-265

Comment:
**Cursor deeplink includes empty `env` in payload**

`model_dump_json(exclude_none=True)` will serialize `"env": {}` into the base64 payload when no env vars are provided, since an empty dict is not `None`. The `mcp-json` command at line 348 explicitly omits `env` when empty (`if server_config.env:`), creating an inconsistency between the two output paths. Consider using `exclude_defaults=True` or filtering the dict to keep the deeplink payload clean:

```suggestion
    config_json = server_config.model_dump_json(exclude_none=True, exclude_defaults=True)
```

How can I resolve this? If you propose a fix, please make it concise.

capture_output=True,
text=True,
)
if "Claude Code" in result.stdout:
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Version check only inspects stdout

Some CLI tools (including certain Node.js-based CLIs) print version info to stderr rather than stdout. Since capture_output=True already captures both streams, checking result.stderr as well would make this detection more robust:

Suggested change
if "Claude Code" in result.stdout:
if "Claude Code" in result.stdout or "Claude Code" in result.stderr:

The same applies to the fallback check on line 187.

Prompt To Fix With AI
This is a comment left during a code review.
Path: src/codereviewbuddy/install.py
Line: 168

Comment:
**Version check only inspects `stdout`**

Some CLI tools (including certain Node.js-based CLIs) print version info to `stderr` rather than `stdout`. Since `capture_output=True` already captures both streams, checking `result.stderr` as well would make this detection more robust:

```suggestion
            if "Claude Code" in result.stdout or "Claude Code" in result.stderr:
```

The same applies to the fallback check on line 187.

How can I resolve this? If you propose a fix, please make it concise.

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