Add ScopeSelectorDelegate to enhance OAuth options for scope filtering (#1596)

This commit is contained in:
Manuel Naujoks 2026-05-27 00:23:52 +02:00 • committed by GitHub
commit fd1ac08925
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -28,6 +28,7 @@ internal sealed partial class ClientOAuthProvider : McpHttpClient
private readonly Uri _serverUrl;
private readonly Uri _redirectUri;
private readonly string? _configuredScopes;
private readonly ScopeSelectorDelegate? _scopeSelector;
private readonly IDictionary<string, string> _additionalAuthorizationParameters;
private readonly Func<IReadOnlyList<Uri>, Uri?> _authServerSelector;
private readonly AuthorizationRedirectDelegate _authorizationRedirectDelegate;
@ -76,6 +77,7 @@ internal sealed partial class ClientOAuthProvider : McpHttpClient
_clientSecret = options.ClientSecret;
_redirectUri = options.RedirectUri ?? throw new ArgumentException("ClientOAuthOptions.RedirectUri must configured.", nameof(options));
_configuredScopes = options.Scopes is null ? null : string.Join(" ", options.Scopes);
_scopeSelector = options.ScopeSelector;
_additionalAuthorizationParameters = options.AdditionalAuthorizationParameters;
_clientMetadataDocumentUri = options.ClientMetadataDocumentUri;
@ -491,8 +493,7 @@ internal sealed partial class ClientOAuthProvider : McpHttpClient
queryParamsDictionary["resource"] = resourceUri;
}
var scope = GetScopeParameter(protectedResourceMetadata);
scope = AugmentScopeWithOfflineAccess(scope, authServerMetadata);
var scope = ComputeEffectiveScope(protectedResourceMetadata, authServerMetadata);
if (!string.IsNullOrEmpty(scope))
{
queryParamsDictionary["scope"] = scope!;
@ -654,7 +655,7 @@ internal sealed partial class ClientOAuthProvider : McpHttpClient
TokenEndpointAuthMethod = "client_secret_post",
ClientName = _dcrClientName,
ClientUri = _dcrClientUri?.ToString(),
Scope = GetScopeParameter(protectedResourceMetadata),
Scope = ComputeEffectiveScope(protectedResourceMetadata, authServerMetadata),
};
var requestBytes = JsonSerializer.SerializeToUtf8Bytes(registrationRequest, McpJsonUtilities.JsonContext.Default.DynamicClientRegistrationRequest);
@ -713,6 +714,20 @@ internal sealed partial class ClientOAuthProvider : McpHttpClient
private static string? GetResourceUri(ProtectedResourceMetadata protectedResourceMetadata)
=> protectedResourceMetadata.Resource;
private string? ComputeEffectiveScope(
ProtectedResourceMetadata protectedResourceMetadata,
AuthorizationServerMetadata authServerMetadata)
{
var scope = GetScopeParameter(protectedResourceMetadata);
scope = AugmentScopeWithOfflineAccess(scope, authServerMetadata);
if (_scopeSelector is not null)
{
var selected = _scopeSelector(scope?.Split(' '));
scope = selected is not null ? string.Join(" ", selected) : null;
}
return scope;
}
private string? GetScopeParameter(ProtectedResourceMetadata protectedResourceMetadata)
{
if (!string.IsNullOrEmpty(protectedResourceMetadata.WwwAuthenticateScope))