Skip to content

Streamable HTTP client ignores SSE messages when event name is omitted #885

@Qiaofanxing

Description

@Qiaofanxing

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 (via spring-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

  1. Run an MCP server over Streamable HTTP.
  2. Make the server return a valid JSON-RPC initialize result as text/event-stream.
  3. The SSE frame should contain only data: ... and omit the event: field. For example:
   data: {"jsonrpc":"2.0","id":"1","result":{"protocolVersion":"2025-06-18","capabilities":{"tools":{}},"serverInfo":{"name":"test","version":"1.0.0"}}}
  1. Start a Spring AI / MCP Java SDK client using WebClientStreamableHttpTransport.
  2. 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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions