Skip to content

feat(profile): mcpPrune field — auto-prune MCPs without an env var#91

Merged
NagyVikt merged 2 commits into
mainfrom
feat/profile-mcp-prune
Jun 30, 2026
Merged

feat(profile): mcpPrune field — auto-prune MCPs without an env var#91
NagyVikt merged 2 commits into
mainfrom
feat/profile-mcp-prune

Conversation

@NagyVikt

Copy link
Copy Markdown
Contributor

What

Makes MCP pruning automatic per-profile instead of only opt-in via env. Follow-up to #90 (which added the opt-in CUE_PRUNE_MCPS). A profile can now declare a default prune mode so a heavy profile drops its unused MCP tool schemas on every launch with no env var.

# profile.yaml
mcpPrune: all   # off (default) | profile | all
  • off (default): keep all MCPs — unchanged behavior.
  • profile: drop unused profile-declared MCPs.
  • all: also drop unused global servers from the runtime .claude.json.

CUE_PRUNE_MCPS still overrides at launch (explicit launch-time intent > profile default). Pruning only ever drops MCPs no active skill needs and that aren't pinned, so a higher mode is always safe.

Changes

  • profiles/_types.ts: McpPruneMode type + Profile.mcpPrune (flows to ResolvedProfile).
  • profiles/schema.json: mcpPrune enum.
  • src/lib/profile-loader.ts: leaf-wins through single inheritance; most-aggressive wins across composite parts (off<profile<all). Fixed the composite fold loop that dropped the resolved scalar.
  • src/commands/launch.ts: effective mode = env (if set) else profile.mcpPrune else off; log line reports the source.
  • src/lib/mcp-overrides.ts: McpPruneMode re-exported from _types (single source of truth).

Test plan

  • bun test src/lib/profile-loader.test.ts — new mcpPrune resolution block (unset / single / inherit / composite most-aggressive): 32 pass.
  • bunx tsc --noEmit — clean.
  • E2E verified: a profile with mcpPrune: all drops an unused MCP (dataforseo) on a clean-cwd launch with no env var, keeps pinned codegraph; env override still works.

🤖 Generated with Claude Code

NagyVikt and others added 2 commits June 30, 2026 03:19
Adds a `mcpPrune: off|profile|all` profile field setting the default
non-interactive prune mode, so a heavy profile drops its unused MCPs on every
launch with no CUE_PRUNE_MCPS needed. The env var still overrides per launch
(explicit launch-time intent > profile default).

- profiles/_types.ts: McpPruneMode type + Profile.mcpPrune (flows to ResolvedProfile).
- profiles/schema.json: mcpPrune enum [off,profile,all].
- profile-loader.ts: leaf-wins through inheritance; most-aggressive wins across
  composite parts (off<profile<all) — safe, since prune only drops unused,
  non-pinned MCPs. Fixed the composite fold loop dropping the resolved value.
- launch.ts: effective mode = env (if set) else profile.mcpPrune else off;
  the auto-prune branch and its log line report the source.
- mcp-overrides.ts: McpPruneMode now re-exported from _types (single source).

Tests: profile-loader mcpPrune resolution (unset/single/inherit/composite).
Verified e2e: a profile with mcpPrune:all drops an unused MCP on a clean-cwd
launch with no env var; pinned MCPs kept.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…w M1)

Review flagged that the new env-overrides-profile logic enlarged a foot-gun: a
non-empty but unrecognized CUE_PRUNE_MCPS (a typo like `profil`) parses to "off"
and would silently SUPPRESS a profile's mcpPrune default. Add isRecognizedPruneEnv
so a set-but-unrecognized value is a no-op: warn to stderr and fall through to the
profile default, instead of disabling it without a diagnostic. An explicit
`off`/`0`/`false` still wins over the profile (recognized).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@NagyVikt NagyVikt merged commit b51e83a into main Jun 30, 2026
4 of 5 checks passed
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