ExMCP.Authorization.ClientRegistration (ex_mcp v1.0.0-rc.8)

Copy Markdown View Source

Deprecated Dynamic Client Registration for OAuth 2.1.

Implements RFC 7591 (OAuth 2.0 Dynamic Client Registration Protocol) to allow MCP clients to register themselves with authorization servers at runtime.

MCP 2026-07-28 deprecates this mechanism in favor of Client ID Metadata Documents. Keep DCR only as a compatibility fallback for authorization servers that advertise registration_endpoint but not a usable CIMD path.

Example

# Register a new client
{:ok, client_info} = ExMCP.Authorization.ClientRegistration.register_client(%{
  registration_endpoint: "https://auth.example.com/register",
  client_name: "My MCP Client",
  application_type: "native",
  redirect_uris: ["https://localhost:8080/callback"],
  grant_types: ["authorization_code"],
  response_types: ["code"],
  scope: "mcp:read mcp:write"
})

# Use the returned client_id and client_secret for authorization flows

Summary

Functions

Validates a deprecated DCR request and builds its JSON payload.

Retrieves client information using a registration access token.

Registers a new client with the authorization server.

Updates client information using a registration access token.

Types

client_information()

@type client_information() :: %{
  client_id: String.t(),
  client_secret: String.t() | nil,
  client_secret_expires_at: integer() | nil,
  registration_access_token: String.t() | nil,
  registration_client_uri: String.t() | nil,
  client_name: String.t(),
  redirect_uris: [String.t()],
  grant_types: [String.t()],
  response_types: [String.t()],
  scope: String.t()
}

registration_request()

@type registration_request() :: %{
  :registration_endpoint => String.t(),
  :client_name => String.t(),
  :application_type => String.t(),
  :redirect_uris => [String.t()],
  :grant_types => [String.t()],
  :response_types => [String.t()],
  :scope => String.t(),
  optional(:token_endpoint_auth_method) => String.t(),
  optional(:client_uri) => String.t() | nil,
  optional(:logo_uri) => String.t() | nil,
  optional(:contacts) => [String.t()] | nil,
  optional(:tos_uri) => String.t() | nil,
  optional(:policy_uri) => String.t() | nil,
  optional(:software_id) => String.t() | nil,
  optional(:software_version) => String.t() | nil
}

Functions

build_request(request)

@spec build_request(registration_request()) :: {:ok, map()} | {:error, term()}

Validates a deprecated DCR request and builds its JSON payload.

get_client_information(registration_client_uri, registration_access_token)

@spec get_client_information(String.t(), String.t()) ::
  {:ok, client_information()} | {:error, term()}

Retrieves client information using a registration access token.

This allows clients to read their current registration information from the authorization server.

register_client(request)

@spec register_client(registration_request()) ::
  {:ok, client_information()} | {:error, term()}

Registers a new client with the authorization server.

Dynamic Client Registration is deprecated by MCP 2026-07-28. New clients should use a pre-registered client or Client ID Metadata Document.

This implements the client registration flow from RFC 7591, sending client metadata to the registration endpoint and receiving client credentials in response.

update_client_information(registration_client_uri, registration_access_token, updates)

@spec update_client_information(String.t(), String.t(), map()) ::
  {:ok, client_information()} | {:error, term()}

Updates client information using a registration access token.

This allows clients to modify their registration information at the authorization server.