TrueFoundry is recognized in the 2025 Gartner® Market Guide for AI Gateways! Read the full report

No items found.

MCP Authentication in Cursor: OAuth, API Keys, and Secure Configuration (2026 Guide)

March 3, 2026
|
9:30
min read
SHARE

MCP authentication dictates how Cursor's AI agent proves who it is when reaching out to external tools and services. Skip it, and every MCP server either runs wide open or relies on a static token sitting in plaintext. Get it right, and the agent connects to GitHub, Slack, or your internal APIs with credentials that are scoped, rotatable, and auditable.

The MCP specification landed standardized OAuth 2.1 authorization in its March 2025 revision. June 2025 followed up by formally splitting MCP servers from authorization servers and requiring Protected Resource Metadata (RFC 9728). Then the November 2025 revision brought in Client ID Metadata Documents (CIMD) as the go-to registration method and made PKCE non-negotiable for every client. Cursor shipped OAuth support in v1.0 back in June 2025, putting it among the first IDEs to offer browser-based MCP authentication.

Two things make understanding Cursor's auth model worth your time: it governs what your agent can touch, and it defines the blast radius when something breaks.

How MCP Authentication Works

MCP authentication lives at the transport layer. What mechanism you get depends on whether the server runs locally over stdio or remotely over Streamable HTTP.

Stdio servers handle authentication outside the MCP protocol entirely. The server process inherits environment variables from Cursor — usually API keys or tokens — and uses those to authenticate against upstream services like the GitHub API, a database, or a cloud provider. The MCP specification is explicit here: stdio implementations should pull credentials from the environment, not from an OAuth flow.

Remote servers on Streamable HTTP follow a different path. The MCP specification recommends OAuth 2.1, and the handshake involves three parties:

Cursor plays the role of OAuth client. The MCP server functions as an OAuth 2.1 resource server — it validates tokens but never issues them. An authorization server (Okta, Auth0, Azure AD, or one the MCP server operator runs) takes care of user authentication and hands out tokens.

Here's the actual sequence. Cursor fires a request at the MCP server with no token attached. The server comes back with 401 Unauthorized and a WWW-Authenticate header that points to its Protected Resource Metadata document. Cursor grabs that document, figures out which authorization server to talk to, registers itself (through Dynamic Client Registration or CIMD), and drops you into a browser window for login.

Once you authorize, the authorization server issues an access token. Cursor stashes that token and attaches it to every subsequent request.

PKCE (Proof Key for Code Exchange) runs through the entire flow. Cursor generates a code_verifier and code_challenge pair before kicking things off. Even if an attacker manages to intercept the authorization code mid-flight, they can't swap it for a token without the original verifier.

Authentication Methods in Cursor

Cursor gives you three ways to authenticate MCP servers. Each one maps to a different deployment scenario.

Method Transport How It Works When to Use
Environment variables stdio API keys fed through the env field in mcp.json. The server process reads them on startup. Local servers, single-developer setups, tokens you rotate yourself.
Static headers Streamable HTTP Bearer tokens or API keys sent via the headers field in mcp.json. Remote servers without OAuth, internal APIs using static tokens.
OAuth 2.1 Streamable HTTP Browser-based login. Cursor handles discovery, registration, PKCE, and token storage automatically. Third-party services (Linear, Figma, Slack), any server implementing the MCP auth spec.

Environment Variables for stdio Servers

Most local MCP servers prove their identity to upstream APIs through environment variables. Cursor injects these into the server process at launch time.

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "<YOUR_TOKEN>"
      }
    }
  }
}

The env field takes key-value pairs. Cursor hands them straight to the spawned process. Your token won't show up in Cursor's UI or logs. But it does sit in plaintext inside mcp.json. Commit that file to Git, and you've just shipped your credentials to every collaborator — or worse, a public repo.

Mitigation: Reference system-level environment variables using the ${env:VARIABLE_NAME} syntax rather than pasting raw values:

{
  "mcpServers": {
    "github": {
      "command": "npx",
      "args": ["-y", "@modelcontextprotocol/server-github"],
      "env": {
        "GITHUB_PERSONAL_ACCESS_TOKEN": "${env:GITHUB_TOKEN}"
      }
    }
  }
}

