From eacdb8e840666e1408a8228ac80d51fde7bb2e80 Mon Sep 17 00:00:00 2001 From: g2vinay <5430778+g2vinay@users.noreply.github.com> Date: Thu, 29 Jan 2026 14:38:02 -0800 Subject: [PATCH 1/3] Add context-aware CORS policy for security --- .../Server/Commands/ServiceStartCommand.cs | 84 +++++++++++++------ 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/core/Azure.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs b/core/Azure.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs index 91bd5fc168..3e84b217a8 100644 --- a/core/Azure.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs +++ b/core/Azure.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs @@ -523,18 +523,10 @@ private IHost CreateHttpHost(ServiceStartOptions serverOptions) services.AddHealthChecks(); // Configure CORS - // We're allowing all origins, methods, and headers to support any web - // browser clients. + // By default in development mode, we restrict to localhost origins for security. + // In production (authenticated mode), allow configured origins or all origins if specified. // Non-browser clients are unaffected by CORS. - services.AddCors(options => - { - options.AddPolicy("AllowAll", policy => - { - policy.AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader(); - }); - }); + ConfigureCors(services, serverOptions); // Configure services ConfigureServices(services); // Our static callback hook @@ -545,7 +537,7 @@ private IHost CreateHttpHost(ServiceStartOptions serverOptions) UseHttpsRedirectionIfEnabled(app); // Configure middleware pipeline - app.UseCors("AllowAll"); + app.UseCors("McpCorsPolicy"); app.UseRouting(); // Add OAuth protected resource metadata middleware @@ -640,18 +632,10 @@ private IHost CreateIncomingAuthDisabledHttpHost(ServiceStartOptions serverOptio services.AddSingleIdentityTokenCredentialProvider(); // Configure CORS - // We're allowing all origins, methods, and headers to support any web - // browser clients. + // By default in development mode, we restrict to localhost origins for security. + // In production (authenticated mode), allow configured origins or all origins if specified. // Non-browser clients are unaffected by CORS. - services.AddCors(options => - { - options.AddPolicy("AllowAll", policy => - { - policy.AllowAnyOrigin() - .AllowAnyMethod() - .AllowAnyHeader(); - }); - }); + ConfigureCors(services, serverOptions); // Configure services ConfigureServices(services); // Our static callback hook @@ -668,13 +652,65 @@ private IHost CreateIncomingAuthDisabledHttpHost(ServiceStartOptions serverOptio UseHttpsRedirectionIfEnabled(app); // Configure middleware pipeline - app.UseCors("AllowAll"); + app.UseCors("McpCorsPolicy"); app.UseRouting(); app.MapMcp(); return app; } + /// + /// Configures CORS policy based on environment and configuration. + /// In development mode (unauthenticated), restricts to localhost for security. + /// In production (authenticated), allows all origins (safe due to authentication requirement). + /// + /// The service collection to configure. + /// The server configuration options. + private static void ConfigureCors(IServiceCollection services, ServiceStartOptions serverOptions) + { + services.AddCors(options => + { + options.AddPolicy("McpCorsPolicy", policy => + { + // In unauthenticated mode (development), restrict to localhost by default + // Allows localhost with any port to support various development scenarios: + // - Port 1031: Default HTTP mode (launchSettings.json) + // - Port 5008: SSE mode default + // - Port 5173: MCP Inspector tool + // - Custom ports: User-specified via ASPNETCORE_URLS + if (serverOptions.DangerouslyDisableHttpIncomingAuth) + { + policy.SetIsOriginAllowed(origin => + { + if (Uri.TryCreate(origin, UriKind.Absolute, out var uri)) + { + // Allow localhost and 127.0.0.1 with any port + return uri.Host == "localhost" || + uri.Host == "127.0.0.1" || + uri.Host == "[::1]"; // IPv6 loopback + } + return false; + }) + .AllowAnyMethod() + .AllowAnyHeader() + .AllowCredentials(); // Required when using SetIsOriginAllowed + } + // In authenticated mode (production), allow all origins by default + // This is safe because: + // 1. Authentication (JWT Bearer) validates all requests regardless of origin + // 2. CORS is a browser security mechanism, not a server security feature + // 3. MCP clients (GitHub Copilot in VS Code/Codespaces) need to connect from various origins + // 4. The server still enforces authentication and authorization on every request + else + { + policy.AllowAnyOrigin() + .AllowAnyMethod() + .AllowAnyHeader(); + } + }); + }); + } + /// /// Configures the MCP server services. /// From ee83aff0d7bd9bf1db52f6b7867b81f294eb8ae5 Mon Sep 17 00:00:00 2001 From: g2vinay <5430778+g2vinay@users.noreply.github.com> Date: Mon, 2 Feb 2026 16:13:17 -0800 Subject: [PATCH 2/3] format fix --- .../src/Areas/Server/Commands/ServiceStartCommand.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/core/Azure.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs b/core/Azure.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs index 3e84b217a8..7605d7296b 100644 --- a/core/Azure.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs +++ b/core/Azure.Mcp.Core/src/Areas/Server/Commands/ServiceStartCommand.cs @@ -685,7 +685,7 @@ private static void ConfigureCors(IServiceCollection services, ServiceStartOptio if (Uri.TryCreate(origin, UriKind.Absolute, out var uri)) { // Allow localhost and 127.0.0.1 with any port - return uri.Host == "localhost" || + return uri.Host == "localhost" || uri.Host == "127.0.0.1" || uri.Host == "[::1]"; // IPv6 loopback } @@ -888,11 +888,11 @@ private static WebApplication UseHttpsRedirectionIfEnabled(WebApplication app) } return Sdk.CreateTracerProviderBuilder() - // captures incoming HTTP requests .AddAspNetCoreInstrumentation() - // captures outgoing HTTP requests with filtering - .AddHttpClientInstrumentation(o => o.FilterHttpRequestMessage = ShouldInstrumentHttpRequest) - .AddAzureMonitorTraceExporter(exporterOptions => exporterOptions.ConnectionString = connectionString) + .AddHttpClientInstrumentation(o => + o.FilterHttpRequestMessage = ShouldInstrumentHttpRequest) + .AddAzureMonitorTraceExporter(exporterOptions => + exporterOptions.ConnectionString = connectionString) .Build(); } From eb4371c1ca0d83c6b8b463730d1ea4c7f68b03c4 Mon Sep 17 00:00:00 2001 From: g2vinay <5430778+g2vinay@users.noreply.github.com> Date: Mon, 2 Feb 2026 16:29:54 -0800 Subject: [PATCH 3/3] add changelog --- servers/Azure.Mcp.Server/changelog-entries/1770078551923.yaml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 servers/Azure.Mcp.Server/changelog-entries/1770078551923.yaml diff --git a/servers/Azure.Mcp.Server/changelog-entries/1770078551923.yaml b/servers/Azure.Mcp.Server/changelog-entries/1770078551923.yaml new file mode 100644 index 0000000000..4561c87047 --- /dev/null +++ b/servers/Azure.Mcp.Server/changelog-entries/1770078551923.yaml @@ -0,0 +1,3 @@ +changes: + - section: "Bugs Fixed" + description: "Added CORS policy to restrict cross-origin requests to localhost when running in unauthenticated development environment" \ No newline at end of file