Streamable HTTP client: slow reception of large SSE tool responses (fromLineSubscriber line-assembly bottleneck)
Maintainer antworten meist innerhalb von 3 Tagen
@chemicL arbeitet bereits daran.
Seit 03.7.2026.
Bewertung
Dieses Issue wurde noch nicht bewertet.
Beschreibung
Summary
When a tool returns a large response over the Streamable HTTP client transport, the client takes ~5s to receive a ~4 MB body that curl/HttpClient.ofString() reads in ~0.4s. The bottleneck is the client-side SSE body reading in ResponseSubscribers.sseToBodySubscriber, not the server, network, or JSON parsing.
Environment
io.modelcontextprotocol.sdk:mcp-core/mcp2.0.0 (latest)- JDK 25, Reactor (via SDK)
- Server: Spring AI 2.0.0
mcp-spring-webmvc(HttpServletStreamableServerTransportProvider) returning a single large SSEmessageevent — one compact-JSONdata:line (~4.17 MB) - Client:
HttpClientStreamableHttpTransport(McpSyncClient.callTool)
Measurements (steady-state, 3 runs)
| Path | Time to receive ~4.17 MB |
|---|---|
McpSyncClient.callTool (this SDK) |
~5,300 ms |
Same payload via curl / HttpClient BodyHandlers.ofString() |
~0.4–0.75 s |
| Jackson parse of the received JSON | < 70 ms |
→ ~10–13× slower than a plain one-shot read of the identical bytes.
Root cause analysis
The response body is effectively a single huge data: line (compact JSON has no newlines). ResponseSubscribers.sseToBodySubscriber uses HttpResponse.BodySubscribers.fromLineSubscriber(...); assembling that one ~4 MB line through the JDK line subscriber is the cost.
Things I tried:
- Changing
SseLineSubscriberdemand fromupstream().request(1)torequest(Long.MAX_VALUE)→ no improvement (so it isn't per-line backpressure). - Replacing the body subscriber with a streaming byte-level SSE parser (
BodySubscribers.fromSubscriber, unbounded demand, accumulateByteBuffers, split on\n\nevent boundaries, decode each event once) → ~0.4 s (≈13×).
Important constraint (must stay streaming)
A whole-body ofString read fixes the speed but breaks progress: the server interleaves notifications/progress on the same POST response SSE stream before the final result. So the fix must remain a streaming parser that emits each SSE event as its boundary arrives (a byte-level parser does this while still avoiding the line-assembly cost).
Questions
- Is there a recommended approach/workaround for large tool responses on the client that we're missing?
- Would you accept a PR replacing
fromLineSubscriberwith a streaming byte-level SSE parser inResponseSubscribers.sseToBodySubscriber(preserving incremental event emission)? - Is this related to #844 (opt-in
application/jsonresponse mode)? That would avoid SSE framing on the server side, but clients receiving SSE responses would still benefit from this fix.
Happy to open a PR with the streaming parser + a benchmark if that's welcome.
- Vorherrschende Sprache
- Java
- Sterne
- 3.7k
- Forks
- 1.2k
- Ø Merge
- 2 T. 5 Std.
- Gemergte PRs (30 T.)
- 4
Entwicklungsumgebung
- Kein Dockerfile und keine Docker-Compose-Datei
- Keine Pull-Request-Vorlage
- Beitragsleitfaden lesen
Erste Schritte
- Lesen Sie das ganze Issue und danach den Beitragsleitfaden des Projekts.
- Schreiben Sie ins Issue, dass Sie es übernehmen — das erspart doppelte Arbeit.
- Forken Sie das Repository und arbeiten Sie in einem Branch.
- Öffnen Sie einen Pull Request, der die Issue-Nummer nennt.
Mehr aus modelcontextprotocol/java-sdk
-
HttpServletStreamableServerTransportProvider: GET stream sends no status or headers until the first eventEvtl. vergeben @karthiksenv hat das vor 3 Tagen übernommen. Offen
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 86/100
modelcontextprotocol/java-sdk#1155 ·
Maintainer antworten meist innerhalb von 3 Tagen
-
Client request handlers that complete empty send no JSON-RPC responseEvtl. vergeben @1fanwang hat das vor 32 Tagen übernommen. Offenarea/client bug P2
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 84/100
modelcontextprotocol/java-sdk#1124 · 5 Kommentare ·
Maintainer antworten meist innerhalb von 3 Tagen
-
ServerCapabilities.logging is added unconditionally, overriding the caller's explicit capabilitiesEvtl. vergeben @1yuxiangJ hat das vor 48 Tagen übernommen. Offenbug P2 ready for work
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
modelcontextprotocol/java-sdk#1086 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 3 Tagen
-
Reject listRoots if not supported by client, without sending any requestEvtl. vergeben @nikita-kibitkin hat das vor 71 Tagen übernommen. Offenenhancement good first issue P3
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 82/100
modelcontextprotocol/java-sdk#1067 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 3 Tagen
-
StdioClientTransport missing explicit UTF-8 charset in InputStreamReader (same issue as #295, but on client side)Evtl. vergeben @suryateja-g13 hat das vor 142 Tagen übernommen. Offenbug P2 ready for work
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 74/100
modelcontextprotocol/java-sdk#898 · 1 Kommentar ·
Maintainer antworten meist innerhalb von 3 Tagen
Alle Issues in modelcontextprotocol/java-sdk
Ähnliche Issues
-
enhancement
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 88/100
helidon-io/helidon#12721 ·
Maintainer antworten meist innerhalb von 1 Tag
-
status: team-only type: dependency-upgrade
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 64/100
spring-projects/spring-boot#51966 ·
Maintainer antworten meist innerhalb von 1 Tag
-
Missing repro Platform: Android
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 78/100
software-mansion/react-native-reanimated#10816 · 2 Kommentare ·
Maintainer antworten meist innerhalb von 1 Tag
-
area/docs backport/26.6 backport/26.8 kind/bug status/triage
Schwierigkeit 1/5 Unter einer Stunde Anfängerfreundlichkeit 75/100
Maintainer antworten meist innerhalb von 1 Tag
-
[destination-snowflake] Custom domains rejected unlike source connectionsEvtl. vergeben @kuza55 hat das heute übernommen. Offenautoteam community connectors/destination/snowflake team/use
Schwierigkeit 2/5 1-3 Stunden Anfängerfreundlichkeit 68/100
Maintainer antworten meist innerhalb von 1 Tag