Now the real token lives in your shell profile or a secrets manager. The mcp.json file holds only a pointer, so you can safely version-control it.

Static Headers for Remote Servers

Some remote servers don't support OAuth. For those, you can pass a static API key or Bearer token in HTTP headers. Cursor ships these headers along with every request to the server endpoint.

{
  "mcpServers": {
    "internal-api": {
      "url": "https://mcp.internal.company.com/v1",
      "headers": {
        "Authorization": "Bearer <YOUR_API_KEY>"
      }
    }
  }
}

The environment variable reference syntax works in headers too:

{
  "mcpServers": {
    "internal-api": {
      "url": "https://mcp.internal.company.com/v1",
      "headers": {
        "Authorization": "Bearer ${env:INTERNAL_API_KEY}"
      }
    }
  }
}

Static headers are dead simple to set up. They also carry every downside of long-lived credentials: no expiration, no per-session scoping, and rotating them forces you to touch every developer's config file.

OAuth 2.1 for Remote Servers

OAuth is what the MCP specification actually recommends for remote servers, and Cursor v1.0 brought native support. Here's what the experience looks like end to end:

  1. Drop a remote server URL into mcp.json — no auth headers needed.
  2. Open Cursor Settings → Tools & MCP. The server shows up with a blue Connect button and a "Needs authentication" label under its name.
  3. Hit Connect. Cursor pops open your default browser to the authorization server's login page.
  4. Log in and grant the permissions it asks for.
  5. After you authorize, the browser redirects to cursor://anysphere.cursor-mcp/oauth/callback. Your OS routes the callback back to Cursor, which swaps the authorization code for tokens via PKCE with S256.
  6. The server's tools show up in the MCP tools list, ready for the agent to call.

The JSON config for an OAuth-backed server looks minimal because it is minimal:

{
  "mcpServers": {
    "linear": {
      "url": "https://mcp.linear.app/mcp"
    }
  }
}

No tokens. No headers. Cursor handles everything through the spec's discovery flow — the server's Protected Resource Metadata tells Cursor where to go, and PKCE locks down the token exchange.

One-click deep links also play nicely with OAuth. Click an "Add to Cursor" link on a server's docs page, and Cursor triggers the OAuth flow right away if the server needs it.

Authentication Security Risks

MCP authentication opens up attack surface at every point in the credential lifecycle: how you store them, send them, exchange them, and revoke them. Several nasty vulnerabilities made that clear throughout 2025.

CVE-2025-6514: Command Injection via OAuth Discovery

JFrog Security Research found a critical flaw (CVSS 9.6) in mcp-remote, a popular npm package that proxied OAuth connections for MCP clients — Cursor included. The issue? The package grabbed the authorization_endpoint URL from whatever MCP server it connected to and never sanitized it.

A rogue server operator could stuff shell commands into that endpoint URL. When mcp-remote tried opening the URL in a browser, the operating system executed the embedded commands instead of loading a web page.

Versions 0.0.5 through 0.1.15 were affected. Over 437,000 downloads. Cloudflare, Hugging Face, and Auth0 had all pointed to mcp-remote in their MCP integration docs. The fix landed in version 0.1.16.

At its core, the vulnerability traced back to the OAuth trust model: the MCP client asked an untrusted server "where should I send my user to log in?" and then blindly followed the answer. The patch added URL validation and sanitization before anything got passed to system handlers.

One-Click Account Takeover in Remote MCP Servers

Obsidian Security dropped a set of one-click account-takeover vulnerabilities in production MCP servers run by well-known organizations. The common thread across all of them: most MCP servers double as OAuth proxies — they take an authorization code from Cursor and trade it for tokens with the upstream service.

What went wrong was structural. These servers failed to bind OAuth state parameters to user sessions. They didn't enforce consent properly. An attacker could craft a link that funneled an authorization code to a redirect URI the attacker controlled.

Obsidian filed the reports between July and August 2025. Vendors patched them by September. The November 2025 MCP specification update added explicit security guidance covering these exact attack patterns. Worth noting: only 3 out of 78 MCP authorization servers Obsidian tested actually supported CIMD at the time. Adoption of newer spec features has been slow.

MCP Client Vulnerabilities via OAuth Flows

