Installing public GitHub marketplace plugin quandora succeeds then drops to 0 plugins; MCP still loads and OAuth stuck at Error Unauthorized

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

Environment: Cursor 3.14.7, macOS 15.6 (24G84), arm64.
Quit the default browser before starting.

Plugin marketplace used:

MCP endpoint declared by that plugin:
https://mcp.quandora.ai/quant

(No other links in this post.)

Bug:
Installing this public production marketplace plugin fails to remain installed in Cursor Desktop 3.14.7 on macOS.

This is not a packaging issue. The repository follows Cursor’s published plugin layout:

  • .cursor-plugin/marketplace.json
  • plugins/quandora/.cursor-plugin/plugin.json
  • plugins/quandora/mcp.json
  • plugins/quandora/skills/*/SKILL.md

Local Cursor logs show install/enable succeeds, then immediately collapses.

Exact production install sequence (session 20260804T195913):

20:16:22.773 BackendMarketplaceClient: Adding enabled plugin: quandora from 5648d8d3d953d6bed63e2b79c6f74c9d037bed8e at plugins/quandora
20:16:25.640 marketplace listEnabledPlugins completed in 5196.9ms (2 plugins)
20:16:25.640 loadFromMarketplaceSource: Plugin missing from cache, installing: quandora
20:16:25.642 MarketplaceCacheManager: Cloning @5648d8d3
20:16:31.568 loadFromMarketplaceSource completed in 11125.0ms (2 plugins loaded, 0 failures)
20:16:31.568 Plugins reload completed: 4 plugins loaded (0 extension), 0 failures

Seconds later, with no uninstall action:

20:16:31.589 marketplace listEnabledPlugins completed in 0.0ms (0 plugins)

Repeated /add-plugin attempts all show the same pattern:
Adding enabled plugin: quandora
listEnabledPlugins (2 plugins)
loadFromMarketplaceSource (2 plugins loaded, 0 failures)
then immediately listEnabledPlugins (0 plugins)

UI result:

  • Plugins list shows 0
  • No marketplace/plugin icon for Quandora
  • Local registry stays empty: cursor.plugins.installedIds.* →

Despite plugin count = 0, Cursor still creates and connects MCP server plugin-quandora-quandora to the MCP endpoint above.

Then OAuth cannot complete:

19:40:45.388 Successfully connected to streamableHttp server
19:40:45.388 [V2 FSM] connect_success: conn=connecting,auth=unknown → conn=connected,auth=unknown
19:40:45.635 MCP OAuth redirect
19:40:45.635 Client error: Unauthorized Unauthorized
19:40:45.637 tools(authRelated=true, reason=auth): Unauthorized

Local MCP UI shows Error · Unauthorized with only Logout (no Authenticate button). Browser never opens. No token is persisted.

Later Cursor also logs:
[error] Failed to get effective user plugins

Steps to reproduce:

  1. Open a new local Cursor Desktop Agent Chat.
  2. Install the production public plugin via /add-plugin using the GitHub marketplace link above (plugin name: quandora).
  3. In Cursor Plugins logs / output, confirm success markers:
    • BackendMarketplaceClient: Adding enabled plugin: quandora from at plugins/quandora
    • MarketplaceCacheManager: Cloning @…
    • loadFromMarketplaceSource completed … (N plugins loaded, 0 failures)
  4. Immediately after, without uninstalling, check again:
    • marketplace listEnabledPlugins … (0 plugins)
    • Plugins UI shows 0 / no Quandora icon
  5. Repeat step 2 several times. Each attempt briefly re-enables quandora, then drops back to 0.
  6. Even with plugin UI count = 0, open MCP configuration.
    Observe MCP server quandora / plugin-quandora-quandora still exists and connects to the MCP endpoint above.
  7. Open Configure for Local environment of that MCP server.
    Observe: Status Error · Unauthorized; control shown is Logout only; no Authenticate button.
  8. Click Logout.
    Status briefly becomes connecting, then returns to Error · Unauthorized. No browser is launched.

Expected:

  • Production plugin remains installed and visible after step 2
  • MCP shows Needs authentication with an Authenticate control that opens the browser

Actual:

  • Enablement collapses to 0 right after successful install
  • MCP still loads
  • OAuth stuck at Error · Unauthorized with no Authenticate entry point

Steps to Reproduce

see above

Screenshots / Screen Recordings

Operating System

MacOS

Version Information

Version: 3.14.7 (Universal)
VS Code Extension API: 1.128.0
Commit: a758f2241ca99fecf380180b6cbdbbce0f1f42c0
Date: 2026-07-30T06:41:34.009Z
Layout: Agent Window
Build Type: Stable
Release Track: Default
Electron: 40.10.3
Chromium: 144.0.7559.236
Node.js: 24.15.0
V8: 14.4.258.32-electron.0
xterm.js: 6.1.0-beta.291
OS: Darwin arm64 24.6.0

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey, thanks for the detailed report with logs, that really helps. I can see both screenshots: the Configure quandora dialog with status Error · Unauthorized (only Logout, no Authenticate) and the Output panel with repeated Client error: Unauthorized.

This looks like two separate symptoms, and the second one is likely caused by the first:

  1. The plugin drops to 0 after a successful install. The MCP server keeps running as an orphan, which breaks the OAuth state and removes the Authenticate button.

First, let’s clean up the state:

  • Fully quit Cursor with Cmd+Q (not just closing the window).
  • In the MCP config, delete the orphaned server plugin-quandora-quandora (and the marketplace source entry for quandora too, if it’s still there).
  • Start Cursor again and install the plugin via /add-plugin one more time.

If the plugin count drops back to 0 after that, please send the full Output log from that session (panel MCP: plugin-quandora-quandora plus the Plugins log) so we can catch what happens between loadFromMarketplaceSource completed and listEnabledPlugins (0 plugins).

  1. OAuth (Error · Unauthorized, browser doesn’t open). Missing Authenticate and an immediate Unauthorized right after MCP OAuth redirect often means the server isn’t returning a proper OAuth challenge (protected resource metadata or WWW-Authenticate), so Cursor can’t start the flow and show the button. If you’re involved with mcp.quandora.ai, it’s worth checking that the endpoint returns a valid auth challenge on an unauthenticated request. If not, this is probably just a side effect of the orphaned MCP state, so the first priority is making sure the plugin stays installed properly (steps above).

Let me know how it goes after the cleanup and reinstall, and attach a fresh log, then we can figure out what’s causing the enablement to fail.

Thanks for the clarification. I corrected my previous test: I had not actually completed Cursor’s native Add Plugin action at that point. I have now repeated the test correctly on Cursor 3.14.27 after the Cursor-only cleanup.

Plugin installation is now successful and persistent

The native installation path is working in this run. The fresh Plugins log records:

BackendMarketplaceClient: Adding enabled plugin: quandora from ae8fe019d8e0630b671e194dcf3a0e09017db542 at plugins/quandora
MarketplaceCacheManager: Ensuring cloned quandora-2180437 ...
marketplace listEnabledPlugins ... (1 plugins)
loadFromMarketplaceSource ... (1 plugins loaded, 0 failures)

The plugin remains installed after repeated reloads:

Native installedIds: [{"id":"48457065","sources":["user"]}]
Native plugin cache: present
Native marketplace checkout: present
Plugin MCP snapshot: present
Plugin version: 2.1.0
Plugin commit: ae8fe019d8e0630b671e194dcf3a0e09017db542

There are still transient 0 plugins results from separate source-enumeration calls in the same log, but they no longer remove the native installation. Later backend checks repeatedly return one enabled plugin, and the database, cache, marketplace checkout, and MCP snapshot all remain present. Therefore the original plugin-persistence symptom is not reproduced in this corrected run.

OAuth still fails independently after the native install

The remaining issue is reproducible with the native plugin installed. Cursor resolves and connects to the correct production MCP origin:

identifier: plugin-quandora-quandora
origin: https://mcp.quandora.ai
Successfully connected to streamableHttp server

Cursor’s structured log records HTTP 401 and explicitly confirms that www-authenticate is present:

response.status: 401
response.headers.names: ["connection","content-length","content-type","date","server","www-authenticate","x-request-id"]
response.wwwAuthenticateHash: 0935cb5c618e

Cursor then starts the expected loopback listener, but immediately terminates the MCP authorization path without opening the browser or exposing an Authenticate action:

[McpOAuthLoopback] listening on localhost:8787
MCP OAuth redirect
Client error: Unauthorized
authState: unknown
authState: expired

I used Logout and retried twice. Each retry cleared the local OAuth state, reconnected to the same production endpoint, received the same valid 401 challenge, reopened the loopback listener, and ended in the same Unauthorized state. The loopback listener later expired without receiving a callback.

The attached server evidence also shows that the public endpoint returns a Bearer challenge with resource_metadata, and that protected-resource discovery, authorization-server metadata, dynamic client registration, public-client token auth (none), and PKCE S256 are available.

Could you please investigate the remaining Cursor OAuth state-machine behavior: why does a native remote HTTP MCP transition from a recognized 401 challenge and MCP OAuth redirect directly to terminal Unauthorized / authState=expired, instead of opening the authorization URL or exposing Needs authentication?

Fresh, privacy-filtered attachments from the corrected native Add Plugin run in session 20260806T170116:

  • fresh-cursor-plugins-3.14.27.log

  • fresh-mcp-plugin-quandora-3.14.27.log

  • fresh-mcp-workbench-quandora-3.14.27.log

  • fresh-mcp-process-quandora-extract-3.14.27.log

  • fresh-structured-oauth-extract-3.14.27.log

  • fresh-install-state-3.14.27.txt

  • server-oauth-public-evidence.txt

    upload.zip (15.2 KB)

Great diagnostics on 3.14.27, that’s exactly what we needed.

First, the good news about installation. On 3.14.27 the plugin now stays installed reliably. Your summary confirms it: persistence after repeated reloads: yes, cache and checkout are there, installedIds is populated, and loadAllPlugins reports marketplace=2 sources, total=3 plugins, 0 failures. The listEnabledPlugins ... (0 plugins) lines come from the second empty marketplace source that gets checked in the same loop, it’s not an uninstall. So the quandora-2180437 entry is fine, no re-index needed. The “drops to 0” issue is basically gone on this version.

Now OAuth. Your logs rule out a server-side issue. The challenge is valid, and on 3.14.27 Cursor is actually using a loopback redirect. The logs show [McpOAuthLoopback] listening on localhost:8787. After that: the connection comes up, a correct 401 with www-authenticate arrives, loopback gets armed, MCP OAuth redirect is logged, but the browser authorization page never opens (Browser authorization page opened: no). Then the flow immediately ends with Unauthorized from StreamableHTTPClientTransport._authThenStart, and the state transitions unknown -> expired. So it’s not your server or config. The client isn’t opening the auth URL in the browser.

Two more things from the logs that I passed along. The createClient / reload (reason=user_requested) loop repeats, and each iteration re-binds loopback. At the same time listOfferingsForUI hits Unauthorized (Auth error detected in listOfferingsForUI). It looks like repeated reconnects restart the OAuth flow before the redirect has time to open.

This is a known problem area we’re tracking. It affects MCP OAuth on standards-compliant streamable HTTP servers when the browser doesn’t open after the redirect step. I can’t share an ETA yet. Similar threads are here:

One thing to try on your side, just to keep the experiment clean. In your first post you said you fully closed the default browser before starting. Please try /add-plugin and Authenticate again with your default browser already running. The redirect step relies on opening the authorize URL there, and having the browser closed might affect whether the page opens. If nothing changes, that further confirms it’s a client-side OAuth flow issue.

The 3.14.27 logs you shared are exactly what we needed, no need to send anything else. I’ve passed them to the team and I’ll update the thread once we have news.