fix: return 405 on POST /sse so MCP clients fall back to legacy SSE transport
All checks were successful
Build and publish Docker image / Build and push CPU image (push) Successful in 2m8s
Build and publish Docker image / Build and push GPU image (push) Successful in 3m1s

Modern MCP clients (Claude Code, etc.) probe for Streamable HTTP transport by
POSTing an InitializeRequest to the server URL first. Per MCP spec 2025-11-25,
they fall back to legacy HTTP+SSE only on 400/404/405.

Previously, POST /sse fell through the SPA resource resolver (which had 'sse'
missing from EXCLUDED_PREFIXES) and returned 500, causing clients to abort
instead of retrying with the GET-based SSE handshake.

Fix:
- Add 'sse' to EXCLUDED_PREFIXES so the SPA resolver ignores that path
- Add explicit @PostMapping("/sse") returning 405 Method Not Allowed with
  Allow: GET header — the correct signal for Streamable HTTP probe fallback
This commit is contained in:
moze
2026-05-06 02:08:32 +02:00
parent cfb35b35c0
commit c3e657e2a1

View File

@@ -5,6 +5,11 @@ import java.util.Set;
import org.jspecify.annotations.Nullable;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.web.servlet.resource.PathResourceResolver;
@@ -15,11 +20,26 @@ import org.springframework.web.servlet.resource.PathResourceResolver;
* explicitly excluded — Spring routes those first anyway, but we exclude them defensively so the
* resource resolver does not attempt a fallback for them.
*/
/**
* Explicit POST handler for the SSE endpoint. Modern MCP clients (e.g. Claude Code) probe for
* Streamable HTTP transport by POSTing to the server URL first. Returning 405 here tells them this
* server uses the legacy HTTP+SSE transport, triggering the correct GET-based SSE fallback.
*/
@RestController
class McpSseMethodNotAllowed {
@PostMapping("/sse")
ResponseEntity<Void> rejectPost() {
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.ALLOW, "GET");
return ResponseEntity.status(HttpStatus.METHOD_NOT_ALLOWED).headers(headers).build();
}
}
@Configuration
public class WebConfig implements WebMvcConfigurer {
private static final Set<String> EXCLUDED_PREFIXES =
Set.of("api/", "mcp", "swagger-ui/", "v3/api-docs", "actuator/");
Set.of("api/", "mcp", "sse", "swagger-ui/", "v3/api-docs", "actuator/");
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {