MCP OAuth failures trigger repeated provider reinitialization / missing backoff

Where does the bug appear (feature/product)?

Cursor IDE

Describe the Bug

I ran into an issue where failed MCP OAuth/auth attempts caused a lot of repeated MCP reinitialization and extension-host activity.

To be clear: my actual infinite reload loop was caused by a third-party extension, not Cursor. That part is solved. But while debugging it, I noticed that Cursor seemed to keep retrying failed Cloudflare MCP OAuth/auth flows very aggressively.

The Cloudflare MCP plugin had several servers configured. One worked, but the others were failing with 401 invalid_token or fetch timeouts. Each failed attempt seemed to trigger mcp_providers_changed, which then caused MCP to reinitialize again. This created a lot of log noise and made the original issue much harder to debug.

The main problem is not that OAuth failed. That can happen. The problem is that Cursor appeared to keep treating the same failed auth state as something that required repeated provider changes/reinitialization instead of backing off and showing a stable “authentication required” state.

Steps to Reproduce

How to reproduce:

  1. Enable the Cloudflare MCP plugin in Cursor.
  2. Configure Cloudflare MCP servers that require OAuth, for example:
  • cloudflare-bindings
  • cloudflare-builds
  • cloudflare-observability
  1. Do not complete the OAuth flow, or use an expired/invalid token.
  2. Restart Cursor.
  3. Check the logs.

Now you should see repeated auth/fetch failures like:

  • 401 invalid_token
  • fetch failed
  • timeout errors

In my case, these failures were followed by repeated mcp_providers_changed events and MCP reinitialization behavior.

Expected Behavior

If an MCP server repeatedly fails because OAuth is missing, expired, invalid, or times out, Cursor should stop retrying aggressively.

I would expect Cursor to:

  • apply exponential backoff after repeated OAuth failures
  • avoid firing mcp_providers_changed when the MCP config did not actually change
  • avoid reinitializing unrelated extension hosts because of the same failed auth state
  • show a clear “authentication required” or “OAuth failed” state in the MCP settings UI
  • provide a manual “Retry OAuth” button instead of repeatedly retrying in the background
  • avoid creating lots of stale OAuth attempt files

Operating System

MacOS

Version Information

Cursor IDE v3.10.20 stable

Does this stop you from using Cursor

No - Cursor works, but with this issue

Hey @devinoldenburg,

A couple of these already work the way you’re asking:

  • Backoff on reconnects already exists. When an MCP server keeps failing to connect, Cursor backs off progressively rather than retrying at a fixed rate.
  • A failed or expired OAuth token isn’t retried forever. A 401 invalid_token is treated as an auth failure, so the server moves into an “authentication required” state instead of looping on that credential. The aggressive token-refresh retry you may have seen referenced elsewhere was a separate bug that’s already fixed in the version you’re on (3.10.20).

Where you’ve got a real point is the repeated reinitialization and log noise. When a plugin re-registers its MCP servers on each failed attempt (which the Cloudflare plugin appears to do here), Cursor currently re-runs MCP initialization every time instead of ignoring a no-op change. That’s the part worth hardening, and I’ve captured your asks around it - debouncing those reinitializations, a clearer per-server auth state, a manual retry, and not leaving stale auth-attempt files behind.

To quiet it down now:

  1. Complete the OAuth flow for the failing Cloudflare servers, or disable/remove them in Customize so the plugin stops re-registering.
  2. To re-trigger auth on a stuck server, toggle it off and back on in Customize.
  3. You can watch exactly what’s happening in the MCP logs: Cmd+Shift+U, then pick “MCP Logs” from the dropdown (docs).

We’ll keep tracking this thread to gauge interest in the hardening side, which helps us prioritize. Let me know if the noise sticks around once the failing servers are disabled.

Thanks, Mohit, that makes sense.

Good to know it already works that way.

I’m just going to disable the Cloudflare Plugin/MCP for now, as I don’t really need it. I also remember the Cloudflare Plugin/MCP not completing the OAuth flow regularly, which probably was why it was not set up, but this is a separate issue in itself. If this issue occurs again, I will create a post here or reply again with details.