ccmcp

command module
v0.23.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 2, 2026 License: MIT Imports: 3 Imported by: 0

README

ccmcp

A dynamic CLI and TUI for managing Claude Code's MCP servers, plugins, and per-project overrides across every scope Claude Code honors.

Why

Claude Code auto-loads MCP servers from at least six distinct places - user config, local project state, committed .mcp.json, bundled plugin .mcp.jsons, claude.ai OAuth integrations, and in-memory overrides. Starting a session with all of them enabled burns hundreds of tokens of context before you type a character. The built-in /mcp menu lets you toggle things one row at a time; ccmcp lets you toggle them in bulk, by scope, or by filter, and gives you a single view that reflects what will actually load in the current project.

Install

Homebrew (macOS, Linux):

brew install robworks-code/tap/ccmcp

Homebrew 5.x tap trust: Homebrew 5.x requires third-party taps to be trusted before it will load them, so on install or brew upgrade you may see Refusing to load formula robworks-code/tap/ccmcp from untrusted tap. Trust the tap once with:

brew trust robworks-code/tap

This is a one-time, per-machine step recorded in ~/.homebrew/trust.json and applies to every non-official tap, not just this one.

go install (needs Go 1.25+):

go install github.com/ringo380/ccmcp@latest

Prebuilt binaries: download from the releases page.

From source:

git clone https://github.com/ringo380/ccmcp
cd ccmcp
go build -ldflags='-s -w' -o ~/bin/ccmcp .
Shell completions

ccmcp completion <shell> prints a completion script for bash, zsh, fish, or powershell. The static --scope flag and dynamic mcp stash <name> / mcp restore <name> arguments tab-complete to live values.

bash (Linux):

ccmcp completion bash | sudo tee /etc/bash_completion.d/ccmcp

bash (Homebrew on macOS, after brew install bash-completion):

ccmcp completion bash > "$(brew --prefix)/etc/bash_completion.d/ccmcp"

zsh (one-shot, current shell):

source <(ccmcp completion zsh)

zsh (persistent, requires compinit enabled in ~/.zshrc):

ccmcp completion zsh > "${fpath[1]}/_ccmcp"

fish:

ccmcp completion fish > ~/.config/fish/completions/ccmcp.fish

powershell:

ccmcp completion powershell | Out-String | Invoke-Expression

Quick start

# In any project directory:
ccmcp

The "effective" view is the default. It lists every MCP that will load in this project, with a badge showing its source and a checkbox showing whether it's currently enabled here. Three keystrokes to turn off every plugin-registered MCP for this project:

/plugin      <enter>      N      w
  • /plugin - filter rows whose name contains "plugin" (or filter on a plugin name like cloudflare)
  • N - bulk-disable everything visible (writes to disabledMcpServers for this project only)
  • w - save

Undo the same way with A.

What ccmcp sees

Badge Source Location Effect
u user ~/.claude.json#/mcpServers loads in every project
l local ~/.claude.json#/projects[<cwd>]/mcpServers this directory only
p project ./.mcp.json shared via git, team-wide
P plugin bundled .mcp.json per enabled plugin loads whenever plugin enabled
@ claude.ai OAuth remote integration loads wherever you're signed in
s stash ~/.claude-mcp-stash.json ccmcp-owned, parked

The effective view's [x] / [~] / [ ] marks mean:

  • [x] - will load in this project
  • [~] - disabled here via a per-project override (easy to undo)
  • [ ] - not active in this project by any source
  • [?] - in disabledMcpServers but no live source found (stale); the row description explains why (plugin not installed, name deleted/renamed, etc.) and ccmcp mcp prune offers to clean it up.

Every row has a resolved source. MCPs whose parent plugin is installed but globally disabled render as [ ] with description (currently disabled) so you can tell them apart from genuinely absent sources.

TUI keys

MCPs tab (default)