Obsidian also flagged critical bugs in MCP clients themselves — Gemini-CLI, VS Code, Windsurf, and Cherry Studio all had issues (CVE-2025-54074 and three related CVEs). The flaw category was Remote Code Execution through sloppy handling of authorization URLs.

When an MCP client opened a crafted authorization_endpoint via the system's URL handler, an attacker could run arbitrary OS commands on the developer's machine. The MCP authorization spec doesn't restrict URL schemes, so file://, javascript:, or platform-specific schemes could sail through if the client skipped validation.

Plaintext Credentials in mcp.json

The most common risk needs no CVE number. Any API key you drop into mcp.json sits in cleartext on your filesystem. If that file ends up in a project directory and somebody commits it to Git, the credential leaks to every collaborator — and possibly every person on the internet if it's a public repo. Environment variables at least require shell access. But mcp.json is a versioned config file that developers share routinely, without thinking twice.

How the MCP Auth Spec Evolved

The MCP authorization specification went through three major rewrites in 2025. Each one addressed real flaws uncovered in the previous version.

Spec Date Key Change Impact on Cursor
March 2025 Introduced OAuth 2.1 with PKCE. MCP servers acted as both resource servers and authorization servers. Cursor shipped initial OAuth support in v1.0 (June 2025).
June 2025 Separated MCP servers from authorization servers. MCP servers now only validate tokens, not issue them. Mandated Protected Resource Metadata (RFC 9728). Deprecated SSE as standalone transport. Cursor aligned with the updated discovery flow.
November 2025 Added CIMD as preferred client registration method. Made PKCE mandatory with S256 challenge. Downgraded Dynamic Client Registration (DCR) from SHOULD to MAY. Added explicit security guidance for consent and state binding. Cursor forum posts from January 2026 request CIMD support, indicating Cursor still primarily uses DCR.

The June 2025 revision was the big one. Before that change, every MCP server developer had to build their own authorization endpoints. That effectively forced every server author into becoming an OAuth implementer — a terrible idea if you care about security. The updated spec offloaded token issuance to dedicated identity providers (Okta, Auth0, Azure AD), which is how enterprise auth has worked for years.

November 2025 tackled client registration head-on. DCR had been a headache because most enterprise authorization servers don't enable it out of the box. CIMD sidesteps that problem: each client publishes a metadata document at a well-known URL, and authorization servers make trust decisions based on the domain alone. Cleaner, more practical, and friendlier to locked-down enterprise environments.

Enterprise Authentication with an MCP Gateway

A single developer can keep track of a handful of API keys without much trouble. A team cannot. Ten developers each using five MCP servers creates fifty separate credential setups — no central visibility into who can access what, no automated key rotation, no audit trail.

An MCP Gateway puts all of that in one place. TrueFoundry's MCP Gateway supports three authentication methods when you register upstream MCP servers:

  • No Auth: For demo environments or public APIs. Not suitable for production.
  • Static Header Auth: For servers that use API keys or static tokens. The gateway stores the credential centrally and injects it into every outbound request.
  • OAuth2 and DCR: For servers that implement OAuth. The gateway runs the full OAuth flow, stores per-user tokens, and refreshes them automatically before they expire.

The operating model resembles single sign-on but for MCP. Developers authenticate once with TrueFoundry — either through a Personal Access Token (PAT) or their org's identity provider (Okta, Azure AD). The gateway maps that identity to the right downstream credential for each MCP server. Individual developers never touch an OAuth token directly.

On the admin side, you organize servers into MCP Server Groups and assign access by team or role. A junior developer might get read-only GitHub access. A senior engineer gets full GitHub plus write access to JIRA. The gateway enforces those boundaries at the protocol level — not through honor-system config files.

Here is a detailed walkthrough for setting up Okta OAuth2 authentication with MCP servers through the gateway, covering authorization server provisioning, scope management, and token refresh configuration.

