New Livestream: OWASP Top 10 2025 Explained for .NET Developers.

Register Now!

CIMD vs DCR: A Better Client Registration Model for MCP Authorization

Joe DeCock Principal Product Software Engineer
Joe DeCock follows the OAuth working group, the OpenID Foundation, and the IETF and writes up what matters for working developers. Follow Joe on LinkedIn to catch his commentary as these standards evolve, and subscribe to the Duende newsletter using the form at the bottom of this page for implementation guidance, security updates, and deep dives delivered to your inbox.

By replacing Dynamic Client Registration (DCR) with Client ID Metadata Documents (CIMD), the latest MCP specification solves the problem of accumulating orphaned client records on authorization servers.

Imagine you're using an agent harness like Claude Code or OpenCode, and you connect to a Model Context Protocol (MCP) server for the first time. The server protects its tools with OAuth, so before the harness can send you through an authorization flow, it needs a client ID that the authorization server understands. Where does that client ID come from?

Early versions of MCP answered that question with Dynamic Client Registration (DCR). The client sends its metadata to an endpoint, the authorization server creates a client record, and the server hands back a client ID to use in the authorization flow.

The latest MCP specification has changed its answer. It now recommends Client ID Metadata Documents (CIMD), and I think that's the right call. In this article, we'll look at why DCR is a poor fit for the way MCP clients and servers meet, and what CIMD does differently.

Why Does Dynamic Client Registration Create Unused Records?

DCR does exactly what it says on the tin: it registers an OAuth client dynamically. The client sends its metadata to the authorization server:

Http

POST /register HTTP/1.1
Host: authorization.example.com
Content-Type: application/json

{
  "client_name": "Claude Code",
  "redirect_uris": ["http://localhost:49231/callback"],
  "grant_types": ["authorization_code"],
  "token_endpoint_auth_method": "none"
}

The authorization server validates the request, writes a client record, and returns a client_id. That's a sensible design when the server expects the client to stick around and has a plan for managing that record over time.

Sometimes a durable record is exactly what you want. A deployment pipeline that spins up a new environment can use its own credentials to register the client that environment needs. An Open Banking participant can present evidence from the ecosystem's trust framework before another bank registers it. The controls differ, but in both cases the authorization server is deliberately admitting a client it expects to manage for a long time.

MCP has the opposite shape. Clients and servers meet before the authorization server has any reason to set up a lasting relationship. The server needs enough metadata to run an OAuth flow, but it often has no controlled basis for admitting the client into a permanent registry, and it may see a lot of these connections.

Go back to our agent harness example. You connect to an MCP server, register, and authorize access. Other developers connect their own MCP clients, and every DCR request adds another client record. Over time the pile grows. The operator would like to clean out records that will never be used again, but has no reliable way to tell them apart from clients that will come back next week.

The client wants the opposite: confidence that its registration still exists when it returns. It can't safely assume that, so re-registering is the conservative choice. Cleanup makes re-registering more likely, but every retry creates another record for the operator to manage, pushing the operator to more aggressively clean up old records.

Neither side is doing anything unreasonable. The problem is that DCR makes the authorization server store client metadata that the client is usually better placed to publish and maintain itself. That’s exactly the approach that CIMD takes: the client is to describe itself, and the authorization server pulls from it on demand.

Lifecycle isn't the only concern. An open DCR endpoint is a write endpoint that anyone can call without credentials, so an attacker can fill your store with registrations. You can rate-limit the endpoint and add other controls, but you're still defending against unbounded writes.

More importantly, a successful registration creates an OAuth client that can operate in your authorization server's environment. Before you allow that, you need some basis for deciding which clients you're willing to create.

When Does Dynamic Client Registration Work Well? Governed Ecosystems

DCR does have mechanisms for controlled registration. MCP doesn't use them as its general answer, but not because MCP is missing something. DCR’s controlled registration mechanisms assume a source of authority that an open MCP ecosystem doesn't have.

An authorization server can require an initial access token before it accepts a DCR request. This works well when a CI/CD system or an administrator already has credentials and permission to create registrations. The token gives the server a direct reason to let that caller create a client.

More structured ecosystems also use software statements. A software statement is signed metadata about a client, and it lets the authorization server verify that some other party vetted the client before registration.

Open Banking is a useful contrast. The ecosystem accredits a participant and issues a software statement from a trust authority. When it registers with another bank, that bank validates the trust authority's signature and checks that the statement is bound to the calling client. The two banks don't need a direct relationship, because they share the ecosystem's governance, accreditation process, and public key infrastructure.

MCP assumes none of that. A new MCP client and authorization server should work together without a common authority issuing registration tokens or vouching for every client. Initial access tokens and software statements are still useful where those prerequisites exist, but they can't be the default registration model for open MCP.

Why Does MCP Need Metadata Instead of Full Registration?

In the open MCP case, the authorization server still needs client metadata: redirect URIs, supported grant types, and the other details it uses to evaluate and run the OAuth flow. It doesn't need durable registration the first time it sees a client.

