Skip to content

Commit 79f5aa8

Browse files
committed
Remove and rename DynamicClientRegistrationDelegate
- Make client_name optional since it's only RECOMMENDED by https://www.rfc-editor.org/rfc/rfc7591
1 parent 0da592d commit 79f5aa8

5 files changed

Lines changed: 18 additions & 53 deletions

File tree

src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs

Lines changed: 15 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
using Microsoft.Extensions.Logging;
22
using Microsoft.Extensions.Logging.Abstractions;
3-
using System.Collections.Specialized;
43
using System.Diagnostics.CodeAnalysis;
54
using System.Net.Http.Headers;
65
using System.Security.Cryptography;
@@ -28,12 +27,12 @@ internal sealed partial class ClientOAuthProvider
2827
private readonly IDictionary<string, string> _additionalAuthorizationParameters;
2928
private readonly Func<IReadOnlyList<Uri>, Uri?> _authServerSelector;
3029
private readonly AuthorizationRedirectDelegate _authorizationRedirectDelegate;
31-
private readonly DynamicClientRegistrationDelegate? _dynamicClientRegistrationDelegate;
3230

33-
// _clientName, _clientUri, and _initialAccessToken is used for dynamic client registration (RFC 7591)
34-
private readonly string? _clientName;
35-
private readonly Uri? _clientUri;
36-
private readonly string? _initialAccessToken;
31+
// _dcrClientName, _dcrClientUri, _dcrInitialAccessToken and _dcrResponseDelegate are used for dynamic client registration (RFC 7591)
32+
private readonly string? _dcrClientName;
33+
private readonly Uri? _dcrClientUri;
34+
private readonly string? _dcrInitialAccessToken;
35+
private readonly Func<DynamicClientRegistrationResponse, CancellationToken, Task>? _dcrResponseDelegate;
3736

3837
private readonly HttpClient _httpClient;
3938
private readonly ILogger _logger;
@@ -79,20 +78,10 @@ public ClientOAuthProvider(
7978
// Set up authorization URL handler (use default if not provided)
8079
_authorizationRedirectDelegate = options.AuthorizationRedirectDelegate ?? DefaultAuthorizationUrlHandler;
8180

82-
if (string.IsNullOrEmpty(_clientId))
83-
{
84-
if (options.DynamicClientRegistration is null)
85-
{
86-
throw new ArgumentException("ClientOAuthOptions.DynamicClientRegistration must be configured when ClientId is not set.", nameof(options));
87-
}
88-
89-
_clientName = options.DynamicClientRegistration.ClientName;
90-
_clientUri = options.DynamicClientRegistration.ClientUri;
91-
_initialAccessToken = options.DynamicClientRegistration.InitialAccessToken;
92-
93-
// Set up dynamic client registration delegate
94-
_dynamicClientRegistrationDelegate = options.DynamicClientRegistration.DynamicClientRegistrationDelegate;
95-
}
81+
_dcrClientName = options.DynamicClientRegistration?.ClientName;
82+
_dcrClientUri = options.DynamicClientRegistration?.ClientUri;
83+
_dcrInitialAccessToken = options.DynamicClientRegistration?.InitialAccessToken;
84+
_dcrResponseDelegate = options.DynamicClientRegistration?.ResponseDelegate;
9685
}
9786

9887
/// <summary>
@@ -463,8 +452,8 @@ private async Task PerformDynamicClientRegistrationAsync(
463452
GrantTypes = ["authorization_code", "refresh_token"],
464453
ResponseTypes = ["code"],
465454
TokenEndpointAuthMethod = "client_secret_post",
466-
ClientName = _clientName,
467-
ClientUri = _clientUri?.ToString(),
455+
ClientName = _dcrClientName,
456+
ClientUri = _dcrClientUri?.ToString(),
468457
Scope = _scopes is not null ? string.Join(" ", _scopes) : null
469458
};
470459

@@ -476,9 +465,9 @@ private async Task PerformDynamicClientRegistrationAsync(
476465
Content = requestContent
477466
};
478467

