MCP OAuth Evolution: SEP-991 Simplifies Client Registration

Overview

The Problem with Dynamic Client Registration

In my previous deep-dive into MCP authorization, I analyzed how the protocol builds on OAuth 2.1 with mandatory PKCE, Resource Indicators (RFC 8707), and the "Discovery Trifecta" of RFC 7591, 8414, and 9728. Dynamic Client Registration (DCR) was positioned as the key enabler for MCP's federated ecosystem.

However, DCR has significant practical limitations:

ChallengeImpact
Requires AS support for public registration APIMany identity providers don't offer this
Forces OAuth proxy infrastructureAdded complexity when AS lacks DCR
Manual IT involvementEnd users need admin help for each registration

The MCP ecosystem faces a unique challenge: unbounded clients connecting to unbounded servers with no prior relationship. DCR, while standardized, often requires workarounds in practice.

SEP-991: URL-Based Client Identity

On MCP's first anniversary, the team announced a simplified approach: OAuth Client ID Metadata Documents (SEP-991). This mechanism is now officially part of the 2025-11-25 stable specification.

Core Concept

Instead of registering with the Authorization Server, the client hosts its own identity document at an HTTPS URL. The client_id itself becomes the URL pointing to this metadata.

1client_id = "https://my-mcp-client.com/.well-known/oauth-client.json"

Metadata Document Structure

The client hosts a JSON document containing its OAuth metadata:

 1{
 2  "client_id": "https://my-mcp-client.com/.well-known/oauth-client.json",
 3  "client_name": "My MCP Client",
 4  "redirect_uris": [
 5    "https://my-mcp-client.com/callback",
 6    "http://localhost:8080/callback"
 7  ],
 8  "token_endpoint_auth_method": "none",
 9  "grant_types": ["authorization_code"],
10  "response_types": ["code"]
11}

Key fields:

  • client_id: Must exactly match the document's URL
  • client_name: Displayed to users during authorization
  • redirect_uris: Allowed callback URLs
  • token_endpoint_auth_method: none for public clients, private_key_jwt for confidential

New Client Registration Priority

The specification defines a clear priority order:

PriorityMethodWhen to Use
1Pre-registered credentialsKnown client-server relationships
2Client ID Metadata DocumentsServer supports client_id_metadata_document_supported
3Dynamic Client RegistrationFallback if AS supports RFC 7591
4Manual user entryLast resort

SEP-991 now takes precedence over DCR when supported.

Authorization Flow Comparison

Traditional DCR Flow

sequenceDiagram
    participant Client
    participant AS as Authorization Server

    Note over Client,AS: Registration Phase
    Client->>AS: POST /register {redirect_uris, client_name...}
    AS->>AS: Validate & store client
    AS-->>Client: {client_id: "generated-id-123", client_secret...}

    Note over Client,AS: Authorization Phase
    Client->>AS: GET /authorize?client_id=generated-id-123&...

SEP-991 Flow

sequenceDiagram
    participant Client
    participant AS as Authorization Server
    participant Meta as Client Metadata URL

    Note over Client,AS: No Registration Phase!

    Client->>AS: GET /authorize?client_id=https://client.com/meta.json&...
    AS->>Meta: GET https://client.com/meta.json
    Meta-->>AS: {client_id, client_name, redirect_uris...}
    AS->>AS: Validate: client_id matches URL, redirect_uri allowed
    AS-->>Client: Continue authorization flow

Key difference: The client never registers. The AS fetches and validates the metadata on-demand.

Server Discovery Support

Authorization Servers declare SEP-991 support in their metadata (RFC 8414):

1{
2  "issuer": "https://auth.example.com",
3  "authorization_endpoint": "https://auth.example.com/authorize",
4  "token_endpoint": "https://auth.example.com/token",
5  "client_id_metadata_document_supported": true
6}

Clients check this field before using URL-based client IDs.

Specification Status

VersionSEP-991 Status
2025-03-26Not included
2025-06-18Not included
2025-11-25 (current)Included

The feature is now officially part of the stable MCP specification.

SDK Implementation Status

Not all official MCP SDKs have implemented SEP-991 yet. Here's the current support matrix:

SDKLanguageSEP-991 SupportNotes
typescript-sdkTypeScript✅ ImplementedFull CIMD support with capability detection
python-sdkPython✅ ImplementedFull CIMD support with graceful fallback
rust-sdkRust❌ Not yetStandard OAuth 2.1 + DCR only
go-sdkGo❌ Not yetRFC 8414 metadata only
kotlin-sdkKotlin❓ UnknownOAuth support not documented
csharp-sdkC#❌ No OAuthProtocol implementation only

TypeScript SDK Example

1// The SDK automatically detects server support
2const supportsUrlBasedClientId =
3  metadata?.client_id_metadata_document_supported === true;
4
5// When supported, uses URL as client_id
6if (supportsUrlBasedClientId && clientMetadataUrl) {
7  clientInformation = { client_id: clientMetadataUrl };
8}

Python SDK Example

1# Validates metadata URL format
2# "client_metadata_url must be a valid HTTPS URL with a non-root pathname"
3
4# Creates client info from metadata URL when supported
5client_information = create_client_info_from_metadata_url(
6    self.context.client_metadata_url,
7    redirect_uris=self.context.client_metadata.redirect_uris,
8)

Both SDKs implement the priority order: check client_id_metadata_document_supported → use CIMD if available → fall back to DCR.

Implementation Impact

For MCP Clients

Requirements:

  • Host metadata document at HTTPS URL with path component
  • Ensure client_id in document matches the URL exactly
  • Include all required fields: client_id, client_name, redirect_uris

Benefits:

  • No registration API calls needed
  • Self-managed identity
  • Works with any AS that supports SEP-991

For Authorization Servers

Requirements:

  • Implement metadata document fetching and validation
  • Verify client_id matches fetched URL
  • Respect HTTP cache headers for metadata
  • Declare support via client_id_metadata_document_supported

Trust model:

  • HTTPS domain ownership proves client identity
  • Servers can restrict to trusted domains or allow any HTTPS client

Relationship to Existing Infrastructure

For those who followed my guide on implementing MCP OAuth with Keycloak, SEP-991 represents a significant simplification. Instead of configuring DCR endpoints and client registration flows, implementations can now:

  1. Host a static JSON file on the client's domain
  2. Configure the Authorization Server to fetch and validate client metadata URLs
  3. Eliminate the need for client pre-registration or DCR infrastructure

This aligns with MCP's goal of zero-configuration federation.

Summary

SEP-991 shifts the client registration paradigm:

AspectDCR (Legacy)Client ID Metadata (New)
Who registersAuthorization ServerClient self-hosts
client_id formatServer-generated stringHTTPS URL
Coordination neededYes (API call)No
Identity verificationRegistration-timeFetch-time (HTTPS domain)

The change transforms "server registers client" into "client proves identity"—a fundamental simplification for MCP's open ecosystem.


Resources

Specifications