diff --git a/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs b/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs index 30854dcdf..4e7cf77c5 100644 --- a/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs +++ b/src/ModelContextProtocol.Core/Authentication/ClientOAuthProvider.cs @@ -640,7 +640,11 @@ private static Uri GetRequiredResourceUri(ProtectedResourceMetadata protectedRes private string? GetScopeParameter(ProtectedResourceMetadata protectedResourceMetadata) { - if (!string.IsNullOrEmpty(protectedResourceMetadata.WwwAuthenticateScope)) + if (_configuredScopes is not null) + { + return _configuredScopes; + } + else if (!string.IsNullOrEmpty(protectedResourceMetadata.WwwAuthenticateScope)) { return protectedResourceMetadata.WwwAuthenticateScope; } @@ -648,8 +652,10 @@ private static Uri GetRequiredResourceUri(ProtectedResourceMetadata protectedRes { return string.Join(" ", protectedResourceMetadata.ScopesSupported); } - - return _configuredScopes; + else + { + return null; + } } /// diff --git a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthTests.cs b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthTests.cs index be831d523..be66d8b18 100644 --- a/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthTests.cs +++ b/tests/ModelContextProtocol.AspNetCore.Tests/OAuth/AuthTests.cs @@ -501,6 +501,42 @@ public async Task AuthorizationFlow_UsesScopeFromForbiddenHeader() Assert.Equal(adminScopes, requestedScope); } + [Fact] + public async Task AuthorizationFlow_UsesScopeFromClientOAuthOptions() + { + Builder.Services.Configure(McpAuthenticationDefaults.AuthenticationScheme, options => + { + options.ResourceMetadata!.ScopesSupported = ["mcp:tools", "files:read"]; + }); + + await using var app = await StartMcpServerAsync(); + + string? requestedScope = null; + + await using var transport = new HttpClientTransport(new() + { + Endpoint = new(McpServerUrl), + OAuth = new() + { + ClientId = "demo-client", + ClientSecret = "demo-secret", + RedirectUri = new Uri("http://localhost:1179/callback"), + Scopes = ["mcp:tools"], + AuthorizationRedirectDelegate = (uri, redirect, ct) => + { + var query = QueryHelpers.ParseQuery(uri.Query); + requestedScope = query["scope"].ToString(); + return HandleAuthorizationUrlAsync(uri, redirect, ct); + }, + }, + }, HttpClient, LoggerFactory); + + await using var client = await McpClient.CreateAsync( + transport, loggerFactory: LoggerFactory, cancellationToken: TestContext.Current.CancellationToken); + + Assert.Equal("mcp:tools", requestedScope); + } + [Fact] public async Task AuthorizationFails_WhenResourceMetadataPortDiffers() {