diff --git a/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java b/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java index 61f56636..d42be301 100644 --- a/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java +++ b/src/main/java/org/apache/solr/mcp/server/security/HttpSecurityConfiguration.java @@ -39,6 +39,9 @@ class HttpSecurityConfiguration { @Value("${spring.security.oauth2.resourceserver.jwt.issuer-uri:}") private String issuerUrl; + @Value("${mcp.cors.allowed-origins}") + private List allowedOrigins; + @Bean @ConditionalOnProperty(name = "http.security.enabled", havingValue = "true", matchIfMissing = true) SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { @@ -80,9 +83,19 @@ SecurityFilterChain unsecured(HttpSecurity http) throws Exception { public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); - configuration.setAllowedOriginPatterns(List.of("*")); - configuration.setAllowedMethods(List.of("*")); - configuration.setAllowedHeaders(List.of("*")); + // Use the strict setAllowedOrigins API (not setAllowedOriginPatterns) so the + // browser-spec rule that wildcards cannot be combined with credentials is + // enforced. + // Origins are configurable via the mcp.cors.allowed-origins property + // (env: MCP_CORS_ALLOWED_ORIGINS) and default to the MCP Inspector's local + // proxy. + configuration.setAllowedOrigins(allowedOrigins); + // Only the HTTP methods used by the MCP Streamable HTTP transport. + configuration.setAllowedMethods(List.of("GET", "POST", "DELETE", "OPTIONS")); + // Only the headers the MCP specification requires for the Streamable HTTP + // transport. + configuration.setAllowedHeaders( + List.of("Authorization", "Content-Type", "Mcp-Session-Id", "MCP-Protocol-Version", "Last-Event-ID")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); diff --git a/src/main/resources/application-http.properties b/src/main/resources/application-http.properties index 1364348f..6a613b5d 100644 --- a/src/main/resources/application-http.properties +++ b/src/main/resources/application-http.properties @@ -28,6 +28,10 @@ spring.security.oauth2.resourceserver.jwt.issuer-uri=${OAUTH2_ISSUER_URI:https:/ # in any environment reachable from the network is unsafe; the MCP Authorization # specification requires HTTP-based MCP servers to authenticate. http.security.enabled=${HTTP_SECURITY_ENABLED:true} +# Comma-separated list of allowed CORS origins for the MCP HTTP endpoint. +# Defaults to MCP Inspector's local proxy. Add additional origins (browser-based +# MCP clients, internal dashboards) as needed. Do NOT use "*" with credentials. +mcp.cors.allowed-origins=${MCP_CORS_ALLOWED_ORIGINS:http://localhost:6274,http://127.0.0.1:6274} # observability management.endpoints.web.exposure.include=health,sbom,metrics,info,loggers,prometheus # Enable @Observed annotation support for custom spans