Skip to content

MCP Streamable HTTP transport incompatible with Spring AI servers - GET method not supported #4326

@wpf375516041

Description

@wpf375516041

What happened?

Description

Qwen Code's MCP client fails to maintain stable connections with MCP servers using Spring AI's Streamable HTTP transport. The client intermittently reports
Gateway Time-out and TypeError: fetch failed errors.

Root Cause

After investigation, I found that Qwen Code's StreamableHTTPClientTransport uses GET method to establish the SSE long-lived connection:

// From @modelcontextprotocol/sdk/dist/esm/client/streamableHttp.js
async _startOrAuthSse(options) {
const headers = await this._commonHeaders();
headers.set("Accept", "text/event-stream");
const response = await fetch(this._url, {
  method: "GET",  // ← Uses GET method
  headers,
  signal: this._abortController?.signal
});

However, Spring AI 1.1.5's WebMvcStreamableServerTransportProvider only supports POST method for SSE connections. GET requests return 400 Bad Request.

Evidence

Request Accept Header Result
POST text/event-stream, application/json ✅ 200 OK
GET text/event-stream ❌ 400 Bad Request
GET text/event-stream, application/json ❌ 400 Bad Request

curl test:

POST works
curl -X POST https://<your-mcp-server>/mcp \
-H "Content-Type: application/json" \
-H "Accept: text/event-stream, application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize",...}'
Returns: 200 OK

GET fails
curl -X GET https://<your-mcp-server>/mcp \
-H "Accept: text/event-stream"
Returns: 400 Bad Request

Connection Flow Analysis

The reason "it works at first but then fails" is due to the MCP connection sequence:

Step Method Purpose Result
1. Initialize POST Establish session, get session ID ✅ Success
2. Tool discovery POST Get tool list ✅ Success
3. SSE long-lived connection GET Receive server push notifications ❌ Failed (400)

Error timeline:

Startup → POST initialize success → POST tool discovery success → Tools available
      ↓
      GET SSE connection fails → Error: "Failed to open SSE stream"
      ↓
      Health check detects disconnected → Triggers reconnection
      ↓
      Reconnect: POST initialize success → GET SSE connection fails again → Loop

User experience:

  • Initially tools work (POST succeeds)
  • Soon errors appear (GET SSE connection fails)
  • Intermittently usable (POST still works during reconnection gaps)

Environment

  • Qwen Code Version: 0.15.11
  • MCP Server: Spring AI 1.1.5 (spring-ai-starter-mcp-server-webmvc)
  • Protocol: Streamable HTTP (spring.ai.mcp.server.protocol=STREAMABLE)
  • OS: Linux

Expected Behavior

The MCP client should use POST method for SSE connections when using Streamable HTTP transport, as required by the MCP specification and Spring
implementation.

Actual Behavior

The client uses GET method for SSE connections, which Spring AI rejects with 400 Bad Request. This causes:

  1. Initial connection may succeed (POST for initialize works)
  2. SSE long-lived connection fails (GET rejected)
  3. Client reports Gateway Time-out or fetch failed
  4. Health check triggers reconnection, but SSE connection fails again

Suggested Fix

Modify StreamableHTTPClientTransport._startOrAuthSse() to use POST method instead of GET for establishing SSE connections, or support both methods based
on server capabilities.

What did you expect to happen?

The MCP client should use POST method for SSE connections when using Streamable HTTP transport, as required by the MCP specification and Spring
implementation.

Client information

Client Information

Run qwen to enter the interactive CLI, then run the /about command.

$ qwen /about
# paste output here

Login information

No response

Anything else we need to know?

No response

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions