Skip to content

Add application_type to the Dynamic Client Registration request#1613

Open
jayaraman-venkatesan wants to merge 7 commits into
modelcontextprotocol:mainfrom
jayaraman-venkatesan:feature/sep-837-application-type
Open

Add application_type to the Dynamic Client Registration request#1613
jayaraman-venkatesan wants to merge 7 commits into
modelcontextprotocol:mainfrom
jayaraman-venkatesan:feature/sep-837-application-type

Conversation

@jayaraman-venkatesan

@jayaraman-venkatesan jayaraman-venkatesan commented May 29, 2026

Copy link
Copy Markdown
Contributor

Fixes #1545

Implements SEP-837 — adds application_type to the Dynamic Client Registration request when the C# SDK registers against an OIDC-flavored authorization server.

Summary

Without application_type, an OIDC AS applies its spec-mandated default. This PR makes the SDK supply the correct value.

What happens in the changes

When the caller sets DynamicClientRegistrationOptions.ApplicationType explicitly, that value is sent unchanged. Otherwise, the SDK infers the value from the redirect URI immediately before Dynamic Client Registration is performed.

What changed

src/ModelContextProtocol.Core/Authentication/

  • DynamicClientRegistrationRequest.cs — adds the application_type field on the wire DTO.
  • DynamicClientRegistrationOptions.cs — adds the ApplicationType setter so callers can opt out of inference and force a specific value.
  • ClientOAuthProvider.cs — resolves the application type only when Dynamic Client Registration is selected:
    • Uses the explicit value from options when configured.
    • Otherwise calls a private static InferApplicationType(Uri redirectUri) helper.
    • Uses the resolved value to construct the DCR request and report DCR rejection context.

tests/ModelContextProtocol.Tests/Authentication/ClientOAuthProviderApplicationTypeTests.cs (new)

  • Verifies construction defers application-type validation until Dynamic Client Registration is selected.

Contract changes

  • New nullable property on DynamicClientRegistrationOptions: ApplicationType { get; set; }. Backwards-compatible — existing callers default to null and now get an inferred value where they previously got nothing on the wire.
  • Explicit values are authoritative: callers can override URI inference to accommodate authorization-server-specific requirements or retry a rejected registration with an adjusted application type.
  • DCR-only resolution: static-client and successful-CIMD flows do not resolve or validate unused DCR settings.

Test plan

  • dotnet build — 0 warnings, 0 errors.
  • Focused OAuth integration tests across net8.0, net9.0, and net10.0.
  • Covers inferred native, explicit web override, DCR failure/retry, and static-client/CIMD flows with unused DCR settings.

@jayaraman-venkatesan jayaraman-venkatesan changed the title feature/sep-837-application-type: adds application_type to the Dynamic Client Registration request Add application_type to the Dynamic Client Registration request May 29, 2026
@jayaraman-venkatesan
jayaraman-venkatesan force-pushed the feature/sep-837-application-type branch from 5063493 to cd9ba60 Compare May 29, 2026 21:49
@jayaraman-venkatesan

Copy link
Copy Markdown
Contributor Author

@mikekistler - can you please help reviewing this PR

mikekistler
mikekistler previously approved these changes May 31, 2026

@mikekistler mikekistler left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good! 👍

Thank you for this contribution!

@jayaraman-venkatesan

Copy link
Copy Markdown
Contributor Author

@mikekistler
If you are good with the changes can you help merging this? I don't have write access yet to do that.

@jeffhandley jeffhandley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for getting this together, @jayaraman-venkatesan.

Before we merge, SEP-837's normative language ("MCP clients MUST be prepared to handle registration failures…", "SHOULD surface a meaningful error", "MAY retry with adjusted application_type or redirect URIs") is aimed at MCP clients. As the C# SDK those clients are built on, we don't have to implement the surfacing or retry behavior ourselves, but we do need to make sure a developer using the SDK is able to do those things, and we should prove it with tests in this PR before we close out #1545.

