Skip to content

feat(cli): add /mcp remove slash command for interactive server removal#26305

Closed
martin-hsu-test wants to merge 1 commit into
google-gemini:mainfrom
martin-hsu-test:try/mcp-remove-clean
Closed

feat(cli): add /mcp remove slash command for interactive server removal#26305
martin-hsu-test wants to merge 1 commit into
google-gemini:mainfrom
martin-hsu-test:try/mcp-remove-clean

Conversation

@martin-hsu-test
Copy link
Copy Markdown
Contributor

Adds the missing third corner of the /mcp lifecycle:

  • /mcp add (existing — via settings file)
  • /mcp enable | disable (existing)
  • /mcp remove (this PR) — interactive removal without leaving the session

Closes the asymmetry where adding an MCP is one step but removing requires manual JSON editing.

What

/mcp remove <name> [--scope user|workspace|all]

Aliases: /mcp rm <name>.

Behavior

  • Single-scope server — auto-removed, no flag needed.
  • Server defined in BOTH user & workspace — refuses with a teaching error message and asks the user to disambiguate (--scope workspace, --scope user, or --scope all). This avoids the silent "zombie config" pitfall where deleting one copy leaves a forgotten copy in the other scope still active after the next restart.
  • Extension-provided servers — rejected with a hint to use /extensions instead (they live in the extension manifest, not in user/workspace settings).
  • After removal, McpClientManager.restart() is called so the server is disconnected and its tools become unavailable immediately.

Why --scope (not --session)

Mirrors the existing gemini mcp remove --scope CLI subcommand naming. --session (used by enable/disable) refers to in-memory persistence — orthogonal to the file-location concept that remove cares about.

Notes

  • No core API changes. Uses the existing McpClientManager.restart() path; no need to add a new removeServer() method.
  • Single file touched in cli/src plus its test plus a docs section. Smallest possible surface.
  • 18 unit tests (12 existing + 6 new) covering: missing arg, unknown server, extension-provided rejection, single-scope auto-remove, multi-scope refusal, --scope user|workspace|all paths, invalid --scope value, completion filtering.
  • Local npm run preflight is green.

Context

Previous attempt at this issue: #19025 (closed after CI failed and the contributor went inactive for 26 days). This PR is a clean-room rewrite against current main rather than a rebase — different design (no --scope all/zombie-detection, no core API change, no UI/snapshot churn) and a fresh test suite.

Adds a new `/mcp remove <server-name> [--scope user|workspace|all]`
slash command (alias `rm`) that removes an MCP server entry from
user or workspace settings without leaving the CLI session.

- If the server is only defined in one scope it is removed
  automatically.
- If defined in BOTH workspace and user scopes the command refuses
  and asks the user to disambiguate with `--scope user`,
  `--scope workspace`, or `--scope all`. This avoids silently
  leaving a zombie copy in the other scope.
- Servers contributed by extensions are rejected with a hint to use
  /extensions instead.
- After removal the MCP client manager is restarted so the server is
  disconnected and its tools become unavailable immediately.

No core API changes — uses the existing
`McpClientManager.restart()` path.

Closes google-gemini#18388
@martin-hsu-test martin-hsu-test requested review from a team as code owners May 1, 2026 01:36
@gemini-code-assist
Copy link
Copy Markdown
Contributor

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request completes the MCP lifecycle management within the CLI by adding the ability to remove configured servers interactively. By providing a dedicated command for removal, it eliminates the need for manual JSON configuration editing, while incorporating safety checks to prevent configuration drift and ensure immediate synchronization of the MCP client state.

Highlights

  • New Slash Command: Introduced the /mcp remove (alias /mcp rm) command to allow interactive removal of MCP servers directly from the CLI.
  • Scope Management: Implemented logic to handle server removal across user and workspace scopes, including a safety mechanism that prevents accidental deletion when a server is defined in both locations without explicit scope selection.
  • Validation and Feedback: Added robust validation to reject removal of extension-provided servers and provided clear error messaging for invalid arguments or scope conflicts.
  • Automatic Reloading: Integrated McpClientManager.restart() to ensure that removed servers are immediately disconnected and their tools are removed from the active session.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for GitHub and other Google products, sign up here.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

Copy link
Copy Markdown
Contributor

