feat: clean up keychain secrets on mcp remove#25
Merged
Conversation
Add interactive prompt when removing an MCP with stored secrets, plus --keep-secrets and --remove-secrets flags for non-interactive use. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
kaushalpaneri
commented
Mar 24, 2026
kaushalpaneri
left a comment
Contributor
Author
There was a problem hiding this comment.
PR Review Summary
| # | Severity | Category | Finding |
|---|---|---|---|
| 1 | WARNING | Tests | mock_backend fixture in test_mcp_remove_secrets.py is defined but never referenced by any test |
| 2 | NIT | Logic | Redundant index cleanup after backend.delete() — each delete() already calls _index_remove_key(), so the subsequent load_secrets_index() + pop() is defensive but rarely needed. Not a bug, just a minor optimization opportunity. |
Verdict: APPROVE (self-review — cannot self-approve via GH)
- CI: Lint ✅, Security ✅, Validate ✅, Tests pending (all 423 pass locally)
- Code: Clean implementation, follows existing patterns (
_auth_keychainin auth.py) - Security: Only key names printed, never values. Uses established
backend.delete()path - Tests: 9 unit tests + 3 integration tests cover all code paths (flags, interactive, non-interactive, partial storage)
- Issue #24: Changes match the proposed implementation exactly
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
When removing an MCP with stored keychain secrets,
crux mcp removenow detects orphaned secrets and prompts the user to clean them up. Adds--keep-secretsand--remove-secretsflags for non-interactive use.Linked Issue
Closes #24 —
crux mcp removeleaves keychain secrets and secrets index entries behind as orphans.Changes
Source
src/crux_cli/cli/commands/mcp.py: Added_cleanup_secrets()helper called after registry removal. Checks for stored secrets via the backend, prompts interactively (Y/n default), and respects--keep-secrets/--remove-secretsflags. Non-interactive sessions default to keeping secrets with an informational message.src/crux_cli/cli/main.py: Added--keep-secretsand--remove-secretsas mutually exclusive flags to themcp removesubparser.Tests
tests/unit/test_mcp_remove_secrets.py: 9 unit tests covering: no auth, no env vars, no stored secrets,--remove-secretsflag,--keep-secretsflag, interactive yes (default), interactive no, non-interactive fallback, and partially stored secrets.tests/integration/test_cli_mcp.py: 3 integration tests covering:--keep-secretsflag,--remove-secretsflag, and mutual exclusivity of both flags.Docs
No doc changes
Config
No config changes
Breaking Changes
None — existing
crux mcp remove <name>behavior is unchanged for MCPs without keychain auth. For MCPs with stored secrets, a new interactive prompt appears (defaulting to Y), but non-interactive sessions silently keep secrets to avoid breaking scripts.Security Considerations
backend.delete(), using the same secure path ascrux mcp auth.~/.crux/secrets.json) is cleaned up atomically after secret deletion.Test Plan
uv run pytest tests/unit/ -v)uv run pytest tests/integration/ -v)uv run ruff check src/ tests/)crux mcp add test --npx pkg --keychain KEY1,KEY2 && crux mcp auth test && crux mcp remove test— verify prompt appearscrux mcp remove test --remove-secrets— verify no prompt, secrets deletedcrux mcp remove test --keep-secrets— verify no prompt, secrets kept🤖 Generated with Claude Code