[BUG] Disabled marketplace plugins (nimble/wix/serena) still spawn MCP servers and open browser tabs without consent
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
- Install
nimble@claude-plugins-officialfrom the official marketplace. - Do NOT set
NIMBLE_API_KEY(most users won't have one out of the box). - Open Claude Code → MCP server starts →
mcp-remoteopens an OAuth tab in the default browser pointing athttps://api.nimbleway.com/authorize?.... - Close Claude Code, close the tab.
- Edit
~/.claude/settings.json→ set"nimble@claude-plugins-official": falseunderenabledPlugins. - 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.jsonl — three 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:
- Remove plugin entries entirely from
~/.claude/settings.json. - Remove plugin entries from
~/.claude/plugins/installed_plugins.json. - Add to
~/.claude/plugins/blocklist.json. rm -rf ~/.claude/plugins/cache/claude-plugins-official/{nimble,wix,serena}.rm -rf ~/.npm/_npx/<hashes>(where mcp-remote lived).rm -rf ~/.mcp-auth/.rm -rf ~/.serena/and the Serena uv archive.- Kill running PIDs.
- Delete
~/Library/Caches/claude-cli-nodejs/*/mcp-logs-plugin-{nimble,wix,serena}-*.
That's 9 manual steps. Toggling enabled: false should be enough.
Asks
- Honor
enabledPlugins: falsestrictly — never spawn the MCP server for a plugin marked false. - Add a single "Uninstall + clean" UI button that does steps 1–4 atomically.
- Audit
mcp-remote-based marketplace plugins. Warn on install: "This plugin opens a browser tab for OAuth each session until you authenticate." - Patch the official
serenaplugin to defaultweb_dashboard: false.
10 Comments
Found 3 possible duplicate issues:
This issue will be automatically closed as a duplicate in 3 days.
🤖 Generated with Claude Code
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: falsebeing silently ignored for hook registration. This issue (#58806) extends the sameenabledPlugins: falsenon-honor to the MCP-server-spawn path plus themcp-remoteauto-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: falseruntime gate, so they are adjacent but not duplicates.Two operator-side mitigations while the gate is fixed:
mcp-remotefrom auto-opening the OAuth URL. SetMCP_REMOTE_NO_OPEN=1in the environment that launches Claude Code (your shell rc file for the launching shell, or your launcher script).mcp-remotethen prints the URL to stderr instead of callingopen. This neutralizes the browser-tab pollution even when the underlying spawn still fires.mcp__nimble*,mcp__wix*,mcp__serena*. A short bash hook withexit 2matching 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.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.jsonstate.The actual source
For me, that was:
…and its contents were the smoking gun:
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:~/.claude/settings.json→enabledPlugins.nimble@…: false→ bypassed~/.claude/plugins/installed_plugins.json→ bypassed~/.claude/plugins/blocklist.json→ bypassedrm -rf ~/.claude/plugins/cache/claude-plugins-official/nimble→ bypassedfalse) → bypassedThe 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:
With
[…] Browser opened automatically.lines and successfulmcp-remoteinvocations againstmcp.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)
Why this is worse than a normal config bug
claude-codeshows the plugin as "uninstalled" while still spawning it.Asks (updating from original report)
claude-code mcp listshould reflect reality: if a plugin's.mcp.jsonis being spawned from anywhere on disk, list it (and show its source path).claude-code mcp purge <plugin>that nukes every install location.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
~/.claude/backups/nimble-final-2026-05-14/.mcp.jsonand full directory tree are in that backup folder@/tmp/cc-reaper-comment-58806.md
+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:
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."disabledPlugins": ["nimble", "nimble-inline"]in~/.claude/settings.json→ no effect."mcpServers": { "nimble": { "disabled": true } }→ no effect.~/.claude/plugins/data/nimble-inline/config.jsonwith{"enabled": false, "skipAuth": true}→ no effect.~/.claude/plugins/marketplaces/.../external_plugins/so there's nothing to delete — it's bundled as an inline plugin inside theclaude.exebinary itself (grep nimbleon the binary matches). For an end-user there is literally no uninstall path./etc/hosts. And even that has a gotcha: the obvious127.0.0.1 online.nimbleway.comline 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:
mcp-remotefrom 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./config), not a JSON field that doesn't actually work.nimblewants 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.
Update 2: deletion alone is insufficient — cloud sync re-installs the plugin at the same path. Only
chflags uchgdefense 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
| Time | State | Action |
|---|---|---|
| Day 1, 23:25 | Directory exists,
.mcp.jsoncontains 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:
extensions-installations.jsonhas zero nimble references; that file is for.mcpb-style extensions)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:
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.jsonyields{}, so:mcp-remoteprocess is spawnedmcp-logs-plugin-nimble-*log file is createdVerified 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
chflags uchgunnecessary by gating spawn on a user preference that survives cloud sync.mcp-remoteand auto-opening OAuth — this whole class of plugin is hostile by default.Artifacts
~/.claude/backups/nimble-final-2026-05-14/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.
@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 uchgworks 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.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.jsonyou pulled out of the RPM plugin path:That was the old shape of our config. The
mcp-remotestdio bridge + bearer-header pattern is what should be triggeringBrowser opened automatically.on every spawn when the API key isn't set.We migrated to Claude Code's native HTTP transport:
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 · Nimbleon 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
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.