-
Notifications
You must be signed in to change notification settings - Fork 1.8k
Description
Bug description
I'm using the following versions:
spring-ai-starter-mcp-server-webmvc:1.0.0 (MPC server)
spring-ai-starter-mcp-client:1.0.0 (MPC client)
The client successfully sends requests and generates responses. However, most of the time, the client does not wait for the server's full response and instead returns prematurely with a default output.
As a result,The connection between the client and server is aborted.
Server throws the following exception:
java.io.EOFException: null at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.fillReadBuffer(NioEndpoint.java:1295) ~[tomcat-embed-core-10.1.41.jar:10.1.41] at org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper.read(NioEndpoint.java:1183) ~[tomcat-embed-core-10.1.41.jar:10.1.41]
025-08-03T12:15:41.002+10:00 DEBUG 20823 --- [sse-mcp-server-demo] [nio-8080-exec-2] o.apache.coyote.http11.Http11Processor : Error state [CLOSE_CONNECTION_NOW] reported while processing request
2025-08-03T12:15:41.002+10:00 DEBUG 20823 --- [sse-mcp-server-demo] [nio-8080-exec-2] o.apache.coyote.http11.Http11Processor : Socket: [org.apache.tomcat.util.net.NioEndpoint$NioSocketWrapper@7514622d:org.apache.tomcat.util.net.NioChannel@7bd392ff:java.nio.channels.SocketChannel[connected local=/[127.0.0.1:8080](http://127.0.0.1:8080/) remote=/127.0.0.1:65117]], Status in: [OPEN_READ], State out: [CLOSED]
2025-08-03T12:21:46.570+10:00 DEBUG 20823 --- [sse-mcp-server-demo] [ SIGINT handler] java.lang.Runtime : Runtime.exit() called with status: 130
However request header is not massive, printed in server logs
connection: Upgrade, HTTP2-Settings content-length: 69 host: localhost:8080 http2-settings: AAEAAEAAAAIAAAAAAAMAAAAAAAQBAAAAAAUAAEAAAAYABgAA upgrade: h2c user-agent: Java-http-client/21.0.8 accept: text/event-stream cache-control: no-cache content-type: application/json
Environment
Spring AI version: 1.0.0
Java version: 21
Running in local host
Steps to reproduce
- Start the server.
- Start the client.
- Observe the logs — they indicate that the client and server are communicating initially.
- The server responds to one or two messages, then throws the error mentioned above.
- The client continues running but returns a default response, stating that no tool is defined.
Client responds before server returns with
2025-08-03T12:15:18.586+10:00 INFO 20994 --- [nio-8081-exec-1] mcp_client.ClientController : User message: get all stores
2025-08-03T12:15:18.586+10:00 INFO 20994 --- [nio-8081-exec-1] mcp_client.ClientController : AI response: To get all stores, you can use the following function:
python stores = spring_ai_mcp_client_server1_getAllStores()
Expected behavior
The client should wait for the server's response and return that response, rather than falling back to a default message.
Minimal Complete Reproducible example
This is server application.yaml
spring: application: name: sse-mcp-server-demo ai: mcp: server: enabled: true stdio: false name: sse-mcp-server-demo version: 1.0.0 resource-change-notification: true tool-change-notification: true prompt-change-notification: true sse-endpoint: /api/v1/sse sse-message-endpoint: /api/v1/mcp type: sync capabilities: completion: true prompt: true resource: true tool: true server: error: include-message: always max-http-request-header-size: 640
This is client application.yaml
server: port: 8081 spring: application: ollama: base-url: http://localhost:11434/ timeout: 300s chat: enabled: true options: model: qwen3:8b ai: mcp: client: enabled: true name: spring-ai-mcp-client version: 1.0.0 initialized: true request-timeout: 300s type: sync root-change-notification: true toolcallback.enabled: true sse: connections: server1: url: http://localhost:8080/ sse-endpoint: /api/v1/sse
Client is using chat client
@Bean fun chatClient(builder: ChatClient.Builder, toolCallbackProvider: ToolCallbackProvider): ChatClient { return builder .defaultToolCallbacks(toolCallbackProvider) .defaultAdvisors( MessageChatMemoryAdvisor.builder( MessageWindowChatMemory.builder().build() ) .build() ) .build(); }
Service using chat client to prompt
@Service class AiServiceImpl(val chatClient: ChatClient) : AiService { override fun complete(message: String): String? { return chatClient.prompt() .user(message) .call() .content(); } }