spring-projects / spring-projects/spring-ai
MCP integration using WebMVC SSE
Nobody has claimed this yet.
- Dominant language
- Java
- Stars
- 9.5k
- Forks
- 2.9k
- Avg merge
- 1d 7h
- Merged PRs (30d)
- 6
Description
Bug description
I have implemented both the client and server components for the Model Context Protocol (MCP). Both communicate using Server-Sent Events (SSE), allowing real-time, streaming responses. This setup works as expected in most cases, and the client receives responses from the server as a continuous stream of data.
However, in certain scenarios - depending on the question asked, I encounter an error related to the parsing or serialization while returning the response in streaming.
The error that I face:
2025-05-22T11:03:41.070+05:30 ERROR 117009 --- [spring-boot-ai-mcp-client] [oundedElastic-2] o.s.ai.chat.model.MessageAggregator : Aggregation Error
io.modelcontextprotocol.spec.McpError: Failed to wait for the message endpoint
at io.modelcontextprotocol.client.transport.HttpClientSseClientTransport.sendMessage(HttpClientSseClientTransport.java:405) ~[mcp-0.9.0.jar:0.9.0]
at io.modelcontextprotocol.spec.McpClientSession.lambda$sendRequest$11(McpClientSession.java:232) ~[mcp-0.9.0.jar:0.9.0]
at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:61) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.SerializedSubscriber.onNext(SerializedSubscriber.java:99) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.onNext(FluxTimeout.java:181) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Operators$MonoInnerProducerBase.complete(Operators.java:2834) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.SinkOneMulticast.subscribe(SinkOneMulticast.java:101) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Mono.subscribe(Mono.java:4576) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Mono.block(Mono.java:1778) ~[reactor-core-3.7.5.jar:3.7.5]
at io.modelcontextprotocol.client.McpSyncClient.callTool(McpSyncClient.java:200) ~[mcp-0.9.0.jar:0.9.0]
at org.springframework.ai.mcp.SyncMcpToolCallback.call(SyncMcpToolCallback.java:115) ~[spring-ai-mcp-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.mcp.SyncMcpToolCallback.call(SyncMcpToolCallback.java:125) ~[spring-ai-mcp-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.model.tool.DefaultToolCallingManager.executeToolCall(DefaultToolCallingManager.java:205) ~[spring-ai-model-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.model.tool.DefaultToolCallingManager.executeToolCalls(DefaultToolCallingManager.java:128) ~[spring-ai-model-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.anthropic.AnthropicChatModel.lambda$internalStream$4(AnthropicChatModel.java:265) ~[spring-ai-anthropic-1.0.0-M8.jar:1.0.0-M8]
at reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:46) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.run(FluxSubscribeOn.java:194) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37) ~[reactor-core-3.7.5.jar:3.7.5]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:104) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Mono.block(Mono.java:1779) ~[reactor-core-3.7.5.jar:3.7.5]
... 15 common frames omitted
2025-05-22T11:03:41.080+05:30 ERROR 117009 --- [spring-boot-ai-mcp-client] [nio-8081-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] threw exception
io.modelcontextprotocol.spec.McpError: Failed to wait for the message endpoint
at io.modelcontextprotocol.client.transport.HttpClientSseClientTransport.sendMessage(HttpClientSseClientTransport.java:405) ~[mcp-0.9.0.jar:0.9.0]
at io.modelcontextprotocol.spec.McpClientSession.lambda$sendRequest$11(McpClientSession.java:232) ~[mcp-0.9.0.jar:0.9.0]
at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:61) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.SerializedSubscriber.onNext(SerializedSubscriber.java:99) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.onNext(FluxTimeout.java:181) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Operators$MonoInnerProducerBase.complete(Operators.java:2834) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.SinkOneMulticast.subscribe(SinkOneMulticast.java:101) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Mono.subscribe(Mono.java:4576) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Mono.block(Mono.java:1778) ~[reactor-core-3.7.5.jar:3.7.5]
at io.modelcontextprotocol.client.McpSyncClient.callTool(McpSyncClient.java:200) ~[mcp-0.9.0.jar:0.9.0]
at org.springframework.ai.mcp.SyncMcpToolCallback.call(SyncMcpToolCallback.java:115) ~[spring-ai-mcp-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.mcp.SyncMcpToolCallback.call(SyncMcpToolCallback.java:125) ~[spring-ai-mcp-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.model.tool.DefaultToolCallingManager.executeToolCall(DefaultToolCallingManager.java:205) ~[spring-ai-model-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.model.tool.DefaultToolCallingManager.executeToolCalls(DefaultToolCallingManager.java:128) ~[spring-ai-model-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.anthropic.AnthropicChatModel.lambda$internalStream$4(AnthropicChatModel.java:265) ~[spring-ai-anthropic-1.0.0-M8.jar:1.0.0-M8]
at reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:46) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.run(FluxSubscribeOn.java:194) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37) ~[reactor-core-3.7.5.jar:3.7.5]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:104) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Mono.block(Mono.java:1779) ~[reactor-core-3.7.5.jar:3.7.5]
... 15 common frames omitted
2025-05-22T11:03:41.081+05:30 ERROR 117009 --- [spring-boot-ai-mcp-client] [nio-8081-exec-3] o.a.c.c.C.[.[.[/].[dispatcherServlet] : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed: io.modelcontextprotocol.spec.McpError: Failed to wait for the message endpoint] with root cause
io.modelcontextprotocol.spec.McpError: Failed to wait for the message endpoint
at io.modelcontextprotocol.client.transport.HttpClientSseClientTransport.sendMessage(HttpClientSseClientTransport.java:405) ~[mcp-0.9.0.jar:0.9.0]
at io.modelcontextprotocol.spec.McpClientSession.lambda$sendRequest$11(McpClientSession.java:232) ~[mcp-0.9.0.jar:0.9.0]
at reactor.core.publisher.MonoCreate.subscribe(MonoCreate.java:61) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.InternalMonoOperator.subscribe(InternalMonoOperator.java:76) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.MonoFlatMap$FlatMapMain.onNext(MonoFlatMap.java:165) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxOnErrorResume$ResumeSubscriber.onNext(FluxOnErrorResume.java:79) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.SerializedSubscriber.onNext(SerializedSubscriber.java:99) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxTimeout$TimeoutMainSubscriber.onNext(FluxTimeout.java:181) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Operators$MonoInnerProducerBase.complete(Operators.java:2834) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.SinkOneMulticast.subscribe(SinkOneMulticast.java:101) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Mono.subscribe(Mono.java:4576) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Mono.block(Mono.java:1778) ~[reactor-core-3.7.5.jar:3.7.5]
at io.modelcontextprotocol.client.McpSyncClient.callTool(McpSyncClient.java:200) ~[mcp-0.9.0.jar:0.9.0]
at org.springframework.ai.mcp.SyncMcpToolCallback.call(SyncMcpToolCallback.java:115) ~[spring-ai-mcp-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.mcp.SyncMcpToolCallback.call(SyncMcpToolCallback.java:125) ~[spring-ai-mcp-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.model.tool.DefaultToolCallingManager.executeToolCall(DefaultToolCallingManager.java:205) ~[spring-ai-model-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.model.tool.DefaultToolCallingManager.executeToolCalls(DefaultToolCallingManager.java:128) ~[spring-ai-model-1.0.0-M8.jar:1.0.0-M8]
at org.springframework.ai.anthropic.AnthropicChatModel.lambda$internalStream$4(AnthropicChatModel.java:265) ~[spring-ai-anthropic-1.0.0-M8.jar:1.0.0-M8]
at reactor.core.publisher.FluxDefer.subscribe(FluxDefer.java:46) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.FluxSubscribeOn$SubscribeOnSubscriber.run(FluxSubscribeOn.java:194) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:84) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.scheduler.WorkerTask.call(WorkerTask.java:37) ~[reactor-core-3.7.5.jar:3.7.5]
at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:317) ~[na:na]
at java.base/java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:304) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[na:na]
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[na:na]
at java.base/java.lang.Thread.run(Thread.java:1583) ~[na:na]
Suppressed: java.lang.Exception: #block terminated with an error
at reactor.core.publisher.BlockingSingleSubscriber.blockingGet(BlockingSingleSubscriber.java:104) ~[reactor-core-3.7.5.jar:3.7.5]
at reactor.core.publisher.Mono.block(Mono.java:1779) ~[reactor-core-3.7.5.jar:3.7.5]
... 15 common frames omitted
2025-05-22T11:03:41.086+05:30 WARN 117009 --- [spring-boot-ai-mcp-client] [nio-8081-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Ignoring exception, response committed already: org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.LinkedHashMap] with preset Content-Type 'text/event-stream'
2025-05-22T11:03:41.086+05:30 WARN 117009 --- [spring-boot-ai-mcp-client] [nio-8081-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: No converter for [class java.util.LinkedHashMap] with preset Content-Type 'text/event-stream']
Environment
Java: 21
Spring-AI: 1.0.0-M8
Steps to reproduce
I have a very simple tool:
@Tool(description = "Get weather information by city name")
public String getWeather(String cityName) {
return "The weather in " + cityName + " is sunny with a temperature of 25°C.";
}
When I give a prompt like What is the weather in ABC city?
I get above mentioned error.
Expected behavior
Not getting this error. And return the response
Minimal Complete Reproducible example
The client exposes the following endpoint, which sends a prompt to the server and returns the streamed content as a Flux:
@GetMapping(produces = MediaType.TEXT_EVENT_STREAM_VALUE)
public Flux<String> ask(@RequestParam String question) {
return chatClient
.prompt(question)
.stream()
.content();
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by reproducing the WebMVC SSE client/server setup described in the issue and trace the failure from HttpClientSseClientTransport.sendMessage at line 405 through McpClientSession.sendRequest. Compare cases that stream successfully with those producing “Failed to wait for the message endpoint” and the subsequent HttpMessageNotWritableException; done means the affected streaming responses complete without either error.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- java, spring-boot
- Domain
- api, backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100