mcp

MCP auth without a user: OAuth client credentials for server-to-server

When no human is present to approve access in a browser, the **OAuth Client Credentials** MCP authorization extension covers machine-to-machine access. The extension text itself defines "OAuth 2.1 Client Credentials flow support for the Model Context Protocol, enabling machine-to-machine authentication without user interaction." It is an **OPTIONAL** extension (Protocol Revision: draft) in the ext-auth repository—not part of the core authorization page. Clients and servers must opt in; extensions are never active by default. The interactive user flow (authorization code + PKCE) stays on the core MCP authorization spec.

Who this is for

You need a CI job, backend worker, or scheduled service to call a remote MCP server, and there is no user available to complete a login redirect.

Extension vs core auth

PieceWhat it isWhen it fits
Core MCP authorization (spec 2026-07-28)Authorization so clients can call restricted servers on behalf of resource owners, with a browser grant in the happy pathA human should approve access
OAuth Client Credentials extensionMachine-to-machine grant with pre-registered credentials; no user interactionCI, daemons, server-to-server
Static `CLIENT_ID` in Cursor `mcp.json`Fixed client for the user OAuth Connect path when DCR isn't availableInteractive Cursor Connect, not this extension

The core Authorization introduction says MCP authorization enables clients to make requests "on behalf of resource owners." The client-credentials extension builds on that baseline for cases with no resource owner in the loop. Implementations that adopt the extension "MUST also conform to the baseline authorization requirements," so Protected Resource Metadata discovery and the 401 `WWW-Authenticate` challenge still apply. See Protected Resource Metadata in plain English and the MCP OAuth pillar for Cursor and Claude Connect.

How the machine flow works

Per the extension:

  1. The client hits the MCP server without a token and gets 401 with `WWW-Authenticate` pointing at resource metadata.
  2. It discovers the authorization server the same way the core flow does.
  3. It requests a token with pre-registered credentials—no Dynamic Client Registration in this flow.
  4. It sends `Authorization: Bearer <access_token>` on MCP HTTP requests.

Client authentication is one of two methods the extension allows: a signed JWT assertion (RFC 7523), which the extension marks RECOMMENDED, or a client secret in the token request body. Prefer JWT when you can avoid shipping a long-lived secret. Store secrets outside the repo; rotate on a schedule you own.

The extension "is specifically designed for HTTP-based transports." For local stdio servers, credentials usually come from the environment instead of this grant.

Cursor static OAuth is not this extension

Cursor's MCP docs let you put an `auth` object with `CLIENT_ID`, optional `CLIENT_SECRET`, and optional `scopes` on a remote server entry. That is static client registration for the interactive Connect path when the provider doesn't support Dynamic Client Registration. Cursor's protocol/extension support table lists Apps among supported extensions; it does not list the client-credentials extension. Do not treat a static `CLIENT_ID` in `mcp.json` as proof that Cursor runs the machine-to-machine grant. For the static-ID pattern itself, see static CLIENT_ID in mcp.json.

Pitfalls

  • Calling client credentials "core MCP auth." It is an OPTIONAL authorization extension (draft). Quote the extension or narrow the claim.
  • Assuming every MCP client supports it. Extension support varies; check your client and server before designing around it.
  • Skipping the 401 + PRM path. Adopters still follow baseline authorization: challenge, metadata, then token.
  • Confusing static Connect credentials with client credentials. Same words; different flows.
  • Putting secrets in the repo. The marketing extension page warns that leaked client secrets authenticate as your app until rotated.

How to check it

  1. Confirm your authorization server advertises client-credentials support in its metadata (`token_endpoint_auth_methods_supported` includes at least one of `private_key_jwt` or `client_secret_basic`, per the extension).
  2. Prove the unauthenticated MCP URL still returns 401 with `resource_metadata` (same failure-card order as WWW-Authenticate stripped).
  3. Obtain a token with the client-credentials grant against that authorization server, then call the MCP URL with the bearer token.
  4. Confirm the client you will run in production declares the extension; if it doesn't, this flow will not appear in Connect UI.

Where the kit fits

The MCP Starter Kit ($27) is aimed at shipping remote MCP with OAuth-ready layout for Connect-style clients. Soft path if you're not buying yet: /free. Cheat Sheet for the skim checklist mindset.

Soft next step

Map whether your caller is a human Connect client or a headless service. If it's headless, verify extension support on both sides, then prove 401 → PRM → client-credentials token → bearer MCP call. Soft ladder: /free, then the MCP Starter Kit ($27). Related: MCP OAuth for Cursor and Claude Connect, static CLIENT_ID, PRM plain English, MCP auth checklist.

FAQ

Does MCP support auth without a user?+

Through an extension, yes. The MCP OAuth Client Credentials Extension "defines OAuth 2.1 Client Credentials flow support for the Model Context Protocol, enabling machine-to-machine authentication without user interaction."

Is client credentials part of the core MCP authorization spec?+

No. It's a separate extension that the text itself marks as "OPTIONAL for MCP implementations," and it's still a draft revision. Check whether your client and server adopt it before you design around it.

Do I still need Dynamic Client Registration for this flow?+

No. The extension says the flow "requires pre-registered client credentials" set up out-of-band, and "Dynamic Client Registration is not used in this flow."

How does the client authenticate to the token endpoint?+

One of two ways: a signed JWT assertion per RFC 7523, which the extension marks RECOMMENDED, or a client secret sent in the request body.

Does the extension replace the baseline MCP auth rules?+

No. Implementations that adopt it "MUST also conform to the baseline authorization requirements," so protected resource metadata discovery and the 401 challenge still apply.

Does it work over stdio?+

The extension says it "is specifically designed for HTTP-based transports." For a local stdio server, credentials usually come from the environment instead.

Get the free starter

Value first, then a kit when you are ready. No fake urgency. Start with Harness Desk Starter at /free.