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..7605d7296b 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.
///
@@ -852,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();
}
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