That's the problem Client ID Metadata Documents (CIMD) solve. Instead of pushing metadata to the authorization server for storage, the client publishes its metadata at a URL. The authorization server fetches that document when it needs it and caches the result according to its own policy.

The client ID is itself an HTTPS URL, and the document at that URL contains the client metadata:

Json

{
  "client_id": "https://code.example.com/oauth/client-metadata.json",
  "client_name": "Example Code Assistant",
  "redirect_uris": ["http://localhost:49231/callback"],
  "grant_types": ["authorization_code"],
  "token_endpoint_auth_method": "none"
}

So DCR pushes metadata to the server and creates a stored registration, while CIMD gives the server a URL to pull and cache metadata, with no permanent registration relationship.

The MCP authorization specification reflects that distinction. It deprecates DCR for new implementations in favor of CIMD. Pre-registration is still preferred when the client and authorization server already have a relationship, and DCR remains as a backward-compatible fallback. CIMD covers the common MCP case where no relationship exists yet.

Here's what the exchange looks like:

sequenceDiagram
    participant Client as MCP client
    participant AS as Authorization server
    participant Metadata as Client metadata URL

    Client->>AS: Authorization request with URL client_id
    AS->>Metadata: GET client_id URL
    Metadata-->>AS: Client ID Metadata Document
    AS->>AS: Validate metadata and apply policy
    AS->>AS: Cache metadata
    AS-->>Client: Continue authorization flow

The authorization server checks that the document's client_id matches the URL it fetched the document from. Then it validates the metadata, applies its policy, caches the result, and continues the OAuth flow.

What Does the Client ID Identify?

When we talk about agents, it's tempting to lump the OAuth client together with the user, the language model, or a particular agent run. A CIMD identifies the OAuth client: the software acting on a user's behalf. The CIMD URL tells the authorization server where to get that software's metadata.

If you and I both use Claude Code, we share the same client ID while authenticating as different users and granting access to different resources. That's ordinary OAuth. A native app, a server-rendered web app, or a Backend for Frontend (BFF) also uses one client identity across many users.

User authentication and authorization matter as much as ever. CIMD only changes how the authorization server learns about the client that starts the flow.

How Does Client-Published Metadata Improve Lifecycle Management?

CIMD doesn't make the authorization server's work disappear. For one thing, the server needs to fetch the metadata documents safely. Arbitrary network calls based on untrusted input is dangerous, so a CIMD implementation will need to include standard precautions against SSRF attacks. An authorization server implementing CIMD will also need to decide whether to trust the client’s domain. There are a number of heuristics that are possible, including allow-lists of known trusted domains, deny-lists of known bad actors, and trustworthiness checks, such as how recently the domain was registered. See Section 8.9 of the CIMD draft for more ideas. The authorization server also still manages user grants and consent according to its own policy, just as it always has.

What changes is the client metadata lifecycle. The authorization server doesn't create a permanent client row because an unfamiliar client showed up. It fetches metadata when needed and caches it for a sensible period. If the client goes away, its metadata URL eventually stops working, and the cache entry expires.

That sidesteps the DCR problem that matters most for MCP: treating every new connection as a permanent server-side registration.

What Is the Security and Trust Model of CIMD?

Anyone can host a CIMD. That's what makes it useful before a relationship exists, but you need to be clear about what the URL actually proves.

Suppose a client uses https://vscode.dev/oauth/client-metadata.json as its client ID. Microsoft controls vscode.dev, and HTTPS lets the authorization server fetch the document from that origin. If the document's client_id matches that URL, the server has evidence that whoever controls vscode.dev published the metadata.

That's useful information about the client, but it isn't enough to make a fully informed decision on trustworthiness. A well-hosted metadata document can still describe a buggy or malicious client, and a user still has to decide whether to grant it access. Those decisions still belong to the authorization server, which might accept any valid CIMD, require an allow-list, restrict the scopes a client can request, or apply policy based on the client and the user.

This is less ambitious than an accredited ecosystem with software statements. It also better matches where MCP starts: an open ecosystem where clients and servers interact before anyone has set up a bilateral relationship.

Conclusion

When you're deciding how a client should become known to your authorization server, ask two questions. Do you already have a relationship with this client, or a trusted party who can vouch for it? And do you want to manage a record for it over time? If the answer to both is yes, pre-registration or governed DCR still fits. If the client is showing up unannounced, as MCP clients usually do, publishing metadata at a URL is a much better fit than creating a registration that outlives its usefulness.

CIMD isn't a new authorization model for AI. It's a better way to describe OAuth clients in an ecosystem where clients often show up without an introduction.

Think back to that first connection from Claude Code. With DCR, it leaves behind a client record that the operator will wonder about forever. With CIMD, the authorization server reads the document the client already published and decides whether it likes what it sees. Nothing is left behind. I'm pleased to see MCP make this change. It fixes a real operational problem by moving client metadata to where it belongs: with the client that publishes and maintains it.

Related Articles