camunda / camunda/c8ctl

Make MCP client setup just work: c8ctl mcp install <client>

Open
#293 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
TypeScript
Stars
7
Forks
0
Avg merge
15h 36m
Merged PRs (30d)
28

Description

User report

Hi team, I had a bit of trouble configuring the c8ctl mcp-proxy in Claude. Our docs say the key name in the JSON config is server, but Claude Desktop expects mcpServers in its claude_desktop_config.json; everything else is being ignored. When restarting Claude, it shows two error messages, but these can safely be ignored.

The docs have a key-name defect (servermcpServers). The fix "update the docs" is unsatisfying — reading docs to hand-edit a JSON file is a 2006 onboarding experience. We should make this just work without docs.

Proposed solution: c8ctl mcp install <client>

Add install / uninstall subcommands that edit the MCP client's config file for the user:

c8ctl mcp install claude-desktop   [--profile <name>] [--alias <name>]
c8ctl mcp install cursor           [--profile <name>] [--alias <name>]
c8ctl mcp install vscode           [--profile <name>] [--alias <name>]
c8ctl mcp uninstall claude-desktop [--alias <name>]
c8ctl mcp list                     # show installed entries across known clients
Behaviour
  1. Resolve client config path per OS:
    • Claude Desktop (macOS): ~/Library/Application Support/Claude/claude_desktop_config.json
    • Claude Desktop (Windows/WSL): %APPDATA%/Claude/claude_desktop_config.json
    • Cursor: ~/.cursor/mcp.json
    • VS Code (user MCP): ~/Library/Application Support/Code/User/mcp.json or the workbench.mcp.servers setting
  2. Read, merge, write:
    • Preserve existing unrelated keys (preferences, other mcpServers entries).
    • Use the client's correct top-level key name (mcpServers for Claude, servers for VS Code's MCP schema, etc.).
    • Key the entry by --alias (default: active profile name, fallback "camunda").
  3. Embed the active profile's credentials:
    • Read from the c8ctl profile store (same config c8ctl already knows).
    • Emit the env block with CAMUNDA_BASE_URL, CAMUNDA_CLIENT_ID, CAMUNDA_CLIENT_SECRET, CAMUNDA_OAUTH_URL, CAMUNDA_TOKEN_AUDIENCE.
    • Use the correct command + args shape: "command": "npx", "args": ["-y", "@camunda8/cli", "mcp-proxy"].
  4. Atomic write: write to tmpfile + rename, so a partial failure doesn't corrupt the user's Claude config.
  5. --dry-run: print the merged JSON without writing (we already have the dryRun() helper — uses the existing framework).
  6. Friendly confirmation:
    ✔ Installed camunda → claude-desktop
      Config: ~/Library/Application Support/Claude/claude_desktop_config.json
      Restart Claude Desktop to activate.
    
Why this kills the defect class, not just the instance
  • No docs hand-off: the JSON key name (mcpServers vs server vs servers) is owned by code with a test per client. A key-name typo becomes a test failure, not a user-hours-lost incident.
  • Secret-handling normalisation: today users copy-paste secrets from c8ctl profile output into Claude's config. The install command keeps secrets inside a single trusted tool and writes them with chmod 600 (where applicable).
  • Multi-profile pattern: users juggling saas-stable + local + customer-dev get c8ctl mcp install claude-desktop --profile customer-dev --alias acme and end up with named, clearly-scoped entries.
  • Symmetric uninstall: removes the defect-class of "leftover stale credentials in Claude config" that happens with hand-edited JSON.
  • Per-client adapters are isolated: one small adapter per client (Claude, Cursor, VS Code). Each adapter tests the key name, path resolution, and merge semantics. Adding a new client (Zed, Windsurf, …) is a single file.
Docs impact

After this ships, the docs collapse to:

Run c8ctl mcp install claude-desktop and restart Claude. Done.

The key-name defect in current docs becomes unreachable — no user is hand-editing that file any more.

Open design choices (flag if anything is contentious)
  1. Command shape: c8ctl mcp install <client> vs. reusing mcp-proxy install <client>. Prefer a new mcp verb — mcp-proxy is the runtime, mcp is the configurator.
  2. Client enum: start with claude-desktop. Add cursor and vscode in the same PR if cheap; otherwise stub them with a "not yet supported" error that links to the issue.
  3. Alias defaulting: use the active profile name. If that collides with an existing entry, error with a hint to pass --alias.
  4. Secrets handling: for OAuth client secrets, keep as plain env vars (matches Claude's current config shape) — OS keyring integration is a separate, larger issue.

Related

  • #288 — normalise command architecture. This new mcp command goes in as a canonical-shape handler from day one.
  • Existing mcp-proxy runtime command stays unchanged.

Acceptance

  • c8ctl mcp install claude-desktop writes a valid merged config that Claude Desktop accepts without errors on restart.
  • Tests per client adapter verify key names + merge semantics against realistic pre-existing config fixtures (including the preferences + unrelated mcpServers blocks).
  • --dry-run renders through the framework's JSON/text modes.
  • Uninstall is symmetric and safe on already-absent entries.
  • Docs section reduced to a single-line install invocation.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start by locating the existing mcp-proxy command, the profile store, the dryRun() helper, and the canonical command architecture described in #288. Define client adapters for the requested config paths, key names, merge and atomic-write behavior, then add fixtures covering install, uninstall, and dry-run. Done means the acceptance cases pass and the documentation becomes a single install invocation.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
cli
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.