Skip to content

feat(client,core): application_type client metadata with native/web inference (SEP-837)#2266

Open
mattzcarey wants to merge 2 commits into
mainfrom
feat/sep-837-application-type
Open

feat(client,core): application_type client metadata with native/web inference (SEP-837)#2266
mattzcarey wants to merge 2 commits into
mainfrom
feat/sep-837-application-type

Conversation

@mattzcarey

@mattzcarey mattzcarey commented Jun 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Implements SEP-837 (clarify client type requirements) for dynamic client registration. The draft authorization spec, basic/authorization/client-registration.mdx § "Application Type and Redirect URI Constraints", is MUST-level:

Clients MUST specify an appropriate application_type during dynamic client registration. OIDC-based registries default the field to "web", which conflicts with native/loopback redirect URIs; authorization servers that do not implement OIDC registration ignore the field. Native applications (desktop, CLI, loopback redirects) SHOULD register with "native"; remote browser-based applications SHOULD use "web".

Previously the SDK made compliance impossible: OAuthClientMetadataSchema uses .strip() and had no application_type, so any user-supplied value was silently dropped from DCR request bodies, and OAuthClientInformationFullSchema stripped it from registration responses.

What changed

  • @modelcontextprotocol/core (packages/core/src/shared/auth.ts): OAuthClientMetadataSchema gains optional application_type (typed z.string() because OIDC permits extension values beyond 'web'/'native'; JSDoc documents the standard values and SEP-837 semantics). Since OAuthClientInformationFullSchema merges the metadata schema, the field now also survives DCR response parsing.
  • @modelcontextprotocol/client (packages/client/src/client/auth.ts): registerClient() infers application_type when it is absent from the provided metadata: 'native' if every redirect_uris entry is loopback (localhost, 127.0.0.1, [::1]) or a custom non-http(s) scheme; otherwise 'web'. The rule lives in a new exported helper inferApplicationType(redirectUris). Empty/unparseable inputs conservatively yield 'web' (the OIDC default).
  • JSDoc on OAuthClientProvider.clientMetadata and a short note in docs/client.md.
  • Tests: request-body round-trip, response parse retention, and inference cases (loopback-only → native, custom scheme → native, https → web, mixed → web, localhost.example.com is not loopback, explicit value never overridden).
  • Changeset: client minor (new export + behavior), core patch (additive optional schema field).

Design choice for maintainers

Inference only applies when the field is absent — an explicitly provided application_type is never overridden. Happy to drop the inference entirely and make this docs-only (schema field + JSDoc) if you'd prefer registration bodies stay byte-for-byte what the provider supplies.

Validation

  • pnpm build:all, pnpm typecheck:all, pnpm lint:all — clean
  • @modelcontextprotocol/client tests: 379/379 pass (11 files)
  • @modelcontextprotocol/core tests: 463/463 pass (22 files)
  • Client conformance suite (pnpm run test:conformance:client:all): the 13 scenarios that failed only on the SEP-837 application_type DCR check now pass, so they are removed from test/conformance/expected-failures.yaml (the runner fails on stale entries). auth/scope-step-up stays in the baseline for an unrelated SEP-2350 scope-union WARNING.

Downstream impact: cloudflare/agents' DurableObjectOAuthClientProvider uses remote https redirect URLs on Workers → inferred 'web', which is correct; no changes needed downstream.

Closes #2198

…nference (SEP-837)

- Add optional application_type to OAuthClientMetadataSchema (and thus
  OAuthClientInformationFullSchema) so user-supplied values survive DCR
  request bodies and response parsing.
- registerClient() infers application_type when absent: 'native' if every
  redirect URI is loopback (localhost, 127.0.0.1, [::1]) or a custom
  non-http(s) scheme, otherwise 'web'. Explicit values are never overridden.
- New inferApplicationType(redirectUris) export.
- JSDoc on OAuthClientProvider.clientMetadata + docs/client.md note.

Closes #2198
@mattzcarey mattzcarey requested a review from a team as a code owner June 9, 2026 20:35
@changeset-bot

changeset-bot Bot commented Jun 9, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 7f811c4

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 2 packages
Name Type
@modelcontextprotocol/client Minor
@modelcontextprotocol/core Patch

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@pkg-pr-new

pkg-pr-new Bot commented Jun 9, 2026

Copy link
Copy Markdown

Open in StackBlitz

@modelcontextprotocol/client

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/client@2266

@modelcontextprotocol/codemod

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/codemod@2266

@modelcontextprotocol/server

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server@2266

@modelcontextprotocol/server-legacy

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/server-legacy@2266

@modelcontextprotocol/express

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/express@2266

@modelcontextprotocol/fastify

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/fastify@2266

@modelcontextprotocol/hono

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/hono@2266

@modelcontextprotocol/node

npm i https://pkg.pr.new/modelcontextprotocol/typescript-sdk/@modelcontextprotocol/node@2266

commit: 7f811c4

…ted-failures baseline

The application_type implementation makes the 13 scenarios that failed only
on the SEP-837 DCR checks pass, and the conformance runner fails on stale
baseline entries. auth/scope-step-up stays: it still emits a SEP-2350
WARNING (scope union on re-authorization), which the evaluator counts as a
failure.
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.

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

1 participant