479-
if (!string.IsNullOrEmpty(_initialAccessToken))
468+
if (!string.IsNullOrEmpty(_dcrInitialAccessToken))
480469
{
481-
request.Headers.Authorization = new AuthenticationHeaderValue(BearerScheme, _initialAccessToken);
470+
request.Headers.Authorization = new AuthenticationHeaderValue(BearerScheme, _dcrInitialAccessToken);
482471
}
483472

484473
using var httpResponse = await _httpClient.SendAsync(request, cancellationToken).ConfigureAwait(false);
@@ -509,9 +498,9 @@ private async Task PerformDynamicClientRegistrationAsync(
509498

510499
LogDynamicClientRegistrationSuccessful(_clientId!);
511500

512-
if (_dynamicClientRegistrationDelegate is not null)
501+
if (_dcrResponseDelegate is not null)
513502
{
514-
await _dynamicClientRegistrationDelegate(registrationResponse, cancellationToken).ConfigureAwait(false);
503+
await _dcrResponseDelegate(registrationResponse, cancellationToken).ConfigureAwait(false);
515504
}
516505
}
517506

src/ModelContextProtocol.Core/Authentication/DynamicClientRegistrationDelegate.cs

Lines changed: 0 additions & 13 deletions
This file was deleted.

src/ModelContextProtocol.Core/Authentication/DynamicClientRegistrationOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ public sealed class DynamicClientRegistrationOptions
1111
/// <remarks>
1212
/// This is a human-readable name for the client that may be displayed to users during authorization.
1313
/// </remarks>
14-
public required string ClientName { get; set; }
14+
public string? ClientName { get; set; }
1515

1616
/// <summary>
1717
/// Gets or sets the client URI to use during dynamic client registration.
@@ -45,5 +45,5 @@ public sealed class DynamicClientRegistrationOptions
4545
/// The implementation should save the client credentials securely for future use.
4646
/// </para>
4747
/// </remarks>
48-
public DynamicClientRegistrationDelegate? DynamicClientRegistrationDelegate { get; set; }
48+
public Func<DynamicClientRegistrationResponse, CancellationToken, Task>? ResponseDelegate { get; set; }
4949
}

tests/ModelContextProtocol.AspNetCore.Tests/AuthEventTests.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,7 +155,7 @@ public async Task CanAuthenticate_WithDynamicClientRegistration_FromEvent()
155155
{
156156
ClientName = "Test MCP Client",
157157
ClientUri = new Uri("https://example.com"),
158-
DynamicClientRegistrationDelegate = (response, cancellationToken) =>
158+
ResponseDelegate = (response, cancellationToken) =>
159159
{
160160
dcrResponse = response;
161161
return Task.CompletedTask;

tests/ModelContextProtocol.AspNetCore.Tests/AuthTests.cs

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,6 @@ public async Task CanAuthenticate_WithDynamicClientRegistration()
174174

175175
await app.StartAsync(TestContext.Current.CancellationToken);
176176

177-
DynamicClientRegistrationResponse? dcrResponse = null;
178-
179177
await using var transport = new SseClientTransport(new()
180178
{
181179
Endpoint = new(McpServerUrl),
@@ -188,21 +186,12 @@ public async Task CanAuthenticate_WithDynamicClientRegistration()
188186
{
189187
ClientName = "Test MCP Client",
190188
ClientUri = new Uri("https://example.com"),
191-
DynamicClientRegistrationDelegate = (response, cancellationToken) =>
192-
{
193-
dcrResponse = response;
194-
return Task.CompletedTask;
195-
},
196189
},
197190
},
198191
}, HttpClient, LoggerFactory);
199192

200193
await using var client = await McpClientFactory.CreateAsync(
201194
transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken);
202-
203-
Assert.NotNull(dcrResponse);
204-
Assert.False(string.IsNullOrEmpty(dcrResponse.ClientId));
205-
Assert.False(string.IsNullOrEmpty(dcrResponse.ClientSecret));
206195
}
207196

208197
[Fact]

0 commit comments

Comments
 (0)