Skip to content

feat: clean up keychain secrets on mcp remove#25

Merged
kaushalpaneri merged 2 commits into
mainfrom
feat/issue-24
Mar 24, 2026
Merged

feat: clean up keychain secrets on mcp remove#25
kaushalpaneri merged 2 commits into
mainfrom
feat/issue-24

Conversation

@kaushalpaneri

Copy link
Copy Markdown
Contributor

Summary

When removing an MCP with stored keychain secrets, crux mcp remove now detects orphaned secrets and prompts the user to clean them up. Adds --keep-secrets and --remove-secrets flags for non-interactive use.

Linked Issue

Closes #24crux mcp remove leaves 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-secrets flags. Non-interactive sessions default to keeping secrets with an informational message.
  • src/crux_cli/cli/main.py: Added --keep-secrets and --remove-secrets as mutually exclusive flags to the mcp remove subparser.

Tests

  • tests/unit/test_mcp_remove_secrets.py: 9 unit tests covering: no auth, no env vars, no stored secrets, --remove-secrets flag, --keep-secrets flag, interactive yes (default), interactive no, non-interactive fallback, and partially stored secrets.
  • tests/integration/test_cli_mcp.py: 3 integration tests covering: --keep-secrets flag, --remove-secrets flag, 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

  • Secrets are deleted from the OS keychain/Secret Service via backend.delete(), using the same secure path as crux mcp auth.
  • The secrets index (~/.crux/secrets.json) is cleaned up atomically after secret deletion.
  • No secrets are logged or printed — only key names are shown.

Test Plan

  • All unit tests pass (uv run pytest tests/unit/ -v)
  • All integration tests pass (uv run pytest tests/integration/ -v)
  • Ruff clean (uv run ruff check src/ tests/)
  • No secrets in committed files
  • Manual: crux mcp add test --npx pkg --keychain KEY1,KEY2 && crux mcp auth test && crux mcp remove test — verify prompt appears
  • Manual: crux mcp remove test --remove-secrets — verify no prompt, secrets deleted
  • Manual: crux mcp remove test --keep-secrets — verify no prompt, secrets kept

🤖 Generated with Claude Code

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 kaushalpaneri left a comment

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

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_keychain in 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>
@kaushalpaneri kaushalpaneri merged commit 7578690 into main Mar 24, 2026
15 checks passed
@kaushalpaneri kaushalpaneri deleted the feat/issue-24 branch March 24, 2026 05:32
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.

feat: crux mcp remove should prompt to clean up keychain secrets

1 participant