[BUG] Disabled marketplace plugins (nimble/wix/serena) still spawn MCP servers and open browser tabs without consent

Status Fixed / completed
Maintainer reply None cached
Activity 10 comments · opened May 13, 2026 · closed May 17, 2026

Summary

nimble@claude-plugins-official (and to a lesser extent wix@claude-plugins-official, serena@claude-plugins-official) keeps spawning its MCP server and opening a browser tab without consent every Claude Code session, even after I set enabledPlugins["nimble@claude-plugins-official"]: false in ~/.claude/settings.json. After a few weeks the user's browser is polluted with dozens of "Login - Nimble" tabs.

Environment

  • OS: macOS 26 (Apple Silicon)
  • Default browser: ChatGPT Atlas
  • Plugin versions: nimble@0.6.1, wix@1.0.0, serena@61c0597779bd

Reproduction

  1. Install nimble@claude-plugins-official from the official marketplace.
  2. Do NOT set NIMBLE_API_KEY (most users won't have one out of the box).
  3. Open Claude Code → MCP server starts → mcp-remote opens an OAuth tab in the default browser pointing at https://api.nimbleway.com/authorize?....
  4. Close Claude Code, close the tab.
  5. Edit ~/.claude/settings.json → set "nimble@claude-plugins-official": false under enabledPlugins.
  6. Restart Claude Code.

Expected: plugin does not load; no MCP server starts; no browser tab opens.
Actual: plugin still loads; mcp-remote launches; new browser tab opens for OAuth. Repeats every session.

Evidence (smoking gun)

From ~/Library/Caches/claude-cli-nodejs/.../mcp-logs-plugin-nimble-nimble-mcp-server/2026-05-13T19-46-16-563Z.jsonlthree days after disabling the plugin in settings.json:

{"debug":"Starting connection with timeout of 30000ms","timestamp":"2026-05-13T19:46:16.857Z","cwd":"~/Desktop"}
{"error":"Server stderr: [37330] Warning: Environment variable 'NIMBLE_API_KEY' not found for header 'Authorization'.
[37330] Discovering OAuth server configuration...
[37330] Discovered authorization server: https://api.nimbleway.com/
[37330] Connecting to remote server: https://mcp.nimbleway.com/mcp
[37330] Please authorize this client by visiting: https://api.nimbleway.com/authorize?...
[37330] Browser opened automatically.
[37330] Authentication required. Initializing auth...
[37330] Another instance is handling authentication on port 10227 (pid: 36853)
[37330] Waiting for authentication from the server on port 10227..."}

[37330] Browser opened automatically. is the line that pops a new tab every session.

Root cause analysis (best guess)

Bug 1: enabledPlugins: false is not fully honored

Despite "nimble@claude-plugins-official": false, the plugin's .mcp.json server is still spawned. installed_plugins.json keeps listing the plugin regardless of enabled state, and Claude Code appears to read the plugin's .mcp.json from the install path and start the MCP server before honoring the enabledPlugins check.

Suggested fix: gate the spawn of plugin-provided MCP servers behind enabledPlugins[pluginId] !== false.

Bug 2: mcp-remote auto-opens browser tabs without user consent

mcp-remote (used by nimble and wix) calls open on the OAuth URL automatically — Browser opened automatically. — with no opt-out. Combined with bug 1, a disabled plugin still pollutes the browser every session.

Suggested fix: Claude Code should never let mcp-remote run for disabled plugins. Upstream, an env var like MCP_REMOTE_NO_OPEN=1 should make it print the URL instead of opening it.

Bug 3: Serena web_dashboard defaults to opening a tab

serena@claude-plugins-official defaults to web_dashboard: true and web_dashboard_open_on_launch: true in ~/.serena/serena_config.yml. Every Claude Code session that loads Serena pops a http://localhost:24282/dashboard/ tab. This is upstream Serena behavior, but the Claude Code plugin packaging should ship a serena_config.yml with these set to false since users running Serena as an MCP server inside Claude Code don't need a dashboard.

Manual escape

Setting enabledPlugins.<plugin>: false is not sufficient. I had to do all of the following:

  1. Remove plugin entries entirely from ~/.claude/settings.json.
  2. Remove plugin entries from ~/.claude/plugins/installed_plugins.json.
  3. Add to ~/.claude/plugins/blocklist.json.
  4. rm -rf ~/.claude/plugins/cache/claude-plugins-official/{nimble,wix,serena}.
  5. rm -rf ~/.npm/_npx/<hashes> (where mcp-remote lived).
  6. rm -rf ~/.mcp-auth/.
  7. rm -rf ~/.serena/ and the Serena uv archive.
  8. Kill running PIDs.
  9. Delete ~/Library/Caches/claude-cli-nodejs/*/mcp-logs-plugin-{nimble,wix,serena}-*.

That's 9 manual steps. Toggling enabled: false should be enough.

Asks

  1. Honor enabledPlugins: false strictly — never spawn the MCP server for a plugin marked false.
  2. Add a single "Uninstall + clean" UI button that does steps 1–4 atomically.
  3. Audit mcp-remote-based marketplace plugins. Warn on install: "This plugin opens a browser tab for OAuth each session until you authenticate."
  4. Patch the official serena plugin to default web_dashboard: false.

View original on GitHub ↗

10 Comments

github-actions[bot] · 3 months ago

Found 3 possible duplicate issues:

  1. https://github.com/anthropics/claude-code/issues/28554
  2. https://github.com/anthropics/claude-code/issues/56032
  3. https://github.com/anthropics/claude-code/issues/58520

This issue will be automatically closed as a duplicate in 3 days.

  • If your issue is a duplicate, please close it and 👍 the existing issue instead
  • To prevent auto-closure, add a comment or 👎 this comment

🤖 Generated with Claude Code

yurukusa · 3 months ago

The triage bot flagged this as a possible duplicate of #28554, #56032, #58520 — worth flagging that the structural shape differs enough across those four that auto-closure may misclassify here.

#58520 is the closest: it documents enabledPlugins: false being silently ignored for hook registration. This issue (#58806) extends the same enabledPlugins: false non-honor to the MCP-server-spawn path plus the mcp-remote auto-browser-open chain, which is a distinct downstream consequence on the same underlying setting-intent bypass. Closing this as a duplicate of #58520 would correctly fix the root cause but lose the MCP-spawn + browser-open evidence chain that makes the user-visible severity concrete (dozens of OAuth tabs accumulated over weeks).

#28554 and #56032 are about plugin removal / cleanup rather than the enabledPlugins: false runtime gate, so they are adjacent but not duplicates.

Two operator-side mitigations while the gate is fixed:

  1. Block mcp-remote from auto-opening the OAuth URL. Set MCP_REMOTE_NO_OPEN=1 in the environment that launches Claude Code (your shell rc file for the launching shell, or your launcher script). mcp-remote then prints the URL to stderr instead of calling open. This neutralizes the browser-tab pollution even when the underlying spawn still fires.
  1. Block the spawn at the OS process layer with a PreToolUse hook on mcp__nimble*, mcp__wix*, mcp__serena*. A short bash hook with exit 2 matching those tool prefixes will refuse the MCP tool calls; combined with mitigation 1, it surfaces the gate violation without the side effects. This is a workaround for the runtime check that should live inside Claude Code itself.

Neither mitigation is a real fix — the proper fix is your Ask 1 (gate MCP-server spawn behind enabledPlugins[pluginId] !== false). Posting these in case the issue stays open beyond the triage window and someone hits the same wall.

nazmiefearmutcu · 3 months ago

Update: the real culprit — Claude Desktop's RPM plugin path bypasses every Claude Code config

The original report was incomplete. After my 9-step manual cleanup, Nimble still spawned its MCP server and opened OAuth tabs in the browser on every Claude Code session. Three more sessions of investigation revealed a separate, hidden plugin install location that Claude Code reads from regardless of any enabledPlugins / installed_plugins.json / blocklist.json state.

The actual source

~/Library/Application Support/Claude/local-agent-mode-sessions/
  <session-uuid-1>/<session-uuid-2>/
    rpm/plugin_<ULID>/.mcp.json

For me, that was:

~/Library/Application Support/Claude/local-agent-mode-sessions/920a3f8b-…/7c07fb19-…/rpm/plugin_01BB1HUyHKrddLdPpkTMBUvE/.mcp.json

…and its contents were the smoking gun:

{
  "nimble-mcp-server": {
    "command": "npx",
    "args": ["-y", "mcp-remote@latest", "https://mcp.nimbleway.com/mcp",
             "--header", "Authorization:Bearer ${NIMBLE_API_KEY}"]
  }
}

This is an RPM-packaged plugin belonging to Claude Desktop's local-agent-mode-sessions, but Claude Code (CLI) also reads from this directory and spawns the MCP server from it. So:

  1. ~/.claude/settings.jsonenabledPlugins.nimble@…: false → bypassed
  2. Plugin removed from ~/.claude/plugins/installed_plugins.json → bypassed
  3. Added to ~/.claude/plugins/blocklist.json → bypassed
  4. rm -rf ~/.claude/plugins/cache/claude-plugins-official/nimble → bypassed
  5. Settings entry removed entirely (not just false) → bypassed

The plugin kept spawning because the spawn command lived in the Claude Desktop RPM path, which none of the Claude Code config knobs control.

Evidence: new MCP log lines kept appearing

Even with all 9 cleanup steps done in Claude Code's own directories, every new Claude Code session produced fresh entries in:

~/Library/Caches/claude-cli-nodejs/-Users-<user>-Desktop/mcp-logs-plugin-nimble-nimble-mcp-server/

With […] Browser opened automatically. lines and successful mcp-remote invocations against mcp.nimbleway.com. This was happening with zero references to nimble in any user-facing Claude Code config file.

The actual fix (had to do this manually)

# 1. Find and delete the Claude Desktop RPM plugin
find "~/Library/Application Support/Claude/local-agent-mode-sessions" \
  -name ".mcp.json" -exec grep -l nimble {} \; \
  | xargs -I {} dirname {} \
  | xargs rm -rf

# 2. Clean inline metadata in BOTH locations
rm -rf ~/.claude/plugins/data/nimble-inline
rm -rf "~/Library/Application Support/Claude/local-agent-mode-sessions/<sess>/<sess>/local_<id>/.claude/plugins/data/nimble-inline"

# 3. Clean cached MCP logs trap
rm -rf ~/Library/Caches/claude-cli-nodejs/*/mcp-logs-plugin-nimble-*

Why this is worse than a normal config bug

  • Hidden by design: the path is buried 5 directories deep under random UUIDs/ULIDs. Users have no way to discover this.
  • Cross-product state leakage: Claude Desktop's plugin installations silently affect Claude Code's MCP spawning. There's no documented relationship between the two products' plugin systems.
  • No UI surface: claude-code shows the plugin as "uninstalled" while still spawning it.
  • Survives reinstalls: as long as Claude Desktop's session directory exists, the plugin keeps running.
  • In my case: this caused Atlas browser to accumulate 22 nimble OAuth tabs over multiple sessions that I had to manually archive-wipe.

Asks (updating from original report)

  1. Document the RPM plugin path and how it interacts with Claude Code.
  2. Unify plugin state between Claude Desktop and Claude Code, or expose a single uninstall command that touches both.
  3. claude-code mcp list should reflect reality: if a plugin's .mcp.json is being spawned from anywhere on disk, list it (and show its source path).
  4. Add claude-code mcp purge <plugin> that nukes every install location.
  5. For the specific issue here: gate mcp-remote-style plugins (or any plugin whose spawn command shells out to a browser-opening tool) behind explicit per-session opt-in, not auto-spawn at session start.

Artifacts for whoever picks this up

  • Original logs preserved at ~/.claude/backups/nimble-final-2026-05-14/
  • The deleted plugin's .mcp.json and full directory tree are in that backup folder
  • 22 Atlas tab files containing nimble URLs (proof of cumulative spam) also backed up there
theQuert · 3 months ago

@/tmp/cc-reaper-comment-58806.md

danpa5150-collab · 3 months ago

+1 — confirming this on macOS 26 (Apple Silicon) with Chrome as the default browser. The nimble OAuth tab opens every Claude Code startup and after most sessions, exactly as described in the OP.

Additional context from a non-technical end-user perspective:

I work with a Japanese small-business owner (non-engineer) who uses Claude Code for everyday tasks (notion connector, calendar, etc.). For users like them this bug is more than annoying — it actively undermines trust in Claude Code:

  1. They have no NIMBLE_API_KEY, no Nimble account, and have never heard of Nimble. A browser tab popping up that says "Login · Nimble" on a black racing-car background looks like a phishing attempt, not a legitimate flow. They asked me to investigate because they thought their machine was compromised.
  1. The "official" disabling paths all silently fail. We tried every plausible approach:
  • "disabledPlugins": ["nimble", "nimble-inline"] in ~/.claude/settings.json → no effect.
  • "mcpServers": { "nimble": { "disabled": true } } → no effect.
  • Creating ~/.claude/plugins/data/nimble-inline/config.json with {"enabled": false, "skipAuth": true} → no effect.
  • The plugin doesn't appear under ~/.claude/plugins/marketplaces/.../external_plugins/ so there's nothing to delete — it's bundled as an inline plugin inside the claude.exe binary itself (grep nimble on the binary matches). For an end-user there is literally no uninstall path.
  1. The only workaround that survives a reboot is editing /etc/hosts. And even that has a gotcha: the obvious 127.0.0.1 online.nimbleway.com line is silently bypassed because macOS now resolves the domain via IPv6 first (2606:4700:10::...). The full incantation that actually works is:

``
127.0.0.1 online.nimbleway.com api.nimbleway.com auth.nimbleway.com
::1 online.nimbleway.com api.nimbleway.com auth.nimbleway.com
``

Followed by sudo dscacheutil -flushcache && sudo killall -HUP mDNSResponder. Asking a non-engineer to do this is unreasonable.

Asks from a non-technical-user POV:

  • 🚨 Most important: stop any MCP server / mcp-remote from launching for an inline plugin that the user has never explicitly opted into. The current behavior — opening a Nimble OAuth tab for a user who has no account — is a dark pattern and (given how it looks) a real phishing-confusion risk.
  • Ship a one-click "Disable bundled plugins I don't use" toggle in a visible place (status line / /config), not a JSON field that doesn't actually work.
  • At minimum, never auto-open a browser tab without a one-line CLI prompt first: "Plugin nimble wants to open a browser tab to authenticate. [y/N]".

Happy to provide additional logs from the affected machine if useful. Thanks for the great work on Claude Code — this is just the one rough edge that's actively eroding trust with non-technical users.

nazmiefearmutcu · 3 months ago

Update 2: deletion alone is insufficient — cloud sync re-installs the plugin at the same path. Only chflags uchg defense holds.

After the previous comment, I deleted the offending plugin folder (rpm/plugin_01BB1HUyHKrddLdPpkTMBUvE/) along with everything else. The spam stopped for ~2 days. Then the exact same plugin folder reappeared at the exact same path with the exact same ULID and resumed opening browser tabs.

Reproduction

~/Library/Application Support/Claude/local-agent-mode-sessions/<user-uuid>/<session-uuid>/rpm/plugin_01BB1HUyHKrddLdPpkTMBUvE/

| Time | State | Action |
|---|---|---|
| Day 1, 23:25 | Directory exists, .mcp.json contains nimble spawn command | rm -rf <dir> |
| Day 1, 23:40 | Directory gone | Manually confirmed |
| Day 4, 10:11 | Directory back, same ULID, same .mcp.json | Browser tabs started spawning again |

This proves the plugin is part of Anthropic's cloud-synced "skills plugin" system (registry visible under ~/Library/Application Support/Claude/local-agent-mode-sessions/skills-plugin/<user-uuid>/). On Claude Desktop launch, the sync logic refetches the plugin definition from the user's account state and re-materializes the local files.

The user has no UI path to remove it

The user checked all visible Settings panels:

  • Settings → Connectors — Nimble not listed (Connectors are MCP servers added manually by the user)
  • Settings → Extensions — Nimble not listed (extensions-installations.json has zero nimble references; that file is for .mcpb-style extensions)
  • claude.ai → Settings — no "Plugins" / "Skills" panel surfaces this plugin either

The plugin's manifest declares 13 skills under category "data" and an MCP server, but nothing in the UI exposes it for removal. Yet the plugin remains "installed" at the account level, and the cloud sync keeps materializing it locally.

The only fix that holds: file-level immutable flag

After deletion repeatedly failed, the workaround that finally killed the spam:

PLUGIN_DIR="~/Library/Application Support/Claude/local-agent-mode-sessions/<user-uuid>/<session-uuid>/rpm/plugin_01BB1HUyHKrddLdPpkTMBUvE"

# Replace spawn command with empty MCP config
echo '{}' > "$PLUGIN_DIR/.mcp.json"
echo '{}' > "$PLUGIN_DIR/mcp.json"

# macOS user-immutable flag — even root sync logic gets EPERM
chflags uchg "$PLUGIN_DIR/.mcp.json"
chflags uchg "$PLUGIN_DIR/mcp.json"

# Also lock alternate filenames the sync logic might try
for fname in config.json mcp-config.json server.json claude_mcp.json; do
  echo '{}' > "$PLUGIN_DIR/$fname"
  chflags uchg "$PLUGIN_DIR/$fname"
done

After this, restarted Claude Desktop. The plugin does still appear in Claude Code's "still connecting" plugin list (the registry sync runs fine), but reading .mcp.json yields {}, so:

  • No MCP server is registered
  • No mcp-remote process is spawned
  • No browser tab is opened
  • No mcp-logs-plugin-nimble-* log file is created

Verified across a fresh Claude Code restart on 2026-05-16: zero new nimble activity.

What this reveals about the bug

The system is designed so cloud-installed plugins cannot be uninstalled without UI consent that doesn't exist for this category. The deletion → cloud-resync loop is a hard cycle. The only escape is filesystem-level subterfuge (immutable flag), which is exactly the wrong shape of fix for a non-power-user to discover.

Additional asks

  1. Surface "skills plugins" in the UI under a "Plugins" or "Skills" panel so users can disconnect them.
  2. Make chflags uchg unnecessary by gating spawn on a user preference that survives cloud sync.
  3. Tombstone uninstalled plugins so a user's removal sticks across sync rather than being treated as ephemeral local state.
  4. Make the cloud sync respect EPERM gracefully — if a write to a plugin file fails, log it once and don't keep retrying every session.
  5. Audit which marketplace plugins ship with mcp-remote and auto-opening OAuth — this whole class of plugin is hostile by default.

Artifacts

  • Local defense backup: ~/.claude/backups/nimble-final-2026-05-14/
  • 5 sessions of debugging across 4 days
  • The user gave up on the plugin entirely after the third forced-reinstall
m13v · 3 months ago

the seam that breaks here isn't enabledPlugins itself, it's that .mcp.json discovery runs at a different layer than the enable check. spawn decision sits in the manifest-load loop, the enable check sits in tool routing, so the MCP server boots before anyone asks if the plugin should run. mcp-remote compounds it because the OAuth handshake assumes user-present-and-watching, which a disabled plugin definitionally isn't. fix lives at manifest-load gating on enabledPlugins, not at tool-call dispatch. otherwise any plugin's auth handshake becomes a permission-model bypass by accident, which is the real shape of this bug across MCP-aware desktop apps.

yurukusa · 3 months ago

@nazmiefearmutcu, the cloud-sync replay is the part that converts this from "Claude Code didn't honor enabledPlugins" into "no application-layer defense holds." Deletion, dotfile blocklist, enabledPlugins=false, and the original 9-step manual cleanup all fail at the same point: a sync agent above the application layer rewrites the path back, so any state Claude Code itself stores is overwritten faster than enforcement can act. chflags uchg works because it sits one layer below the sync agent, not because it's a stricter Claude-side toggle.

@m13v, your manifest-load-vs-tool-dispatch framing is the right seam. The enable check runs after the spawn decision has already been made, which means the configuration represents an intent that the codepath structurally can't honor. That's the difference between "config not respected" (a bug at one layer) and "config not consultable" (the codepath that would consult it executes too late). The fix has to land at manifest-load gating; anywhere downstream is too late by construction.

For downstream readers: this thread now documents four failed application-layer defenses (delete, blocklist, enabledPlugins, OS-config) plus one working OS-layer defense (uchg flag). The cloud-sync replay shape is why nothing softer holds. The manifest-load gating point is where a real fix has to land.

@danpa5150-collab's point about non-technical end-users is worth keeping visible. The defense currently requires Terminal access plus knowledge of chflags, which is a much higher bar than the "click the toggle in settings" the original UI implies.

ilchemla · 3 months ago

Thanks for the forensic depth here. The RPM-plugin-path trace in your Update 1 and the cloud-sync-replay finding in Update 2 are really useful. Posting from the Nimble side to share what we fixed.

What was on our side

The .mcp.json you pulled out of the RPM plugin path:

{
  "nimble-mcp-server": {
    "command": "npx",
    "args": ["-y", "mcp-remote@latest", "https://mcp.nimbleway.com/mcp",
             "--header", "Authorization:Bearer ${NIMBLE_API_KEY}"]
  }
}

That was the old shape of our config. The mcp-remote stdio bridge + bearer-header pattern is what should be triggering Browser opened automatically. on every spawn when the API key isn't set.

We migrated to Claude Code's native HTTP transport:

{
  "nimble": {
    "type": "http",
    "url": "https://mcp.nimbleway.com/mcp"
  }
}

No mcp-remote, no auto-open, no bearer-via-env-var path. Claude Code should handle the OAuth natively now and cache the token like the other plugins you mentioned.

Anthropic merged the marketplace SHA bump yesterday in anthropics/claude-plugins-official#1914. More detail on the migration in #1774.

On the non-technical-user impact

@danpa5150-collab, your point about Login · Nimble on a black background reading as a phishing attempt really landed. I'm sorry that experience happened on our surface. The new config should remove the unprompted browser-open at the source. For users whose old config is still materialized locally via the RPM path, the workarounds in this thread remain the only escape until the new version propagates.

If anyone here still sees Nimble browser tabs after the new SHA reaches your install, please ping me. Happy to dig in case by case.

— Ilan, Nimble

github-actions[bot] · 1 month ago

This issue has been automatically locked since it was closed and has not had any activity for 7 days. If you're experiencing a similar issue, please file a new issue and reference this one if it's relevant.