Repository navigation
Streamable HTTP client ignores SSE messages when event name is omitted #885
Description
Disclaimer: I am not a native English speaker. This issue was drafted with AI translation assistance. I apologize for any awkward phrasing.
Bug description
When using the Streamable HTTP transport, the Java client receives an SSE frame whose payload contains a valid JSON-RPC response, but the SSE event name is omitted by the server.
In standard SSE semantics, if the event: field is omitted, the event type defaults to message. However, the current Java SDK only parses the frame if event.event() is explicitly equal to "message". If the event name is missing and Spring/WebFlux exposes it as null, the client drops the frame instead of treating it as a default message event.
As a result, the initialize response is ignored even though the client has already received the JSON-RPC result, and initialization eventually times out with:
Client failed to initialize by explicit API call
In my case, the server is rmcp over Streamable HTTP.
Environment
- Spring AI:
2.0.0-M3 - MCP Java SDK:
1.1.0 - Transport:
WebClientStreamableHttpTransport(viaspring-ai-starter-mcp-client-webflux) - Spring Boot:
4.0.4 - Java:
25.0.2 - Reactor Netty:
1.3.4 - MCP server:
rmcp 1.2.0(Rust, Streamable HTTP) - OS: macOS
Steps to reproduce
- Run an MCP server over Streamable HTTP.
- Make the server return a valid JSON-RPC
initializeresult astext/event-stream. - The SSE frame should contain only
data: ...and omit theevent:field. For example:
data: {"jsonrpc":"2.0","id":"1","result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{}},"serverInfo":{"name":"test","version":"1.0.0"}}}
- Start a Spring AI / MCP Java SDK client using
WebClientStreamableHttpTransport. - Call
client.initialize()(or let Spring AI auto-initialize the MCP client during startup).
Expected behavior
The client should treat an SSE frame without an explicit event: field as a default message event and parse the JSON-RPC payload normally.
So the initialize response above should be accepted, and client initialization should complete successfully.
Actual behavior
The client receives the SSE payload, but the event type is exposed as null and is not parsed as a JSON-RPC message.
As a result, the initialize response is effectively ignored, and initialization times out.
From debug logs:
Received SSE event with type: ServerSentEvent [id = 'null', event='null', retry=null, comment='null', data={"jsonrpc":"2.0","id":"9642da98-0","result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{}},"serverInfo":{"name":"rmcp","version":"1.2.0"},"instructions":"..."}}]
...
Caused by: java.util.concurrent.TimeoutException: Did not observe any item or terminal signal within 20000ms
...
Client failed to initialize by explicit API call
Activity
Fix SSE event classification to follow spec for missing event field
iaJingda commentedon Apr 9, 2026
Hi maintainers, I dug into this and pushed a fix on my fork (referenced above).
Scope clarification
WebClientStreamableHttpTransportmentioned in the original report was moved to Spring AI 2.0 as part of #805, so the WebClient-specific fix would need to land there. However, the same root cause is present inHttpClientStreamableHttpTransport(still in this repo), with an interesting asymmetry:sendMessage()POST path processesdata()directly without checking the SSE event type, soinitialize()happens to succeed on HttpClient.reconnect()GET stream path usesMESSAGE_EVENT_TYPE.equals(sseEvent.event()), which evaluates tofalsewhen the server omits theevent:line. Per the SSE spec (WHATWG HTML §9.2.6), a missingevent:field must default tomessage. As a result, server-initiated messages arriving on the open GET stream are silently dropped.So HttpClient users experience a more subtle form of the same bug: initialization succeeds, but server-pushed notifications on the SSE stream never reach the handler.
Fix approach
Extracted the classification into a package-private
isMessageEvent(String)helper that treatsnullor empty event names as equivalent to"message"per the SSE spec, and covered it with parameterized unit tests (null, empty, explicitmessage, plus negative cases including case sensitivity). Happy to open a PR.One question: should a separate issue be filed against
spring-projects/spring-aifor the WebClient variant, or is that being tracked there already?nympheon commentedon Apr 9, 2026
Thanks for digging into this and for the detailed analysis.
I think this should also be filed in spring-projects/spring-ai for the WebClient variant. I haven’t opened an issue there yet.
If you haven’t already filed one, I’d be happy to open it on my side. Of course, if you prefer to do it yourself, that works too.
iaJingda commentedon Apr 9, 2026
@Qiaofanxing thanks for the quick follow-up! Please go ahead and open the issue in
spring-projects/spring-ai— you have the original reproducer with the Rustrmcpserver, so the report will be more actionable from your side.Feel free to link back to #913 and this thread for context on the shared root cause. If the Spring AI maintainers are open to it, I'd be happy to help with a PR there as well once we see how things land, but let's not block your issue on that.
Thanks again for reporting the original bug with such clear reproduction steps — made digging into this much easier.
Fix SSE event classification to follow spec for missing event field
Fix SSE event classification to follow spec for missing event field (m…