Custom cloud MCP re-prompts for Microsoft login on every connect; the refresh token is never stored

Where does the bug appear (feature/product)?

Cloud Agent (GitHub, Slack, Web, Linear)

Describe the Bug

Describe the Bug
A custom HTTP MCP that uses a static Microsoft Entra OAuth client (client id, client secret, and the scopes the resource advertises, including offline_access) is added as a personal cloud MCP. Every connect opens an interactive Microsoft login. Entra issues a valid access token, and the resource server then returns its tools. A few minutes later, while that access token is still valid (about 60–90 minutes), the next connect starts a new interactive login. The IdP shows authorization-code sign-ins and no refresh-token grant.
The same OAuth client, added as a desktop MCP, stores the refresh token and refreshes it silently. First-party plugin MCPs stay signed in. The cloud catalog can show the custom server as “connected”; that status is not a stored token.

Steps to Reproduce

Steps to Reproduce

  1. Register an Entra app as the OAuth client. Allow the cloud redirect Cursor Agent - Turn your ideas into code and the delegated scopes openid, profile, offline_access, plus the resource access scope.
  2. On cursor.com/agents, add a custom HTTP MCP with that URL, CLIENT_ID, CLIENT_SECRET, and those scopes.
  3. Connect and complete the Microsoft login. Call one read-only tool. It succeeds.
  4. A few minutes later, connect again, or start another cloud agent that uses the server.

Expected Behavior

Expected Behavior
Cursor stores the refresh token for that user and server URL and uses it on the next cloud connect, the way desktop MCP and first-party plugins already do.

Operating System

MacOS

Version Information

IDE:
Version: 3.27.14
VSCode Version: 1.128.0
Commit: 69b724ebc67ec522c1b5d287a5025f7a7e81be90

For AI issues: which model did you use?

Not an agent-turn failure. No Request ID and no cloud-agent run id (bc-…). The OAuth connect itself drops the token before a later agent turn.

Additional Information

Ruled out: missing admin consent, wrong scopes, the user missing an app role (a successful connect listed the server’s tools), and access-token expiry (the re-prompts were minutes apart).

Does this stop you from using Cursor

Sometimes - I can sometimes use Cursor

Hi @Haris_Grizovic,

The refresh token is actually being stored. The problem is where the cloud side sends it. Your server advertises its OAuth metadata only through the resource_metadata link in its 401 response. Sign-in follows that link, but the cloud refresh doesn’t: it checks the standard .well-known locations, finds nothing, and the refresh then fails against the MCP host itself. So once the access token expires, the next connect needs a full login again. I’ve passed this to the team.

In the meantime, if your gateway can serve the same protected-resource document at the standard location (/.well-known/oauth-protected-resource followed by your MCP path, on the same host), the refresh should find your Entra tenant and work.

Also, editing the server’s client ID, secret or scopes, or clicking Connect again, always starts a fresh sign-in, so that accounts for re-prompts that come only minutes apart.

Hi @Colin ,
thx for the fast reply. I will add the fix temporarily and looking forward for the fix from cursor’s side.