@gemini-code-assist gemini-code-assist Bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request introduces the /mcp remove (alias /mcp rm) command, enabling users to delete MCP server configurations directly from the CLI. The implementation handles scope-specific removals (user, workspace, or both) and includes corresponding documentation and unit tests. Feedback focuses on a critical security and functional issue: the code currently uses resolved settings (with expanded environment variables) when modifying the configuration. This could result in leaking secrets into the settings.json file and breaking future variable expansion. It is recommended to use originalSettings to ensure raw configuration is preserved and to remove redundant nullish coalescing operators per project guidelines.

const foundIn: RemovableScope[] = [];
for (const scope of scopeOrder) {
const file = settings.forScope(scope);
const scoped = (file.settings.mcpServers ?? {}) as Record<string, unknown>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

This check should use file.originalSettings.mcpServers instead of file.settings.mcpServers. The settings property contains values after environment variable expansion, whereas originalSettings contains the raw configuration from the file. Using originalSettings is more consistent with the intent of identifying which physical file contains the definition. Additionally, redundant nullish coalescing operators should be removed as the schema serves as the source of truth for defaults.

Suggested change
const scoped = (file.settings.mcpServers ?? {}) as Record<string, unknown>;
const scoped = file.originalSettings.mcpServers as Record<string, unknown>;
References
  1. Rely on the schema as the single source of truth for configuration defaults, avoiding redundant nullish coalescing operators.


for (const scope of targetScopes) {
const file = settings.forScope(scope);
const scoped = (file.settings.mcpServers ?? {}) as Record<string, unknown>;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

Using file.settings.mcpServers here is a critical issue. The settings object contains resolved environment variables (e.g., actual API keys instead of $MY_KEY). When settings.setValue is called, it updates originalSettings with these resolved values, which are then persisted to disk. This leaks secrets into the settings.json file and breaks environment variable expansion for future use. You must use file.originalSettings.mcpServers to ensure the raw configuration is preserved. Redundant nullish coalescing has been removed per repository rules.

Suggested change
const scoped = (file.settings.mcpServers ?? {}) as Record<string, unknown>;
const scoped = file.originalSettings.mcpServers as Record<string, unknown>;
References
  1. Use a sanitized environment for variable expansion in stdio-based MCP server configurations to prevent extensions from bypassing environment variable redaction.
  2. Rely on the schema as the single source of truth for configuration defaults, avoiding redundant nullish coalescing operators.

Comment on lines +341 to +343
forScope: (scope: SettingScope) => ({
settings: { mcpServers: scopeContents[scope] ?? {} },
}),
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

high

The mock should include originalSettings to align with the implementation changes needed to avoid environment variable leakage. The handleRemove function should operate on the raw settings to preserve placeholders. Redundant nullish coalescing operators have been removed.

Suggested change
forScope: (scope: SettingScope) => ({
settings: { mcpServers: scopeContents[scope] ?? {} },
}),
forScope: (scope: SettingScope) => ({
settings: { mcpServers: scopeContents[scope] },
originalSettings: { mcpServers: scopeContents[scope] },
}),
References
  1. Rely on the schema as the single source of truth for configuration defaults, avoiding redundant nullish coalescing operators.

@gemini-cli gemini-cli Bot added priority/p2 Important but can be addressed in a future release. area/core Issues related to User Interface, OS Support, Core Functionality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! labels May 1, 2026
Bojun-Vvibe added a commit to Bojun-Vvibe/oss-contributions that referenced this pull request May 2, 2026
- BerriAI/litellm#27059 (Grok 4.20 azure_ai metadata) merge-after-nits
- QwenLM/qwen-code#3743 (path-vs-slash-command classifier) merge-after-nits
- QwenLM/qwen-code#3767 (capture actual wire request in OpenAI logger) merge-after-nits
- google-gemini/gemini-cli#26306 (bound retry fallback to prevent infinite loop) merge-after-nits
- google-gemini/gemini-cli#26305 (/mcp remove slash command) merge-after-nits
Copy link
Copy Markdown
Collaborator

@scidomino scidomino left a comment

Choose a reason for hiding this comment

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

Address the gemni comments which seem valid and mark them as resolved when you are done.

@spencer426
Copy link
Copy Markdown
Contributor

Thank you for your interest in contributing to the project! We are closing this PR due to inactivity.

@spencer426 spencer426 closed this May 7, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area/core Issues related to User Interface, OS Support, Core Functionality help wanted We will accept PRs from all issues marked as "help wanted". Thanks for your support! priority/p2 Important but can be addressed in a future release.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants