Skip to content

Set OIDC application_type on Dynamic Client Registration per SEP-837#408

Open
koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:dcr_application_type
Open

Set OIDC application_type on Dynamic Client Registration per SEP-837#408
koic wants to merge 1 commit into
modelcontextprotocol:mainfrom
koic:dcr_application_type

Conversation

@koic

@koic koic commented Jun 14, 2026

Copy link
Copy Markdown
Member

Motivation and Context

SEP-837 (modelcontextprotocol/modelcontextprotocol#837, merged for the 2026-07-28 spec release) updates the authorization spec to require MCP clients to specify an appropriate OIDC application_type ("native" vs "web") during Dynamic Client Registration, so the authorization server can apply the matching redirect URI policy and native and web clients do not collide on redirect URI validation rules.

This mirrors the approach taken by the TypeScript SDK (typescript-sdk#2266) and the Python SDK (python-sdk#2784):

  • MCP::Client::OAuth::Discovery.infer_application_type(redirect_uris) returns "native" when every redirect URI is a native-app URI (a custom non-http(s) scheme per RFC 8252 Section 7.1, or an http(s) URI with a loopback host per RFC 8252 Section 7.3) and "web" otherwise, including for nil, empty, or unparseable input. Loopback detection reuses the existing loopback_host? helper, so lookalike hosts such as localhost.example.com or 127.attacker.com are not treated as native.
  • Flow#ensure_client_registered now posts the metadata through the new registration_client_metadata helper, which merges the inferred application_type into the DCR request body only when the user did not set one explicitly (symbol or string key); an explicit value always wins.

Resolves #375.

How Has This Been Tested?

New tests in test/mcp/client/oauth/discovery_test.rb cover the inference: loopback http URIs (IPv4, IPv6, localhost), custom schemes, https URIs, mixed lists, the localhost.example.com lookalike, nil/empty input, and unparseable URIs.

New tests in test/mcp/client/oauth/flow_test.rb assert on the actual DCR request body via WebMock assert_requested: loopback redirect URI registers "application_type": "native", an HTTPS redirect URI registers "web", and an explicit application_type (symbol- or string-keyed) is never overridden.

Breaking Changes

None. The DCR request body gains an application_type member only when the user has not specified one; RFC 7591 requires authorization servers to accept and use known metadata fields, and OIDC-registration servers already default this field to "web" when absent.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Documentation update

Checklist

  • I have read the MCP Documentation
  • My code follows the repository's style guidelines
  • New and existing tests pass locally
  • I have added appropriate error handling
  • I have added or updated documentation as needed

## Motivation and Context

SEP-837 (modelcontextprotocol/modelcontextprotocol#837, merged for the 2026-07-28 spec release)
updates the authorization spec to require MCP clients to specify an appropriate OIDC `application_type`
(`"native"` vs `"web"`) during Dynamic Client Registration, so the authorization server can apply
the matching redirect URI policy and native and web clients do not collide on redirect URI validation rules.

This mirrors the approach taken by the TypeScript SDK (typescript-sdk#2266) and the Python SDK (python-sdk#2784):

- `MCP::Client::OAuth::Discovery.infer_application_type(redirect_uris)` returns `"native"` when every redirect URI
  is a native-app URI (a custom  non-http(s) scheme per RFC 8252 Section 7.1, or an http(s) URI with a loopback host
  per RFC 8252 Section 7.3) and `"web"` otherwise, including for nil, empty, or unparseable input.
  Loopback detection reuses the existing `loopback_host?` helper, so lookalike hosts such as `localhost.example.com`
  or `127.attacker.com` are not treated as native.
- `Flow#ensure_client_registered` now posts the metadata through the new `registration_client_metadata` helper,
  which merges the inferred `application_type` into the DCR request body only when the user did not set
  one explicitly (symbol or string key); an explicit value always wins.

Resolves modelcontextprotocol#375.

## How Has This Been Tested?

New tests in `test/mcp/client/oauth/discovery_test.rb` cover the inference: loopback http URIs (IPv4, IPv6, `localhost`),
custom schemes, https URIs, mixed lists, the `localhost.example.com` lookalike, nil/empty input, and unparseable URIs.

New tests in `test/mcp/client/oauth/flow_test.rb` assert on the actual DCR request body via WebMock `assert_requested`:
loopback redirect URI registers `"application_type": "native"`, an HTTPS redirect URI registers `"web"`,
and an explicit `application_type` (symbol- or string-keyed) is never overridden.

## Breaking Changes

None. The DCR request body gains an `application_type` member only when the user has not specified one;
RFC 7591 requires authorization servers to accept and use known metadata fields, and OIDC-registration servers
already default this field to `"web"` when absent.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SEP-837: Update authorization spec to clarify client type requirements

2 participants