CIMD vs DCR: The new default for MCP Client Registration in 2025
A technical guide to MCP client registration: Dynamic Client Registration (DCR) vs Client ID Metadata Documents (CIMD).
MCP’s 2025-11-25 release quietly makes a huge change to how OAuth clients introduce themselves to servers. If you’ve built MCP auth before, you’ve dealt with Dynamic Client Registration (DCR). Starting with this spec, the default path is shifting to Client ID Metadata Documents (CIMD), a newer OAuth pattern that trades per-server registration for a web-native identity model.
This post is a technical guide to both approaches: what they are, how they work in MCP, and when you’d choose one over the other.
The problem that both DCR and CIMD try to solve
OAuth assumes the authorization server already knows the client: it has a client ID, redirect URIs, and maybe keys. In a normal SaaS world, that’s fine; you register once in a developer portal.
MCP breaks that assumption. MCP clients (AI apps, IDE helpers, agents, etc.) might connect to thousands of MCP servers, many of which the client has never seen before. The ecosystem needs a way for a client to say: “Hey auth server, here’s who I am and how to send the user back to me.”
DCR and CIMD are two different answers to that.
What is Dynamic Client Registration (DCR)?
Dynamic Client Registration is an OAuth extension standardized in RFC 7591. It lets a client register itself programmatically with an authorization server at runtime.
Instead of a human creating a client in a dashboard, the client does an HTTP POST to the server’s registration endpoint.
1. Client discovers the registration endpoint from auth server metadata.
2. Client sends a registration request, including:
redirect_urisclient_namegrant_typesresponse_typestoken_endpoint_auth_method- optional keys, logos, etc.
Example (simplified):
3. Auth server stores the client and returns:
- a minted
client_id - (maybe) a
client_secret - the registered metadata.
Then the client can start a normal OAuth code flow using that new client_id.
The problem with Dynamic Client Registration
In early MCP, DCR looked like the obvious solution:
- No manual setup.
- Clients can onboard onto arbitrary servers automatically.
- Matches how OpenID Connect ecosystems scale.
DCR is legit, but MCP pushes it into worst-case territory:
- Client sprawl: Servers potentially see an unbounded number of auto-registered clients. Every new AI tool becomes a database entry. Some DCR implementations add client expiration or cleanup jobs, but RFC 7591 doesn’t mandate any lifecycle policy, so open MCP servers can’t rely on that being present.
- Endpoint risk: DCR requires a public registration endpoint, which becomes a high-value abuse target (spam registrations, DoS, weird metadata attacks).
- Lifecycle pain: Clients need to store per-server client IDs/secrets, rotate them, and clean them up. Many clients “recover” from errors by re-registering, which amplifies the sprawl.
- Enterprise friction: Enterprises don’t love a world where random clients can register themselves against internal auth systems without admin involvement.
So the spec pivoted.
What is Client ID Metadata Documents (CIMD)?
Client ID Metadata Documents are an OAuth Working Group draft (adopted in October 2025) that lets a client identify itself using a URL as its client_id. That URL points to a JSON document describing the client.
No preregistration. No “register me” endpoint. The web address is your identity.
How Client ID Metadata Documents works
1. Client hosts metadata at a stable HTTPS URL it controls, e.g. https://ai.example.com/oauth-client.json. Example:
jwks_uri is optional; if present, servers may allow JWT client auth.
2. The client uses that URL as its client_id in the OAuth request (with PKCE). Example:
client_id = https://ai.example.com/oauth-client.jsonredirect_uri = https://ai.example.com/callbackresponse_type = codecode_challenge/code_challenge_method = S256(PKCE)
3. The auth server fetches the client metadata from the client_id URL. It expects standard OAuth client metadata fields like client_name, redirect_uris, grant_types, token_endpoint_auth_method, and optional jwks_uri.
4. Server validates and caches the doc:
client_idmust be HTTPS- document must be JSON
- doc’s
client_idmust exactly match the URL used - requested
redirect_urimust be inredirect_uris(same-origin recommended) - cache with normal HTTP headers (ETag / Cache-Control)
MCP adopts this model in SEP-991 and calls it out as a headline simplification in the 2025-11-25 spec.
Why this fits MCP better
CIMD is basically “OAuth meets the web.” The benefits line up perfectly with MCP’s scale problem:
- Decentralized identity: If you trust the domain, you trust the client metadata it hosts. No per-server registration list.
- No registration endpoint to secure: Auth servers don’t need to expose DCR routes or deal with spam client creation.
- No client credential sprawl: Clients don’t store a different
client_idper server. Their identity is stable everywhere. - Feels web-native: Using URLs as identifiers is a pattern OAuth already leans on (issuer URLs, JWKS URLs, discovery docs).
In MCP, where any client might talk to any server, CIMD keeps server state flat instead of growing per connection.
Why CIMD fixes MCP’s DCR scaling issues
Think of DCR as a “registration desk.” Every time a client shows up, the server creates a new entry for it. In a world like MCP (where clients might connect to endless servers) that desk becomes a bottleneck and an abuse magnet.CIMD is more like a driver’s license:
- The client identity is a single stable URL for the app, not a new ID per server or per install.
- Servers don’t keep a giant client database; they just read and cache metadata.
- There’s no registration endpoint to flood or rate-limit.
- Trust flows from domain ownership: if you don’t control
app.example.com, you can’t publish a valid identity for it.
So you lose the “open write endpoint + infinite database growth” problems in one move.
CIMD and client impersonation
A fair worry with CIMD is: what stops a sketchy client from claiming it’s a legit one? Like, what if falseurl.com starts an OAuth login but sets client_id=https://app.example.com/oauth.json?
The guardrail is redirect URI matching.
Here’s the attempted attack:
- The phishing app sends an authorization request.
- It uses the real app’s
client_id(the metadata URL onapp.example.com). - But it supplies its own redirect URI, e.g.
https://falseurl.com/callback.
What the auth server does:
- It sees the
client_idis a URL, so it fetches that metadata from the real domain. - In that JSON, it finds the legitimate app’s allowed
redirect_uris. - It compares the redirect URI in the request to that allowlist.
Since https://falseurl.com/callback isn’t in the real app’s list, the server rejects the flow. No code gets issued, so the phisher never receives tokens.
In short: you can pretend to be me, but you can’t make the server send credentials to your domain. Only whoever controls the domain in the metadata doc can receive the auth response.
CIMD and confidential clients (no more per-server secrets)
With DCR, a “confidential client” usually gets a client_secret from each server when it registers. That doesn’t scale well in MCP. CIMD flips the model:
- The client publishes how it authenticates inside its metadata doc.
- Instead of a server-issued secret, the client uses its own keypair.
Concretely:
- The metadata declares something like:
token_endpoint_auth_method: "private_key_jwt"- plus a
jwks_uriwhere the server can fetch public keys.
- When the client hits the token endpoint, it signs a JWT with its private key.
- The auth server fetches the public key from
jwks_uriand verifies the signature.
Result: strong client authentication without preregistered secrets or per-server credential storage.
!!private_key_jwt is the common CIMD-friendly choice, but other OAuth client auth methods (like client_secret_jwt) still work if you do have a shared secret. It just brings back some of the scalability pain CIMD is trying to avoid.!!
CIMD and security
CIMD is a trade: it closes some risks and introduces others.
- SSRF risk: Auth servers now fetch
client_idURLs provided by strangers. A malicious client could try to make your server request internal resources (classic SSRF), like cloud metadata IPsorprivate network ranges. Mitigations are straightforward but must be done:- Block loopback + private IP ranges.
- Enforce HTTPS only.
- Use strict timeouts.
- Cap response size (tiny docs; ~5KB is plenty).
- Don’t follow redirects to private networks.
- Localhost ambiguity: If a client uses
http://localhost:1234/callback, the server can’t tell which local app is listening there. That’s not specific to CIMD, but CIMD doesn’t fix it either. That’s why many native-app OAuth setups prefer custom URI schemes (likevscode://callbackormyapp://auth) to avoid ‘who’s listening on localhost?’ ambiguity. - Domain ≠ reputation: CIMD proves you control a domain, not that you’re trustworthy. Servers still need trust policies (warnings, allowlists, etc.) for unknown domains.
In practice, MCP maintainers judged CIMD’s risks as easier to standardize and defend than DCR’s ecosystem-scale abuse.
Where CIMD sits in MCP’s auth flow
CIMD is now the preferred registration method, but MCP uses a priority order:
- Pre-registration (classic developer-portal clients)
- CIMD
- DCR
- Manual user input
So if pre-registration exists, MCP uses it; otherwise it falls back to CIMD first.
When would you still use DCR?
Even with CIMD as the preferred default, DCR isn’t dead. It still makes sense when:
- You’re in a closed enterprise ecosystem where admins want to approve every client.
- The client can’t host stable web metadata (some ultra-embedded environments).
- You want a guaranteed server-side registry of clients for audit.
Think “internal corporate agent platform” more than “open MCP marketplace.”
Where MCP is heading next
DCR is a real standard and still useful in locked-down ecosystems. But for MCP’s federated scale, CIMD is the better default. The direction in the spec is: CIMD SHOULD be used; DCR MAY be supported when needed.
The community is already talking about layering Software Statements on top of CIMD. The idea isn’t “a statement fixes everything,” but “a statement signed by a trusted issuer creates a chain of trust.”
If the auth server recognizes the issuer (app store, OS vendor, enterprise registry), then a client can prove more than “I own this domain.” It can prove “I’m the officially attested app.”
That’s likely the next step toward MCP identity that scales and survives hostile environments.
WorkOS supports MCP (and CIMD is already live)
If you’re building an MCP server and don’t want to re-implement OAuth from scratch, WorkOS already supports MCP natively. AuthKit can act as your OAuth 2.1 authorization server for MCP, handling PKCE, token minting, scopes/tool permissions, and the rest of the auth surface that the spec expects.
And importantly for this post: WorkOS now supports Client ID Metadata Documents (CIMD) for MCP auth. In other words, if an MCP client shows up with a URL-style client_id, AuthKit will fetch, validate, and cache that metadata per the 2025-11-25 spec, no Dynamic Client Registration required.