Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Jan 26, 2026

Summary

Adds SDK support required to pass v0.1.11 MCP conformance tests. Six client tests were failing due to missing OAuth features and SSE reconnection support.

Changes Made

OAuth Provider Changes (ClientOAuthProvider.cs)

  • Token endpoint auth methods: Respect token_endpoint_auth_methods_supported from server metadata. Use client_secret_basic (HTTP Basic auth) when supported, fall back to client_secret_post
  • Client credentials grant: Support client_credentials flow for machine-to-machine auth when server advertises it and no redirect delegate is configured
  • Pre-registered credentials: Skip dynamic client registration when both ClientId and ClientSecret are provided
  • Auth failure tracking: Replace _scopeStepUpCount with _repeatedAuthFailureCount to track all auth failures. Counter only resets on successful requests to prevent infinite loops.

SSE Transport Changes (SseClientSessionTransport.cs)

  • Track Last-Event-ID and send it on reconnection attempts
  • Honor server-specified retry intervals
  • Fix off-by-one error in MaxReconnectionAttempts

Test OAuth Server Updates

  • Add support for client_credentials grant type
  • Add support for client_secret_basic auth method (HTTP Basic)
  • Add support for private_key_jwt auth method (JWT assertions)
  • Add pre-registered clients for testing client credentials flows

DNS Rebinding Protection

  • Deleted UseMcpDnsRebindingProtection middleware, extension methods, and tests
  • Use ASP.NET Core's built-in AllowedHosts configuration in ConformanceServer instead

New Tests

  • ClientCredentialsTests.cs with tests for:
    • client_credentials with client_secret_post
    • client_credentials with client_secret_basic
    • Infinite loop prevention when tokens are always rejected

Checklist

  • OAuth token endpoint auth methods support
  • Client credentials grant type support
  • Pre-registered credentials support
  • Auth failure tracking to prevent infinite loops
  • SSE reconnection with Last-Event-ID
  • DNS rebinding protection deleted (use AllowedHosts instead)
  • Test OAuth server updates
  • Client credentials flow tests
Original prompt

This section details on the original issue you should resolve

<issue_title>Add support required for v0.1.11 Client Conformance tests</issue_title>
<issue_description>The v0.1.11 release of the Conformance tests was published a few days ago. The C# SDK is required to pass all the tests in this release to be a "Tier 1" SDK.

I've started work on updating the SDK to run these tests. This work is in this branch:

https://github.com/modelcontextprotocol/csharp-sdk/tree/mdk/client-conformance-v0.1.11

I've managed to get some of the tests passing by fixing the test client, and those fixes are already pushed to the branch. But there are six tests still failing. Copilot believes that all these tests require fixes to the SDK itself to get to passing. Here's the summary from Copilot:

Remaining 6 Failing Tests (require SDK changes):

Test Issue Why Not Fixable with Test Changes
sse-retry Client doesn't send Last-Event-ID header on reconnection Requires SDK transport layer changes
auth/token-endpoint-auth-basic Client uses client_secret_post but should use client_secret_basic SDK doesn't respect token_endpoint_auth_methods_supported
auth/pre-registration Client always tries dynamic registration, ignores pre-registered credentials SDK doesn't support pre-registered client credentials
auth/scope-retry-limit Client doesn't retry authorization with different scopes on 401 SDK needs scope step-up retry logic
auth/client-credentials-jwt Client uses authorization code flow instead of client_credentials SDK doesn't support client_credentials grant type
auth/client-credentials-basic Client uses authorization code flow instead of client_credentials SDK doesn't support client_credentials grant type

The remaining failures all require changes to the SDK's OAuth implementation (in ClientOAuthProvider.cs) to:

  1. Support the client_credentials grant type
  2. Respect token_endpoint_auth_methods_supported
  3. Support pre-registered client credentials
  4. Implement scope step-up retry logic
  5. Send Last-Event-ID header on SSE reconnection</issue_description>

Comments on the Issue (you are @copilot in this section)


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

Copilot AI changed the title [WIP] Add support for v0.1.11 client conformance tests Add support for v0.1.11 client conformance tests Jan 26, 2026
Copilot AI requested a review from stephentoub January 26, 2026 17:07
@stephentoub stephentoub marked this pull request as ready for review January 26, 2026 17:08
@mikekistler
Copy link
Contributor

When I rebase onto the mdk/client-conformance-v0.1.11, which adds support to run all the v0.1.11 tests, I still get 5 errors:

image

@copilot please rebase onto that branch and then fix these and any other errors.

@stephentoub
Copy link
Contributor

@halter73, please pay careful attention to all the auth stuff. That was mostly all copilot.

@stephentoub stephentoub force-pushed the copilot/add-support-v0111-tests branch from 77ee750 to 9deb100 Compare January 29, 2026 02:17
Copy link
Contributor

@halter73 halter73 left a comment

Choose a reason for hiding this comment

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

Please fix the _scopStepUpCount logic to include all redirect loops and write test cases for that and all of the client credential flows.

