From c3e657e2a1d643cdd42cd6e12928ebf57ea299a2 Mon Sep 17 00:00:00 2001 From: moze Date: Wed, 6 May 2026 02:08:32 +0200 Subject: [PATCH] fix: return 405 on POST /sse so MCP clients fall back to legacy SSE transport MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 --- .../trueref/adapter/in/rest/WebConfig.java | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/trueref-adapters/src/main/java/com/trueref/adapter/in/rest/WebConfig.java b/trueref-adapters/src/main/java/com/trueref/adapter/in/rest/WebConfig.java index 071d9b4..ea95632 100644 --- a/trueref-adapters/src/main/java/com/trueref/adapter/in/rest/WebConfig.java +++ b/trueref-adapters/src/main/java/com/trueref/adapter/in/rest/WebConfig.java @@ -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 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 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) {