Skip to content

Commit 6e23f4a

Browse files
committed
Placeholder setup
1 parent 008f521 commit 6e23f4a

File tree

5 files changed

+67
-74
lines changed

5 files changed

+67
-74
lines changed

samples/ProtectedMCPServer/Program.cs

Lines changed: 38 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,46 @@
11
using Microsoft.AspNetCore.Authentication;
22
using Microsoft.Extensions.Options;
3+
using ModelContextProtocol.AspNetCore.Auth;
34
using ModelContextProtocol.Protocol.Types;
45
using System.Security.Claims;
56
using System.Text.Encodings.Web;
67

78
var builder = WebApplication.CreateBuilder(args);
89

10+
// Configure authentication to use MCP for challenges
11+
builder.Services.AddAuthentication(options =>
12+
{
13+
options.DefaultScheme = "Bearer";
14+
options.DefaultChallengeScheme = McpAuthenticationDefaults.AuthenticationScheme; // Use MCP for challenges
15+
})
16+
.AddScheme<AuthenticationSchemeOptions, SimpleAuthHandler>("Bearer", options => { })
17+
.AddMcp(options => {
18+
// Configure MCP authentication options with the resource metadata URI
19+
options.ResourceMetadataUri = new Uri("/.well-known/oauth-protected-resource", UriKind.Relative);
20+
21+
// Configure the resource metadata using our enhanced options
22+
options.ResourceMetadata.Resource = new Uri("http://localhost:7071");
23+
options.ResourceMetadata.AuthorizationServers.Add(new Uri("https://login.microsoftonline.com/a2213e1c-e51e-4304-9a0d-effe57f31655/v2.0"));
24+
options.ResourceMetadata.BearerMethodsSupported.Add("header");
25+
options.ResourceMetadata.ScopesSupported.AddRange(["weather.read", "weather.write"]);
26+
options.ResourceMetadata.ResourceDocumentation = new Uri("https://docs.example.com/api/weather");
27+
});
28+
29+
// Add authorization services
30+
builder.Services.AddAuthorization(options =>
31+
{
32+
options.AddPolicy(McpAuthenticationDefaults.AuthenticationScheme, policy =>
33+
{
34+
policy.RequireAuthenticatedUser();
35+
});
36+
});
37+
38+
// Don't forget to register the ResourceMetadataService
39+
builder.Services.AddSingleton<ResourceMetadataService>();
40+
41+
// IMPORTANT: Register the McpAuthorizationMarker to enable authorization on MCP endpoints
42+
builder.Services.AddSingleton<McpAuthorizationMarker>();
43+
944
// Configure MCP Server
1045
builder.Services.AddMcpServer(options =>
1146
{
@@ -64,16 +99,7 @@
6499
}
65100
};
66101
})
67-
.WithHttpTransport()
68-
.WithAuthorization(metadata =>
69-
{
70-
metadata.AuthorizationServers.Add(new Uri("https://login.microsoftonline.com/a2213e1c-e51e-4304-9a0d-effe57f31655/v2.0"));
71-
metadata.BearerMethodsSupported.Add("header");
72-
metadata.ScopesSupported.AddRange(["weather.read", "weather.write"]);
73-
74-
// Add optional documentation
75-
metadata.ResourceDocumentation = new Uri("https://docs.example.com/api/weather");
76-
});
102+
.WithHttpTransport();
77103

78104
var app = builder.Build();
79105

@@ -151,8 +177,6 @@ protected override Task<AuthenticateResult> HandleAuthenticateAsync()
151177
return Task.FromResult(AuthenticateResult.Success(ticket));
152178
}
153179

154-
protected override Task HandleChallengeAsync(AuthenticationProperties properties)
155-
{
156-
return base.HandleChallengeAsync(properties);
157-
}
180+
// The MCP authentication handler will handle challenges
181+
// so we don't need to implement HandleChallengeAsync here
158182
}

src/ModelContextProtocol.AspNetCore/Auth/McpAuthenticationHandler.cs

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,25 @@ protected override Task HandleChallengeAsync(AuthenticationProperties properties
5151
// Initialize properties if null
5252
properties ??= new AuthenticationProperties();
5353

54+
// Set up the resource URI if not already configured, using the current request as a fallback
55+
if (Options.ResourceMetadata.Resource == null)
56+
{
57+
Options.ResourceMetadata.Resource = new Uri($"{Request.Scheme}://{Request.Host}");
58+
}
59+
60+
// Configure the resource metadata service with our metadata
61+
_resourceMetadataService.ConfigureMetadata(metadata => {
62+
metadata.Resource = Options.ResourceMetadata.Resource;
63+
metadata.AuthorizationServers = Options.ResourceMetadata.AuthorizationServers;
64+
metadata.BearerMethodsSupported = Options.ResourceMetadata.BearerMethodsSupported;
65+
metadata.ScopesSupported = Options.ResourceMetadata.ScopesSupported;
66+
metadata.ResourceDocumentation = Options.ResourceMetadata.ResourceDocumentation;
67+
});
68+
5469
// Set the WWW-Authenticate header with the resource_metadata
5570
string headerValue = $"Bearer realm=\"{Scheme.Name}\"";
5671
headerValue += $", resource_metadata=\"{metadataUrl}\"";
5772

58-
// Use Headers.Append with a StringValues object
5973
Response.Headers["WWW-Authenticate"] = headerValue;
6074

6175
// Store the resource_metadata in properties in case other handlers need it

src/ModelContextProtocol.AspNetCore/Auth/McpAuthenticationOptions.cs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
using Microsoft.AspNetCore.Authentication;
2+
using ModelContextProtocol.Auth.Types;
23

34
namespace ModelContextProtocol.AspNetCore.Auth;
45

@@ -10,5 +11,17 @@ public class McpAuthenticationOptions : AuthenticationSchemeOptions
1011
/// <summary>
1112
/// The URI to the resource metadata document.
1213
/// </summary>
14+
/// <remarks>
15+
/// This URI will be included in the WWW-Authenticate header when a 401 response is returned.
16+
/// </remarks>
1317
public Uri? ResourceMetadataUri { get; set; }
18+
19+
/// <summary>
20+
/// Gets or sets the protected resource metadata.
21+
/// </summary>
22+
/// <remarks>
23+
/// This contains the OAuth metadata for the protected resource, including authorization servers,
24+
/// supported scopes, and other information needed for clients to authenticate.
25+
/// </remarks>
26+
public ProtectedResourceMetadata ResourceMetadata { get; set; } = new ProtectedResourceMetadata();
1427
}
Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
using Microsoft.Extensions.DependencyInjection.Extensions;
22
using ModelContextProtocol.AspNetCore;
33
using ModelContextProtocol.AspNetCore.Auth;
4-
using ModelContextProtocol.Auth.Types;
54
using ModelContextProtocol.Server;
65

76
namespace Microsoft.Extensions.DependencyInjection;
@@ -36,61 +35,4 @@ public static IMcpServerBuilder WithHttpTransport(this IMcpServerBuilder builder
3635

3736
return builder;
3837
}
39-
40-
/// <summary>
41-
/// Adds OAuth authorization support to the MCP server.
42-
/// </summary>
43-
/// <param name="builder">The builder instance.</param>
44-
/// <param name="configureMetadata">An action to configure the resource metadata.</param>
45-
/// <param name="configureOptions">An action to configure authentication options.</param>
46-
/// <returns>The builder provided in <paramref name="builder"/>.</returns>
47-
/// <exception cref="ArgumentNullException"><paramref name="builder"/> is <see langword="null"/>.</exception>
48-
public static IMcpServerBuilder WithAuthorization(
49-
this IMcpServerBuilder builder,
50-
Action<ProtectedResourceMetadata>? configureMetadata = null,
51-
Action<McpAuthenticationOptions>? configureOptions = null)
52-
{
53-
ArgumentNullException.ThrowIfNull(builder);
54-
55-
// Create and register the resource metadata service
56-
var resourceMetadataService = new ResourceMetadataService();
57-
58-
// Apply configuration directly to the instance
59-
if (configureMetadata != null)
60-
{
61-
resourceMetadataService.ConfigureMetadata(configureMetadata);
62-
}
63-
64-
// Register the configured instance as a singleton
65-
builder.Services.AddSingleton(resourceMetadataService);
66-
67-
// Mark the service as having authorization enabled
68-
builder.Services.AddSingleton<McpAuthorizationMarker>();
69-
70-
// Add authentication with the MCP authentication handler
71-
builder.Services.AddAuthentication()
72-
.AddMcp(options =>
73-
{
74-
// Default to the standard OAuth protected resource endpoint
75-
options.ResourceMetadataUri = new Uri("/.well-known/oauth-protected-resource", UriKind.Relative);
76-
77-
// Apply custom configuration if provided
78-
configureOptions?.Invoke(options);
79-
});
80-
81-
// Add authorization services
82-
builder.Services.AddAuthorization(options =>
83-
{
84-
options.AddPolicy("McpAuth", policy =>
85-
{
86-
policy.RequireAuthenticatedUser();
87-
});
88-
});
89-
90-
// Register the middleware for automatically adding WWW-Authenticate headers
91-
// Store in DI that we need to use the middleware
92-
builder.Services.AddSingleton<McpAuthenticationResponseMarker>();
93-
94-
return builder;
95-
}
9638
}

src/ModelContextProtocol.AspNetCore/McpEndpointRouteBuilderExtensions.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ public static IEndpointConventionBuilder MapMcp(this IEndpointRouteBuilder endpo
6767
.WithDisplayName("MCP Resource Metadata");
6868

6969
// Apply authorization to MCP endpoints
70-
mcpGroup.RequireAuthorization("McpAuth");
70+
mcpGroup.RequireAuthorization(McpAuthenticationDefaults.AuthenticationScheme);
7171
}
7272

7373
return mcpGroup;

0 commit comments

Comments
 (0)