# Keep version in sync with McpConformanceVersion in Directory.Packages.props
- name: 📦 Install conformance test runner
run: npm install @modelcontextprotocol/conformance@0.1.10
run: npm install @modelcontextprotocol/conformance@0.1.11
Copy link
Contributor

Choose a reason for hiding this comment

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

Should go back to testing against the latest version? I know it will be annoying when it causes random PRs to fail, but we'll definitely notice that way. And the InvalidOperationException we'd get from GetConformanceVersion() when they do fall out of sync should be pretty clear.

Copy link
Contributor

Choose a reason for hiding this comment

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

Ok by me.

Copy link
Contributor

@halter73 halter73 Jan 30, 2026

Choose a reason for hiding this comment

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

Suggested change
run: npm install @modelcontextprotocol/conformance@0.1.11
run: npm install @modelcontextprotocol/conformance

@copilot Also update the message in the InvalidOperationException thrown by GetConformanceVersion() to tell the developer to start pinning the version in ci-build-test.yml and file an issue to update the conformance tests if they run into it.

@halter73
Copy link
Contributor

@stephentoub Given that the client credentials flow stuff is an auth extension (https://github.com/modelcontextprotocol/ext-auth/pull/3/changes), what do we think about only supporting it via a DelegatingHandler?

I think this is more similar to what the TS SDK does with https://github.com/modelcontextprotocol/typescript-sdk/blob/b0ef89ffaf6db8b3c52cd8919e8949b0f1da9ca4/packages/client/src/client/auth.ts for the mainline authorization code and then forces you to manually call createPrivateKeyJwtAuth from https://github.com/modelcontextprotocol/typescript-sdk/blob/b0ef89ffaf6db8b3c52cd8919e8949b0f1da9ca4/packages/client/src/client/authExtensions.ts if you want to do the client credentials flow. I like it because it puts the more niche, arguably less secure, use case less in your face.

…ing protection, add client credentials tests

- Replace _scopeStepUpCount with _repeatedAuthFailureCount to track all auth failures
- Reset counter only on successful requests to prevent infinite loops
- Replace custom DNS rebinding middleware with AllowedHosts configuration
- Add client_credentials grant support to TestOAuthServer with basic auth and post methods
- Add ClientCredentialsTests with infinite loop prevention test
- Fix off-by-one error in MaxReconnectionAttempts

Co-authored-by: halter73 <54385+halter73@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Jan 29, 2026

Please fix the _scopStepUpCount logic to include all redirect loops and write test cases for that and all of the client credential flows.

Fixed in 919ff3e. Replaced _scopeStepUpCount with _repeatedAuthFailureCount that tracks all auth failures (401 and 403). The counter now only resets on successful requests to prevent infinite loops in all scenarios. Added test DoesNotLoopIndefinitely_WhenTokensAlwaysRejected that verifies the client throws McpException after max retries when the server always rejects tokens. Also added client credentials flow tests for client_secret_post and client_secret_basic.

Copilot AI requested a review from halter73 January 29, 2026 21:05
Remove the DNS rebinding protection middleware, extension methods,
and tests as requested. The ConformanceServer now uses the built-in
AllowedHosts configuration instead.

Co-authored-by: halter73 <54385+halter73@users.noreply.github.com>
Copilot AI requested a review from halter73 January 29, 2026 21:24
@stephentoub
Copy link
Contributor

what do we think about only supporting it via a DelegatingHandler?

Can you elaborate?

@halter73
Copy link
Contributor

The idea is that we'd provide a OAuthJwtClientCredentialsDelgatingHandler with constructor parameters for not just the algorithm and the key but also optionally the audience and extra JWT claims. This is for scenarios where the MCP client has prior knowledge with the OAuth server and is already a pre-registered client, so it's probably not best to assume the issuer from the metadata document is necessarily the right audience even though it is a good default. Basically, we'd take a similar set of params that the TS SDK has in createPrivateKeyJwtAuth plus the client ID.

Similarly, we'd provide an OAuthBasicClientCredentialsDelegatingHandler that just takes the client ID and client secret like the TS SDK ClientCredentialsProvider. Most of the ClientOAuthOptions like the AuthorizationRedirectDelegate, AuthServerSelector, AdditionalAuthorizationParameters, RedirectUri, Scopes, etc... make no sense given a client credential flow, so it's best to avoid the ClientOAuthProvider in this case as possible.

I know that by not implementing the ClientOAuthProvider as a DelegatingHandler but instead a McpHttpClient that takes the JsonRpcMessage we send over the request body (if any) as an explicit parameter allowed us to safely replay requests. We could consider making McpHttpClient public and make our custom OAuth handlers for client credentials derive from that.

private string? _clientSecret;
private ITokenCache _tokenCache;
private AuthorizationServerMetadata? _authServerMetadata;
private int _repeatedAuthFailureCount;
Copy link
Contributor

Choose a reason for hiding this comment

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

@stephentoub I don't think this is really thread-safe or safe against interleaved async requests for that matter. There can be multiple concurrent tool calls and the like. Would it be worth shoving the retry count into the HttpRequestMessage?

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.

Add support required for v0.1.11 Client Conformance tests

4 participants