Two test scenarios I'd like added here:

  1. DCR failure is recoverable from the consumer's perspective. When an OIDC AS rejects the DCR call (e.g. 400 invalid_redirect_uri), the failure should propagate to the SDK consumer with enough context: the HTTP status, the AS error body, and ideally the application_type / redirect_uri the SDK actually sent; so the consumer can produce a meaningful error. Please add a negative test that mocks an OIDC AS rejecting registration and asserts the thrown exception (or returned result) carries that information.
  2. A consumer can retry registration with adjusted parameters. The SDK's resolved ApplicationType is fixed in the ClientOAuthProvider constructor today, so a retry implies the consumer constructing a new provider with a different ApplicationType (or different redirect URI). Please add a test that does exactly that: first DCR attempt rejected, second attempt succeeds after swapping ApplicationType; to (a) prove the surface supports the MAY behavior and (b) catch any subtle state-carryover bugs.

One related point worth thinking about while you're in here: the synchronous ArgumentException on conflict (e.g. "web" + localhost) is a nice guardrail, but it also blocks a consumer from retrying with a combination the AS happens to require; for example, if an AS demanded "web" paired with a localhost redirect, the SDK would refuse to even attempt that registration. Probably fine to leave the behavior as-is, but worth a sentence in the xmldoc noting that consumers who need that flexibility must set ApplicationType explicitly and that the inference will not override it. Up to you.

…ble and retryable and enrich the DCR-failure McpException with the application_type and redirect_uri the

  SDK sent
@jayaraman-venkatesan

jayaraman-venkatesan commented Jun 9, 2026

Copy link
Copy Markdown
Contributor Author

Thanks @jeffhandley, pushed 2643b0b addressing both test scenarios

  1. DCR failure is recoverable.
    Added DcrFailureTests.DcrRejection_PropagatesToConsumer_WithStatusBodyAndSentParameters: Asserts the surfaced McpException carries the HTTP status, the AS error body, and the application_type the SDK sent. To make the last part possible, the DCR-failure throw in ClientOAuthProvider now appends the sent application_type/redirect_uri (status + body were already included).

  2. Retry with adjusted parameters.
    Added ConsumerCanRetryRegistration_WithAdjustedRedirectUri_AfterRejection: proving the MAY-retry surface. TestOAuthServer now captures LastApplicationType so the retry's wire value is assertable.

The failure is build (windows-latest, Release), I suppose is pre-existing flake in McpServerBuilderExtensionsMessageFilterTests, a re-run should clear it, please help kick one off when you get a chance. Thanks!

@jeffhandley jeffhandley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for your patience on this, @jayaraman-venkatesan, and for adding those tests as requested--they fill in that coverage gap well. I have another round of feedback but it looks really close. I hope you don't mind, but since I had a delay getting back to this review I am going to proceed with pushing a commit that addresses this feedback directly.

  1. DCR-only validation runs even when DCR is bypassed. ResolveApplicationType runs in the provider constructor, so a static-client or successful-CIMD configuration can fail because of an unused DCR ApplicationType mismatch. DynamicClientRegistrationOptions is documented as applying only when no ClientId is configured. Please resolve/validate immediately before constructing the DCR request, or otherwise gate it on the DCR path.

  2. An explicit application type cannot override the heuristic. The resolver rejects an explicit value that differs from URI inference. SEP-837 makes the native/web classification SHOULD-level guidance and allows retrying with an adjusted application_type; the other Tier 1 SDKs preserve a configured value and infer only when it is absent. Please treat an explicit value as authoritative and use inference only as the default.

jeffhandley and others added 3 commits July 18, 2026 14:12
Defer application type validation until dynamic registration is selected, so static-client and CIMD flows ignore unused DCR settings.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Use explicit application types as configured and infer a value only when no override is supplied.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>

@jeffhandley jeffhandley left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is now good with me and Copilot-assisted deep review of the SEP vs. the implementation confirms the SEP to be fully satisfied.

@halter73 I'd like a review from you on this too before we merge for the 2.0.0 release.

@jeffhandley
jeffhandley requested review from halter73 and removed request for mikekistler July 18, 2026 21:51
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

3 participants