Best Practices for MCP Authentication in Cursor

  • Never commit secrets to mcp.json. Use the ${env:VAR} reference syntax for stdio servers. Reach for OAuth on remote servers. If static headers are your only option, reference environment variables in those too.
  • Prefer OAuth over static tokens for anything remote. OAuth tokens expire. You can scope them. You can revoke them. Static tokens do none of that.
  • Pin your mcp-remote version if you depend on it. CVE-2025-6514 proved that one unpatched OAuth proxy can compromise your whole dev environment. Run npx -y mcp-remote@0.1.16 or later — never @latest in production.
  • Restrict token scopes aggressively. When Cursor walks you through an OAuth flow, grant the bare minimum. Read-only for code search. Write access only when the agent genuinely needs to create issues or merge PRs.
  • Audit your connected servers on a regular basis. Go to Cursor Settings → Tools & MCP and review what's active. Kill anything you don't use anymore. Every connected server is an active credential sitting in memory.
  • Keep Cursor updated. Each release ships OAuth handling improvements and security patches. An outdated Cursor version means outdated auth code running on your machine.

Conclusion

MCP authentication in Cursor spans a wide range — from a plaintext API key in a JSON file all the way to a full OAuth 2.1 flow with PKCE, dynamic registration, and automatic token refresh. Picking the right method comes down to the server's deployment model and how seriously you take your security posture.

For local development, environment variables paired with the ${env:VAR} syntax keep credentials out of version control. For remote services, OAuth removes manual token management from the equation entirely. And for teams or enterprises, an MCP Gateway like TrueFoundry's centralizes credential storage, enforces role-based access, and gives you a full audit trail across every MCP connection.

Explore TrueFoundry's MCP Gateway or book a demo to see centralized MCP authentication in action.

Frequently Asked Questions

What authentication methods does Cursor support for MCP servers?

Cursor offers three: environment variables injected into local stdio server processes, static HTTP headers (Bearer tokens or API keys) for remote servers, and OAuth 2.1 with PKCE for remote servers running the MCP authorization specification. OAuth support has been available since Cursor v1.0, which shipped in June 2025.

How does OAuth work for MCP in Cursor?

When you add a remote MCP server that requires OAuth, Cursor follows the MCP authorization spec. It finds the authorization server through Protected Resource Metadata (RFC 9728), registers itself as a client, opens your browser so you can log in and grant permissions, then exchanges the authorization code for tokens using PKCE. Cursor holds the tokens securely and refreshes them on its own when they're about to expire.

Is it safe to store API keys in mcp.json?

Putting raw API keys in mcp.json means storing credentials in plaintext on disk. If that file gets committed to version control, the key leaks. Swap in the ${env:VARIABLE_NAME} reference syntax instead — it pulls values from your system environment at runtime. For remote servers, prefer OAuth, which cuts static credentials out of the picture entirely.

What was the mcp-remote vulnerability?

CVE-2025-6514 was a critical command injection bug (CVSS 9.6) in the mcp-remote npm package, affecting versions 0.0.5 through 0.1.15. JFrog Security Research discovered that the package forwarded OAuth authorization endpoint URLs to system handlers without any sanitization. A malicious MCP server could construct a URL that executed arbitrary OS commands on the developer's machine. Version 0.1.16 shipped the fix.

How do enterprises manage MCP authentication at scale?

With an MCP Gateway that takes over all credential management. TrueFoundry's gateway stores and refreshes OAuth tokens on a per-user basis, maps organizational identities to downstream MCP credentials, and enforces role-based access policies. Developers log in once and never deal with individual MCP server tokens again.

Does Cursor support CIMD for OAuth client registration?

Not yet, as of early 2026. Cursor still leans on Dynamic Client Registration (DCR) for its OAuth flows. The November 2025 MCP specification introduced CIMD as the preferred registration method, but community forum posts from January 2026 suggest the feature hasn't shipped. DCR continues to work fine for most OAuth-enabled MCP servers in the meantime.

The fastest way to build, govern and scale your AI

Discover More

No items found.
March 3, 2026
|
5 min read

Top 8 Amazon Bedrock Alternative and Competitors for 2026 [Detailed Review]

No items found.
March 3, 2026
|
5 min read

MCP Authentication in Claude Code 2026 Guide

No items found.
March 3, 2026
|
5 min read

MCP Servers in Cursor: Setup, Configuration, and Security (2026 Guide)

No items found.
March 3, 2026
|
5 min read

MCP Authentication in Cursor: OAuth, API Keys, and Secure Configuration (2026 Guide)

No items found.
No items found.
Take a quick product tour
Start Product Tour
Product Tour