-
Notifications
You must be signed in to change notification settings - Fork 156
Closed
Description
The issue stems from the QuarkusStreamableHttpMcpTransport.java using the Vert.x HttpClientResponse.handler() method, which processes each response chunk (e.g., TCP packet) individually, passing it to the SseSubscriber.accept() method for parsing. This causes the JsonEOFException because the SSE event (containing the full JSON-RPC "tools/list" response) is split across multiple chunksand the client attempts to parse the first chunk before receiving the complete event.
if (id != null && contentType != null && contentType.contains("text/event-stream")) {
// the server has started a SSE channel
response.result().handler(bodyBuffer -> {
String responseString = bodyBuffer.toString();
SseEvent<String> sseEvent = parseSseEvent(responseString);
sseSubscriber.accept(sseEvent);
});
}
Using bodyHandler() (which buffers the entire response) could work but risks memory issues for large payloads,
String contentType = response.result().getHeader("Content-Type");
if (id != null && contentType != null && contentType.contains("text/event-stream")) {
// the server has started a SSE channel
response.result().bodyHandler(bodyBuffer -> {
if (bodyBuffer.length() > 0) {
String responseString = bodyBuffer.toString();
SseEvent<String> sseEvent = parseSseEvent(responseString);
sseSubscriber.accept(sseEvent);
}
});
}
Before Raising PR i like to discuss this, if there is any alternative way we can solve this.
ERROR:-
2025-07-28 18:48:42,878 INFO [io.qua.lan.mcp.run.htt.QuarkusStreamableHttpMcpTransport] (executor-thread-2) Request: {"jsonrpc":"2.0","id":0,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{"roots":{"listChanged":false}},"clientInfo":{"name":"langchain4j","version":"1.0"}}}
2025-07-28 18:48:42,881 INFO [io.qua.lan.mcp.run.htt.QuarkusStreamableHttpMcpTransport] (vert.x-eventloop-thread-0) Request: {"jsonrpc":"2.0","method":"notifications/initialized"}
2025-07-28 18:48:42,883 INFO [io.qua.lan.mcp.run.htt.QuarkusStreamableHttpMcpTransport] (vert.x-eventloop-thread-0) Response:
2025-07-28 18:48:42,884 INFO [io.qua.lan.mcp.run.htt.QuarkusStreamableHttpMcpTransport] (executor-thread-2) Request: {"jsonrpc":"2.0","id":1,"method":"tools/list"}
2025-07-28 18:48:42,887 WARN [io.qua.lan.mcp.run.htt.SseSubscriber] (vert.x-eventloop-thread-0) {"jsonrpc":"2.0","id":1,"result":{"tools":[{"description":"create a configmap in namespace","inputSchema":{"type":"object","required":["Info","data"],"properties":{"Info":{"type":"object","required":["name","namespace"],"properties":{"name":{"type":"string"},"namespace":{"type":"string"}},"additionalProperties":{"not":{}}},"data":{"type":"object","additionalProperties":{"type":"string"}}},"additionalProperties":{"not":{}}},"name":"create_configmap","outputSchema":{"type":"object","additionalProperties":{"not":{}}}},{"description":"create deployment in given namespace","inputSchema":{"type":"object","required":["name","namespace","replicas","containerName","containerImage"],"properties":{"containerImage":{"type":"string"},"containerName":{"type":"string"},"name":{"type":"string"},"namespace":{"type":"string"},"replicas":{"type":"integer"}},"additionalProperties":{"not":{}}},"name":"create_deployment","outputSchema":{"type":"object","additionalProperties":{"not":{}}}},{"description":"Create a pod in the namspace","inputSchema":{"type":"object","required":["name","namespace","containerName","containerImage"],"properties":{"containerImage":{"type":"string"},"containerName":{"type":"string"},"name":{"type":"string"},"namespace":{"type":"string"}},"additionalProperties":{"not":{}}},"name":"create_pod","outputSchema":{"type":"object","additionalProperties":{"not":{}}}},{"description":"create a generic key value secret in the namespace","inputSchema":{"type":"object","required":["Info","key","value"],"properties":{"Info":{"type":"object","required":["name","namespace"],"properties":{"name":{"type":"string"},"namespace":{"type":"string"}},"additionalProperties":{"not":{}}},"key":{"type":"string"},"value":{"type":"string"}},"additionalProperties":{"not":{}}},"name":"cr: com.fasterxml.jackson.core.io.JsonEOFException: Unexpected end-of-input: was expecting closing quote for a string value
at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 1790]
at com.fasterxml.jackson.core.base.ParserMinimalBase._reportInvalidEOF(ParserMinimalBase.java:642)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._finishString2(ReaderBasedJsonParser.java:2186)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser._finishString(ReaderBasedJsonParser.java:2173)
at com.fasterxml.jackson.core.json.ReaderBasedJsonParser.getText(ReaderBasedJsonParser.java:295)
at com.fasterxml.jackson.databind.deser.std.BaseNodeDeserializer._deserializeContainerNoRecursion(JsonNodeDeserializer.java:571)
at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:99)
at com.fasterxml.jackson.databind.deser.std.JsonNodeDeserializer.deserialize(JsonNodeDeserializer.java:24)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:342)
at com.fasterxml.jackson.databind.ObjectMapper._readTreeAndClose(ObjectMapper.java:5013)
at com.fasterxml.jackson.databind.ObjectMapper.readTree(ObjectMapper.java:3300)
at io.quarkiverse.langchain4j.mcp.runtime.http.SseSubscriber.accept(SseSubscriber.java:46)
at io.quarkiverse.langchain4j.mcp.runtime.http.QuarkusStreamableHttpMcpTransport.lambda$execute$3(QuarkusStreamableHttpMcpTransport.java:152)
at io.vertx.core.impl.ContextInternal.dispatch(ContextInternal.java:270)
at io.vertx.core.http.impl.HttpEventHandler.handleChunk(HttpEventHandler.java:51)
at io.vertx.core.http.impl.HttpClientResponseImpl.handleChunk(HttpClientResponseImpl.java:239)
at io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.lambda$new$0(Http1xClientConnection.java:432)
at io.vertx.core.streams.impl.InboundBuffer.handleEvent(InboundBuffer.java:279)
at io.vertx.core.streams.impl.InboundBuffer.write(InboundBuffer.java:157)
at io.vertx.core.http.impl.Http1xClientConnection$StreamImpl.handleChunk(Http1xClientConnection.java:730)
at io.vertx.core.impl.ContextImpl.execute(ContextImpl.java:327)
at io.vertx.core.impl.DuplicatedContext.execute(DuplicatedContext.java:158)
at io.vertx.core.http.impl.Http1xClientConnection.handleResponseChunk(Http1xClientConnection.java:913)
at io.vertx.core.http.impl.Http1xClientConnection.handleHttpMessage(Http1xClientConnection.java:834)
at io.vertx.core.http.impl.Http1xClientConnection.handleMessage(Http1xClientConnection.java:799)
at io.vertx.core.net.impl.ConnectionBase.read(ConnectionBase.java:159)
at io.vertx.core.net.impl.VertxHandler.channelRead(VertxHandler.java:153)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.channel.CombinedChannelDuplexHandler$DelegatingChannelHandlerContext.fireChannelRead(CombinedChannelDuplexHandler.java:436)
at io.netty.handler.codec.ByteToMessageDecoder.fireChannelRead(ByteToMessageDecoder.java:346)
at io.netty.handler.codec.ByteToMessageDecoder.channelRead(ByteToMessageDecoder.java:318)
at io.netty.channel.CombinedChannelDuplexHandler.channelRead(CombinedChannelDuplexHandler.java:251)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:442)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.AbstractChannelHandlerContext.fireChannelRead(AbstractChannelHandlerContext.java:412)
at io.netty.channel.DefaultChannelPipeline$HeadContext.channelRead(DefaultChannelPipeline.java:1357)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:440)
at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:420)
at io.netty.channel.DefaultChannelPipeline.fireChannelRead(DefaultChannelPipeline.java:868)
at io.netty.channel.nio.AbstractNioByteChannel$NioByteUnsafe.read(AbstractNioByteChannel.java:166)
at io.netty.channel.nio.NioEventLoop.processSelectedKey(NioEventLoop.java:796)
at io.netty.channel.nio.NioEventLoop.processSelectedKeysOptimized(NioEventLoop.java:732)
at io.netty.channel.nio.NioEventLoop.processSelectedKeys(NioEventLoop.java:658)
at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:562)
at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:998)
at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:1583)
2025-07-28 18:48:42,890 WARN [io.qua.lan.mcp.run.htt.SseSubscriber] (vert.x-eventloop-thread-0) Received event with null name
Metadata
Metadata
Assignees
Labels
No labels