Key Action
space toggle current row in the active scope
A / N bulk enable/disable every visible row
S stash the current row (or unstash if it's already in stash)
m move an MCP's config between user / local / stash
s cycle scope: effective → local → user → project → stash
/ filter by substring (enter to lock, esc to cancel)
c clear filter
j / k / arrows navigate
g / G top / bottom
pgup / pgdn page

Plugins tab

Key Action
space toggle plugin enabled/disabled
A / N bulk enable/disable every visible plugin
B bulk update - re-fetch every installed plugin
F show last bulk-update failures (stderr + hint; R retries one)
x remove (two-step confirm); clean-removes plugins flagged ⚠ removed from marketplace, including their cache dir
R refresh update probes + recheck marketplace membership (live)
f cycle filter: all → enabled → disabled
/ search

Discover tab

Key Action
enter drill in (marketplace → plugins → conflict preview)
a add the selected marketplace (clones it + writes settings)
i install the selected/previewed plugin (adds its marketplace first if needed; i twice to reinstall an existing one)
H show/hide already-installed marketplaces (hidden by default)
r refresh discovery sources (bypass cache)
/ filter (matches name, description, tags)
c clear filter
j / k / arrows navigate · g / G top / bottom · b / esc back

Browse a substantial built-in registry of curated Claude Code marketplaces (plus the awesome-list scraper and any discoverySources URLs), sorted by GitHub stars. By default the list shows only marketplaces you haven't installed yet - managing existing ones is the Marketplaces tab's job; press H to reveal installed entries (marked [=]). a adopts a marketplace without retyping it in the Marketplaces tab; i installs a plugin in one keystroke and enables it.

Tweaks - Profiles sub-view

Key Action
enter apply profile (replaces current project's MCPs)
n create profile from current state
d delete
j/k, g/G, pgup/pgdn navigate / jump / page

Tweaks - Summary sub-view

Key Action
j / k / arrows navigate fixable issues (skips display rows; scrolls past the ends)
f preview a fix for the selected issue (in-place orphan/stash prune, or claude --print for config edits)
F bulk-fix all issues in the cursor's category in one claude run (skill/agent/command frontmatter rewrites, slash conflicts, etc.)
l run an LLM review on the selected issue without applying it
y / n / esc approve / cancel in the confirm panel; u reverts a landed CLI fix
p bulk-prune orphan overrides (legacy; press twice to confirm)

Bird's-eye overview of every scope's counts, per-project overrides, and redundancies. Each actionable row (orphan override, stash redundancy, duplicate-load, slash-command conflict, plugin registration drift) is cursor-selectable and fixable in place - orphan prunes and stash drops apply directly to the in-memory state (save with w), and config edits hand off to claude --print non-interactively with an in-TUI spinner.

Tweaks - Doctor sub-view

Key Action
r re-run lint checks
l run one bundled LLM review across CLAUDE.md + MEMORY.md (Haiku, single call)
a apply the bundled review back to disk (single Claude call)
j / k / arrows scroll
g / G top / bottom
f preview a fix for the selected issue (programmatic when possible)
F bulk-fix every issue sharing the cursor's code in one keystroke (programmatic stack, or single bundled claude call when CLI-only)
y / n approve / reject the previewed fix (in confirm panel)
u revert a CLI fix from its on-disk snapshot (in post-review panel)

Runs structural lint on CLAUDE.md and MEMORY.md for the current project. Pressing f opens a preview panel: in-TUI fixes show a unified diff of the exact change before you approve; Claude-CLI fixes show the full prompt first, then after the CLI runs, show the resulting diff and let you keep (y) or revert (u). Every fix snapshots the original file to ~/.claude-mcp-backups/doctor/ (kept: 20 newest per file, max age 30 days). F bulk-fixes every issue that shares the cursor's lint code in a single keystroke - programmatic codes (broken index entries, missing frontmatter fields, standalone broken links, empty MEMORY.md) are applied directly with per-file snapshots; CLI codes (line-too-long, file-too-long, content rewrites) are bundled into one claude --print --max-turns 4 invocation with a strict-imperative envelope that forces Edit-tool calls instead of prose responses.

ccmcp's doctor lints content quality (CLAUDE.md/MEMORY.md structure, skill/agent/command description and token-budget limits) - it complements, and does not duplicate, Claude Code's own built-in /doctor, which validates config (auto-updater health, settings/.mcp.json schema). The asset-lint limits calibrate to the installed Claude Code version (detected via claude --version and shown as · CC <ver> in the header); the per-skill description cap honors your skillListingMaxDescChars setting. To support a new Claude Code version, the version logic lives in one place - internal/claudecode/CapabilitiesFor.

Tweaks tab (t to open)

The Tweaks tab consolidates app-level controls into five sub-views, cycled with [ / ] (or left/right arrows):

  • Settings - toggle ccmcp preferences (offline discovery mode, etc.) with space/enter. Settings are persisted to ~/.claude-mcp-config.json and honored on the next launch.
  • Maintenance - one-keystroke ops: snapshot the current config, prune stale overrides, GC orphaned plugin caches, and run a health-check. Press enter on any action to run it.
  • Summary - the bird's-eye overview (same content as the former top-level Summary tab).
  • Doctor - the CLAUDE.md/MEMORY.md linter (same content as the former top-level Doctor tab).
  • Profiles - save/apply MCP profiles (same content as the former top-level Profiles tab).

Digits 8/9/0 are unbound; all former numeric shortcuts for Profiles/Summary/Doctor are replaced by t + [/] navigation.

Global

Key Action
tab / shift+tab cycle tabs
1-7 jump to MCPs / Plugins / Marketplaces / Discover / Skills / Agents / Commands
t jump to Tweaks tab (Settings sub-view)
[ / ] or arrows switch Tweaks sub-sections: Settings / Maintenance / Summary / Doctor / Profiles
ctrl+g global search across all tabs (enter jumps to the row, esc closes)
w save all staged changes
q quit (warns if unsaved)
Q force quit, discard changes

Changes are staged until you press w. An UNSAVED badge appears in the header whenever you have pending edits.

CLI

Every TUI action is scriptable from the CLI:

ccmcp status                                   # show everything at once
ccmcp status --json                            # JSON for scripts

ccmcp mcp list [--scope SCOPE]                 # SCOPE: user|local|project|plugin|claudeai|overrides|stash|all
ccmcp mcp enable  <name> [--scope SCOPE]
ccmcp mcp disable <name> [--scope SCOPE] [--to-stash]
ccmcp mcp move    <name> --to {user|local|stash}
ccmcp mcp override <name> [--undo]             # per-project disable (writes disabledMcpServers)
ccmcp mcp prune [--dry-run] [--yes]            # remove stale entries from disabledMcpServers
       [--include-stash-ghosts]                # (keeps disabled-but-installed plugin entries)
ccmcp mcp stash   [<name>...]                  # user-scope → stash
ccmcp mcp restore [<name>...]                  # stash → user-scope (alias: unstash)
ccmcp mcp unstash [<name>...]                  # same as restore

ccmcp profile save|list|show|use|delete <name> [<mcp>...]
ccmcp profile export <name> [--out FILE] [--with-config]
ccmcp profile import [FILE|-] [--overwrite]
ccmcp plugin list [--enabled|--disabled]
ccmcp plugin enable|disable|install|remove <id> [--marketplace M] [--purge]
ccmcp marketplace list|add|remove <name> [--source github|git|local] [--repo R]

ccmcp skill   list [--scope user|project|plugin] [--enabled|--disabled]
ccmcp skill   enable|disable <name> [<name>...]    # writes to skillOverrides
ccmcp skill   new <name> [--scope user|project] [--description D]
ccmcp skill   move <name> --to {user|project}
ccmcp skill   rm   <name> [--scope user|project]
ccmcp skill   show <name>
ccmcp agent   list|new|move|rm|show <name>         # same verb shape as skill
ccmcp command list [--scope user|project|plugin]
ccmcp command conflicts [--include-ignored] [--json]
ccmcp command resolve <effective-name> [--strategy disable-skill|ignore|list]

ccmcp report snapshot [--out FILE] [--format json|md|csv]   # point-in-time state dump
ccmcp report sweep    [--base PATH] [--format json|md|csv]  # summary table across all projects
ccmcp report drift    --from <snapshot.json> [--format json|md]  # what changed since baseline
ccmcp report audit    [--format json|md|csv]                # stale overrides, conflicts, redundancies

ccmcp doctor md [--user] [--memory-dir DIR]                # lint CLAUDE.md + MEMORY.md
ccmcp doctor md --llm-review [--provider anthropic|openai] # + LLM quality review

ccmcp tui --dump [--tab mcps|plugins|marketplaces|discover|skills|agents|commands|profiles|summary|doctor]   # print initial render, no TTY

Global flags: --path <dir> (override cwd), --dry-run, --json, --no-color, --no-update-check (also $CCMCP_NO_UPDATE_CHECK).

Self-update check: the first interactive launch each day queries api.github.com/repos/ringo380/ccmcp/releases/latest (2-second timeout, silent on failure), and if a newer release is out it prints a release-notes excerpt and prompts Update now? [Y/n]. On Y it auto-detects Homebrew vs go install vs a manual binary and runs the matching upgrade command. On n the prompt is suppressed for 24 hours or until a newer release ships. Cached at ~/.claude/plugins/cache/ccmcp-update-check.json.

Per-project overrides

/mcp in Claude Code writes per-project disables to ~/.claude.json#/projects[<path>].disabledMcpServers. ccmcp reads and writes the same field with the same prefix encoding:

Example key Source
"dropbox" stdio MCP (plain name)
"claude.ai Gmail" claude.ai integration
"plugin:context7:context7" plugin-registered MCP (plugin:<plugin>:<server>)

Pressing space on an effective-view row flips the appropriate override key; A/N do it for every visible row at once.

Pruning stale overrides

Over time, disabledMcpServers collects entries that no longer match any live source - e.g. an MCP that was renamed, a plugin that was uninstalled, or a server that moved into the stash. ccmcp mcp prune classifies every entry and removes the stale ones:

ccmcp mcp prune --dry-run                      # list proposed removals, no changes
ccmcp mcp prune --yes                          # go ahead, skip confirmation
ccmcp mcp prune --include-stash-ghosts         # also sweep plain-name overrides that match a stash entry

Orphan entries (plugin not installed, plain name with no source) are pruned by default. Disabled-but-installed plugin overrides are preserved - re-enabling the plugin would re-activate the MCP, and the user likely wanted it off per-project. Remove those explicitly with ccmcp mcp override <key> --undo if that's actually what you want.

Plugin installer

ccmcp plugin install <name> --marketplace <m> fetches source code from the marketplace and records the install in ~/.claude/plugins/installed_plugins.json. Four marketplace source formats are supported:

  • bare string path (./plugins/foo) - subdir of an already-cloned marketplace repo
  • url - full-repo clone, optional sha pin
  • git-subdir - clone a repo and copy a subpath
  • github - repo-shorthand (owner/name, optional ref)

--register-only skips the fetch if the cache dir already exists. --purge on plugin remove also deletes the cache.

Safety

  • Every write is atomic (temp + fsync + rename). No partial writes survive a crash.
  • Before any mutation, ccmcp snapshots the target file to ~/.claude-mcp-backups/<name>-<YYYYMMDD-HHMMSS>.json. Same-second collisions get a numeric suffix.
  • --dry-run never touches disk (asserted by a test against before/after md5s).
  • ~/.claude.json has 80+ telemetry / onboarding / cache fields; ccmcp mutates only what it owns and preserves unknown fields round-trip. Verified by TestClaudeJSONPreservesUnknownFields.

Testing

go test ./...

412 tests across config readers/writers, CLI sandbox runs, installer, skill/agent CRUD, command discovery + conflict classifier + ignore list, profile export/import, marketplace + plugin update probes, plugin MCP scanning (.mcp.json + plugin.json manifest merge), doctor LLM-review provider precedence, doctor autofix preview/snapshot/revert flow, asset lint (skill/agent/command/plugin description + slug rules + skill-shadow detection), Claude Code version detection + capability calibration (probe/cache/mtime-invalidation, version-gated fallback-model, model-override precedence), bulk plugin-update failure capture + retry, marketplace discovery (sources, cache, conflict scan), shell-completion script generation + dynamic arg completion, TUI scroll-window clamping for multi-line list views, and a headless TUI state-machine that drives the real tea.Model with synthesized key events.

Project layout

cmd/              cobra subcommands (status, mcp, profile, plugin, marketplace,
                  skill, agent, command, discover, report, doctor, compat
                  aliases)
internal/
  agents/         agent CRUD + file-backed store
  classify/       override-key classifier (7 buckets)
  claudecode/     installed Claude Code version probe + capability calibration
                  (single place to update per CC release)
  commands/       command discovery, conflict detection, ignore list
  config/         readers + writers for every Claude Code config file
  discovery/      remote marketplace discovery (curated registry + awesome-list
                  + user URLs merged, preview-clone + conflict detection)
  doctor/         CLAUDE.md + MEMORY.md structural linter + asset lint
  install/        plugin marketplace installer (4 source formats)
  paths/          config path resolution ($CLAUDE_CONFIG_DIR aware)
  report/         snapshot / sweep / drift / audit report generators
  selfupdate/     launch-time check vs GitHub releases + Y/n prompt + brew/go
                  dispatch (oh-my-zsh style)
  skills/         skill CRUD + file-backed store
  stringslice/    shared slice helpers
  tui/            bubbletea app: 8 top-level tabs (MCPs, Plugins, Marketplaces,
                  Discover, Skills, Agents, Commands, Tweaks); Tweaks folds
                  Settings, Maintenance, Summary, Doctor, and Profiles as
                  sub-views cycled with [ / ]
  updates/        upstream version probes for marketplaces, plugins, MCPs
main.go

Scope terminology

ccmcp uses Claude Code's native names:

  • user - ~/.claude.json#/mcpServers
  • local - ~/.claude.json#/projects[<cwd>]/mcpServers (what Claude Code calls "local")
  • project - ./.mcp.json (what Claude Code calls "project" - shared via git)
  • stash - ~/.claude-mcp-stash.json (ccmcp-owned)
  • effective - the union of what actually loads in the current project

Legacy aliases --scope project → local and --scope mcpjson → project are still accepted so older scripts keep working.

Contributing

Contributions are welcome. See CONTRIBUTING.md for build/test instructions, coding guidelines, and the Developer Certificate of Origin sign-off requirement (git commit -s). For substantial features, open an issue first to align on the approach.

License & attribution

ccmcp is open source under the MIT License - free to use, fork, modify, and redistribute, provided you retain the copyright notice and license text (see NOTICE).

The "ccmcp" name and brand are reserved and are not covered by the MIT grant. Forks and derivative works must use a clearly distinct name and may not imply official status or endorsement - see TRADEMARK.md. You're welcome to refer to the project by name accurately (e.g. "a fork of ccmcp").

Documentation

The Go Gopher

There is no documentation for this package.

Directories

Path Synopsis
internal
agents
Package agents discovers Claude Code subagents across user, project, and plugin scopes.
Package agents discovers Claude Code subagents across user, project, and plugin scopes.
assets
Package assets contains shared primitives for parsing Claude Code asset files (skills, agents, commands) that use YAML-ish frontmatter.
Package assets contains shared primitives for parsing Claude Code asset files (skills, agents, commands) that use YAML-ish frontmatter.
classify
Package classify buckets a project's disabledMcpServers list by the reason each entry is there.
Package classify buckets a project's disabledMcpServers list by the reason each entry is there.
claudecode
Package claudecode detects the actively-installed Claude Code CLI version and derives a Capabilities bundle that calibrates ccmcp's version-sensitive behavior - asset-lint limits, the headless fix/review model, and fallback-model support - to that exact version.
Package claudecode detects the actively-installed Claude Code CLI version and derives a Capabilities bundle that calibrates ccmcp's version-sensitive behavior - asset-lint limits, the headless fix/review model, and fallback-model support - to that exact version.
commands
Package commands discovers Claude Code slash commands across user, project, and plugin scopes, and classifies duplicate-alias conflicts between sources.
Package commands discovers Claude Code slash commands across user, project, and plugin scopes, and classifies duplicate-alias conflicts between sources.
discovery
Package discovery surfaces Claude Code marketplaces from authoritative online sources (Anthropic-curated lists, awesome-list-style README scraping, an embedded ccmcp registry, and user-supplied registry URLs), shows what each marketplace's plugins contribute, and flags conflicts against already-installed state before the user adopts one.
Package discovery surfaces Claude Code marketplaces from authoritative online sources (Anthropic-curated lists, awesome-list-style README scraping, an embedded ccmcp registry, and user-supplied registry URLs), shows what each marketplace's plugins contribute, and flags conflicts against already-installed state before the user adopts one.
doctor
Package doctor provides structural linting for CLAUDE.md and MEMORY.md files.
Package doctor provides structural linting for CLAUDE.md and MEMORY.md files.
install
Package install fetches plugin source code into the Claude Code cache directory and keeps installed_plugins.json + enabledPlugins in sync.
Package install fetches plugin source code into the Claude Code cache directory and keeps installed_plugins.json + enabledPlugins in sync.
selfupdate
Package selfupdate runs an oh-my-zsh-style background check against the GitHub releases API for ringo380/ccmcp, prompts the user when a newer version is available, and dispatches to the appropriate upgrade command for the detected install method (brew tap vs go install vs raw binary).
Package selfupdate runs an oh-my-zsh-style background check against the GitHub releases API for ringo380/ccmcp, prompts the user when a newer version is available, and dispatches to the appropriate upgrade command for the detected install method (brew tap vs go install vs raw binary).
skills
Package skills discovers Claude Code skills across user, project, and plugin scopes.
Package skills discovers Claude Code skills across user, project, and plugin scopes.
stringslice
Package stringslice holds small, allocation-cheap helpers that were previously duplicated across cmd/ and internal/tui/.
Package stringslice holds small, allocation-cheap helpers that were previously duplicated across cmd/ and internal/tui/.
tui
updates
Package updates probes upstream sources to detect when a newer version of a marketplace, plugin, or MCP server is available.
Package updates probes upstream sources to detect when a newer version of a marketplace, plugin, or MCP server is available.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL