Repository navigation
Streamable servlet transport does not close SSE response for unknown methods #1050
Description
DISCLAIMER: Codex-generated bug report
Bug description
With HttpServletStreamableServerTransportProvider in Java SDK 2.0.0, a request for an unknown or unsupported JSON-RPC method receives the correct -32601 Method not found
response, but the POST response's SSE stream remains open indefinitely.
Supported methods close their SSE streams normally after returning a response.
The MCP Streamable HTTP specification says that after the JSON-RPC response has been sent, the server should close the SSE stream:
Environment
- MCP Java SDK: 2.0.0
- Transport:
HttpServletStreamableServerTransportProvider - Jetty: 12.1.10
- Jakarta Servlet API: 6.1
- Java: 25.0.3
- Negotiated MCP protocol:
2025-06-18
The server advertises tools but not resources or prompts.
Steps to reproduce
Initialize a session:
curl --max-time 5 -i -X POST http://127.0.0.1:8080/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
--data-binary '{
"jsonrpc": "2.0",
"id": 1,
"method": "initialize",
"params": {
"protocolVersion": "2025-06-18",
"capabilities": {},
"clientInfo": {
"name": "reproducer",
"version": "1.0"
}
}
}'Copy the returned Mcp-Session-Id, send notifications/initialized, and then call an unsupported method:
curl --max-time 3 -i -X POST http://127.0.0.1:8080/mcp \
-H 'Content-Type: application/json' \
-H 'Accept: application/json, text/event-stream' \
-H 'MCP-Protocol-Version: 2025-06-18' \
-H 'Mcp-Session-Id: SESSION_ID' \
--data-binary '{
"jsonrpc": "2.0",
"id": 2,
"method": "resources/list",
"params": {}
}'The server sends an SSE event promptly:
event: message
data: {"jsonrpc":"2.0","id":2,"error":{"code":-32601,"message":"Method not found: resources/list"}}
However, the HTTP response does not reach end-of-stream. Curl eventually reports:
curl: (28) Operation timed out after 3002 milliseconds
Calling a supported method such as tools/list returns its response and closes the stream immediately.
Expected behavior
After sending the -32601 JSON-RPC response, the server should complete the asynchronous servlet context and close the POST response's SSE stream.
Actual behavior
The JSON-RPC error is delivered, but the SSE stream and HTTP request remain open.
Apparent cause
In McpStreamableServerSession.responseStream, the missing-handler branch returns only:
return transport.sendMessage(
McpSchema.JSONRPCResponse.error(...));The registered-handler branch ends with:
.flatMap(transport::sendMessage)
.then(transport.closeGracefully());The missing-handler branch appears to need the same transport closure:
return transport.sendMessage(
McpSchema.JSONRPCResponse.error(...))
.then(transport.closeGracefully());Impact
Clients that probe an unsupported method may wait indefinitely unless they impose a timeout. The server also retains the asynchronous servlet request until the client disconnects.
Activity
Kehrlann commentedon Jul 1, 2026
Hey @AlanBurlison ! Thanks for the report.
It is a duplicate of #1040 , which has been fixed in #1041. It will be shipped in 2.0.1 .
AlanBurlison commentedon Jul 1, 2026
Thanks for the quick reply! 🤖 didn't find that bug unfortunately (I did ask...) A win for the humans! 😉