Skip to content

Commit 67342cd

Browse files
committed
Policy setup
1 parent 32f2265 commit 67342cd

File tree

3 files changed

+71
-28
lines changed

3 files changed

+71
-28
lines changed

samples/ProtectedMCPServer/Program.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,10 @@
7777
// Add authorization services
7878
builder.Services.AddAuthorization(options =>
7979
{
80-
options.AddMcpPolicy();
80+
// Modify the MCP policy to include both MCP and JWT Bearer schemes
81+
// This ensures the bearer token is properly authenticated while maintaining MCP for challenges
82+
options.AddMcpPolicy(configurePolicy: builder =>
83+
builder.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme));
8184
});
8285

8386
// Configure MCP Server

src/ModelContextProtocol.AspNetCore/Auth/McpAuthenticationHandler.cs

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,36 @@ public async Task<bool> HandleRequestAsync()
4747
return true;
4848
}
4949

50+
/// <summary>
51+
/// Gets the base URL from the current request, including scheme, host, and path base.
52+
/// </summary>
53+
private string GetBaseUrl() => $"{Request.Scheme}://{Request.Host}{Request.PathBase}";
54+
55+
/// <summary>
56+
/// Gets the absolute URI for the resource metadata endpoint.
57+
/// </summary>
58+
private string GetAbsoluteResourceMetadataUri()
59+
{
60+
var options = _optionsMonitor.CurrentValue;
61+
var resourceMetadataUri = options.ResourceMetadataUri;
62+
63+
if (resourceMetadataUri.IsAbsoluteUri)
64+
{
65+
return resourceMetadataUri.ToString();
66+
}
67+
68+
// For relative URIs, combine with the base URL
69+
string baseUrl = GetBaseUrl();
70+
string resourceMetadataPath = resourceMetadataUri.ToString();
71+
72+
if (!Uri.TryCreate(baseUrl + resourceMetadataPath, UriKind.Absolute, out var absoluteUri))
73+
{
74+
throw new InvalidOperationException("Could not create absolute URI for resource metadata.");
75+
}
76+
77+
return absoluteUri.ToString();
78+
}
79+
5080
/// <summary>
5181
/// Handles the resource metadata request.
5282
/// </summary>
@@ -65,10 +95,7 @@ private async Task HandleResourceMetadataRequestAsync()
6595
// Set default resource if not set
6696
if (metadata.Resource == null)
6797
{
68-
var request = Request;
69-
var hostString = request.Host.Value;
70-
var scheme = request.Scheme;
71-
metadata.Resource = new Uri($"{scheme}://{hostString}");
98+
metadata.Resource = new Uri(GetBaseUrl());
7299
}
73100

74101
Response.StatusCode = StatusCodes.Status200OK;
@@ -95,29 +122,8 @@ protected override Task HandleChallengeAsync(AuthenticationProperties properties
95122
// Set the response status code
96123
Response.StatusCode = StatusCodes.Status401Unauthorized;
97124

98-
// Get the current options to ensure we have the latest values
99-
var options = _optionsMonitor.CurrentValue;
100-
101-
// Generate the full resource metadata URL based on the current request
102-
var baseUrl = $"{Request.Scheme}://{Request.Host}";
103-
104-
string resourceMetadataUriString = options.ResourceMetadataUri.ToString();
105-
string rawPrmDocumentUri;
106-
107-
// Check if the URI is relative or absolute
108-
if (options.ResourceMetadataUri.IsAbsoluteUri)
109-
{
110-
rawPrmDocumentUri = resourceMetadataUriString;
111-
}
112-
else
113-
{
114-
// For relative URIs, combine with the base URL
115-
if (!Uri.TryCreate(baseUrl + resourceMetadataUriString, UriKind.Absolute, out var absoluteUri))
116-
{
117-
throw new InvalidOperationException("Could not create absolute URI for resource metadata.");
118-
}
119-
rawPrmDocumentUri = absoluteUri.ToString();
120-
}
125+
// Get the absolute URI for the resource metadata
126+
string rawPrmDocumentUri = GetAbsoluteResourceMetadataUri();
121127

122128
// Initialize properties if null
123129
properties ??= new AuthenticationProperties();

src/ModelContextProtocol.AspNetCore/Auth/McpAuthorizationPolicyExtensions.cs

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,4 +33,38 @@ public static AuthorizationOptions AddMcpPolicy(
3333

3434
return options;
3535
}
36+
37+
/// <summary>
38+
/// Adds a preconfigured MCP policy that includes additional authentication schemes.
39+
/// </summary>
40+
/// <param name="options">The authorization options.</param>
41+
/// <param name="additionalSchemes">Additional authentication schemes to include in the policy.</param>
42+
/// <param name="policyName">The name of the policy to add. Default is <see cref="McpAuthenticationDefaults.AuthenticationScheme"/>.</param>
43+
/// <param name="configurePolicy">An optional action to further configure the policy builder.</param>
44+
/// <returns>The authorization options for chaining.</returns>
45+
public static AuthorizationOptions AddMcpPolicy(
46+
this AuthorizationOptions options,
47+
string[] additionalSchemes,
48+
string policyName = McpAuthenticationDefaults.AuthenticationScheme,
49+
Action<AuthorizationPolicyBuilder>? configurePolicy = null)
50+
{
51+
if (additionalSchemes == null || additionalSchemes.Length == 0)
52+
{
53+
return AddMcpPolicy(options, policyName, configurePolicy);
54+
}
55+
56+
// Create a policy builder with MCP and additional authentication schemes
57+
var allSchemes = new[] { McpAuthenticationDefaults.AuthenticationScheme }.Concat(additionalSchemes).ToArray();
58+
59+
var policyBuilder = new AuthorizationPolicyBuilder(allSchemes)
60+
.RequireAuthenticatedUser();
61+
62+
// Allow additional configuration if provided
63+
configurePolicy?.Invoke(policyBuilder);
64+
65+
// Add the configured policy
66+
options.AddPolicy(policyName, policyBuilder.Build());
67+
68+
return options;
69+
}
3670
}

0 commit comments

Comments
 (0)