Skip to content
Closed
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions .changeset/sep-837-application-type.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
---
'@modelcontextprotocol/client': minor
'@modelcontextprotocol/core': patch
---

Support `application_type` client metadata with native/web inference for dynamic client registration (SEP-837)

Per the MCP authorization specification, clients MUST specify an appropriate `application_type` when registering dynamically: OIDC-based authorization servers default the field to `'web'`, which conflicts with native/loopback redirect URIs and can cause registration to fail.

- `OAuthClientMetadataSchema` (and therefore `OAuthClientInformationFullSchema`) now includes an optional `application_type` field, so user-supplied values are no longer stripped from registration requests or responses.
- `registerClient()` infers `application_type` when it is absent from the provided metadata: `'native'` if every redirect URI is an HTTP loopback URI (`localhost`, `127.0.0.1`, `[::1]`) or uses a custom non-http(s) scheme, otherwise `'web'`. An explicitly provided value is never overridden.

Check failure on line 11 in .changeset/sep-837-application-type.md

View check run for this annotation

Claude / Claude Code Review

Changeset/JSDoc describe application_type inference behavior the shipped code doesn't implement

The changeset and the new JSDoc on `OAuthClientProvider.clientMetadata` describe an `application_type` inference the shipped code doesn't implement: the prose says `registerClient()` infers `'native'` when *every* redirect URI is an *HTTP* loopback URI, but the actual inference lives in `deriveApplicationType()`/`resolveClientMetadata()` (called only from `auth()`), returns `'native'` as soon as *any* redirect URI is loopback or custom-scheme, and also treats HTTPS loopback as native — the http-
Comment thread
mattzcarey marked this conversation as resolved.
Resolved
6 changes: 6 additions & 0 deletions packages/client/src/client/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,12 @@ export interface OAuthClientProvider {

/**
* Metadata about this OAuth client.
*
* Per the MCP authorization specification (SEP-837), clients MUST specify an
* appropriate `application_type` when registering dynamically: `'native'` for
* desktop/CLI apps using loopback or custom-scheme redirect URIs, `'web'` for
* remote browser-based apps. If `application_type` is omitted, {@linkcode registerClient}
* infers it from `redirect_uris`.
*/
get clientMetadata(): OAuthClientMetadata;

Expand Down
28 changes: 19 additions & 9 deletions packages/core-internal/src/shared/auth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -183,18 +183,28 @@ export const OptionalSafeUrlSchema = SafeUrlSchema.optional().or(z.literal('').t
export const OAuthClientMetadataSchema = z
.object({
redirect_uris: z.array(SafeUrlSchema),
token_endpoint_auth_method: z.string().optional(),
grant_types: z.array(z.string()).optional(),
response_types: z.array(z.string()).optional(),
/**
* OIDC Dynamic Client Registration `application_type`. MCP clients MUST set
* this to `'native'` or `'web'` when registering (SEP-837); the SDK defaults
* it from `redirect_uris` when omitted. Typed as `string` (not an enum) so
* that parsing an authorization server's registration response — which under
* RFC 7591 may echo extension values — never rejects the document on this
* field alone.
* OpenID Connect Dynamic Client Registration `application_type`.
*
* The standard values are `'web'` and `'native'`. OIDC-based authorization
* servers default this to `'web'` when omitted, which conflicts with
* native/loopback redirect URIs (e.g. `http://localhost`, `http://127.0.0.1`,
* or custom URI schemes) and can cause registration to fail. Per the MCP
* authorization specification (SEP-837), clients MUST specify an appropriate
* `application_type` when registering: native apps (desktop, CLI, anything
* using loopback or custom-scheme redirects) SHOULD use `'native'`, while
* remote browser-based apps SHOULD use `'web'`. Authorization servers that
* do not implement OIDC registration ignore this field.
*
* Typed as a plain string because OIDC permits extension values beyond
* `'web'` and `'native'`.
*
* @see https://openid.net/specs/openid-connect-registration-1_0.html#ClientMetadata
*/
application_type: z.string().optional(),
token_endpoint_auth_method: z.string().optional(),
grant_types: z.array(z.string()).optional(),
response_types: z.array(z.string()).optional(),
client_name: z.string().optional(),
client_uri: SafeUrlSchema.optional(),
logo_uri: OptionalSafeUrlSchema,
Expand Down
Loading