|
| 1 | +using System.Net.Http.Headers; |
| 2 | +using System.Security.Claims; |
1 | 3 | using Microsoft.AspNetCore.Authentication.JwtBearer; |
2 | 4 | using Microsoft.IdentityModel.Tokens; |
3 | 5 | using ModelContextProtocol.AspNetCore.Authentication; |
4 | 6 | using ModelContextProtocol.Types.Authentication; |
5 | 7 | using ProtectedMCPServer.Tools; |
6 | | -using System.Net.Http.Headers; |
7 | | -using System.Security.Claims; |
8 | 8 |
|
9 | 9 | var builder = WebApplication.CreateBuilder(args); |
10 | 10 |
|
11 | | -// Define Entra ID (Azure AD) configuration |
12 | | -var tenantId = "a2213e1c-e51e-4304-9a0d-effe57f31655"; // This is the tenant ID from your existing configuration |
| 11 | +var serverUrl = "http://localhost:7071/"; |
| 12 | +var tenantId = "a2213e1c-e51e-4304-9a0d-effe57f31655"; |
13 | 13 | var instance = "https://login.microsoftonline.com/"; |
14 | 14 |
|
15 | | -// Configure authentication to use MCP for challenges and Entra ID JWT Bearer for token validation |
16 | 15 | builder.Services.AddAuthentication(options => |
17 | 16 | { |
18 | 17 | options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme; |
19 | | - options.DefaultChallengeScheme = McpAuthenticationDefaults.AuthenticationScheme; // Use MCP for challenges |
| 18 | + options.DefaultChallengeScheme = McpAuthenticationDefaults.AuthenticationScheme; |
20 | 19 | }) |
21 | 20 | .AddJwtBearer(options => |
22 | 21 | { |
23 | | - // Configure for Entra ID (Azure AD) token validation |
24 | 22 | options.Authority = $"{instance}{tenantId}/v2.0"; |
25 | 23 | options.TokenValidationParameters = new TokenValidationParameters |
26 | 24 | { |
27 | | - // Configure validation parameters for Entra ID tokens |
28 | 25 | ValidateIssuer = true, |
29 | 26 | ValidateAudience = true, |
30 | 27 | ValidateLifetime = true, |
31 | 28 | ValidateIssuerSigningKey = true, |
32 | | - |
33 | | - // Default audience - you should replace this with your actual app/API registration ID |
34 | 29 | ValidAudience = "167b4284-3f92-4436-92ed-38b38f83ae08", |
35 | | - |
36 | | - // This validates that tokens come from your Entra ID tenant |
37 | 30 | ValidIssuer = $"{instance}{tenantId}/v2.0", |
38 | | - |
39 | | - // These claims are used by the app for identity representation |
40 | 31 | NameClaimType = "name", |
41 | 32 | RoleClaimType = "roles" |
42 | 33 | }; |
43 | 34 |
|
44 | | - // Enable metadata-based issuer key retrieval |
45 | 35 | options.MetadataAddress = $"{instance}{tenantId}/v2.0/.well-known/openid-configuration"; |
46 | 36 |
|
47 | | - // Add development mode debug logging for token validation |
48 | 37 | options.Events = new JwtBearerEvents |
49 | 38 | { |
50 | 39 | OnTokenValidated = context => |
|
85 | 74 | }; |
86 | 75 | }); |
87 | 76 |
|
88 | | -// Add authorization services |
89 | 77 | builder.Services.AddAuthorization(options => |
90 | 78 | { |
91 | | - // Modify the MCP policy to include both MCP and JWT Bearer schemes |
92 | | - // This ensures the bearer token is properly authenticated while maintaining MCP for challenges |
93 | 79 | options.AddMcpPolicy(configurePolicy: builder => |
94 | 80 | builder.AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme)); |
95 | 81 | }); |
96 | 82 |
|
97 | | -// Configure MCP Server |
| 83 | +builder.Services.AddHttpContextAccessor(); |
98 | 84 | builder.Services.AddMcpServer() |
99 | 85 | .WithTools<WeatherTools>() |
100 | 86 | .WithHttpTransport(); |
|
113 | 99 |
|
114 | 100 | app.MapMcp().RequireAuthorization(McpAuthenticationDefaults.AuthenticationScheme); |
115 | 101 |
|
116 | | -Console.WriteLine("Starting MCP server with authorization at http://localhost:7071"); |
117 | | -Console.WriteLine("PRM Document URL: http://localhost:7071/.well-known/oauth-protected-resource"); |
118 | | -Console.WriteLine(" - This endpoint returns different metadata based on the client type!"); |
119 | | -Console.WriteLine(" - Try with different User-Agent headers or add ?mobile query parameter"); |
120 | | - |
121 | | -Console.WriteLine(); |
122 | | -Console.WriteLine("Entra ID (Azure AD) JWT token validation is configured"); |
123 | | -Console.WriteLine(); |
124 | | -Console.WriteLine("To test the server with different client types:"); |
125 | | -Console.WriteLine("1. Standard client: No special headers needed"); |
126 | | -Console.WriteLine("2. Mobile client: Add 'mobile' in User-Agent or use ?mobile query parameter"); |
127 | | -Console.WriteLine("3. Partner client: Include 'partner' in User-Agent or add X-Partner-API header"); |
128 | | -Console.WriteLine(); |
129 | | -Console.WriteLine("Each client type will receive different authorization requirements!"); |
130 | | -Console.WriteLine(); |
| 102 | +Console.WriteLine($"Starting MCP server with authorization at {serverUrl}"); |
| 103 | +Console.WriteLine($"PRM Document URL: {serverUrl}.well-known/oauth-protected-resource"); |
131 | 104 | Console.WriteLine("Press Ctrl+C to stop the server"); |
132 | 105 |
|
133 | | -app.Run("http://localhost:7071/"); |
| 106 | +app.Run(serverUrl); |
0 commit comments