refactor(transport): Replace SseEmitter with queue-based SSE implementation in WebMvc transport

Replaces Spring's SseEmitter with a custom BlockingQueue-based SSE implementation in
WebMvcSseServerTransport for improved event delivery control and connection management.

The new implementation:
- Uses BlockingQueue for reliable event queuing and delivery
- Adds proper session management with dedicated SSEEvent record
- Improves error handling and timeout management
- Adds comprehensive integration tests

Resolves #57
This commit is contained in:
Christian Tzolov 2025-01-11 14:55:52 +01:00 • committed by Christian Tzolov
commit edbd78465c
5 changed files with 726 additions and 104 deletions

View file

@ -27,6 +27,13 @@
<artifactId>mcp-webmvc-sse-transport</artifactId>
<version>${spring-ai-mcp.version}</version>
</dependency>
<!-- Used only for the client webflux transport -->
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>mcp-webflux-sse-transport</artifactId>
<version>${spring-ai-mcp.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.experimental</groupId>
<artifactId>spring-ai-mcp</artifactId>

View file

@ -0,0 +1,32 @@
/*
* Copyright 2024 - 2024 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.springframework.ai.mcp.sample.webmvc.client;
import org.springframework.ai.mcp.client.transport.WebFluxSseClientTransport;
import org.springframework.web.reactive.function.client.WebClient;
/**
* @author Christian Tzolov
*/
public class ClientWebFluxSse {
public static void main(String[] args) {
var transport = new WebFluxSseClientTransport(WebClient.builder().baseUrl("http://localhost:8080"));
new SampleClient(transport).run();
}
}

View file

@ -0,0 +1,13 @@
package org.springframework.ai.mcp.sample.webmvc.server;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class McpMvcServerApplication {
public static void main(String[] args) {
SpringApplication.run(McpMvcServerApplication.class, args);
}
}

View file

@ -31,8 +31,6 @@ import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestClient;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.function.RouterFunction;
import org.springframework.web.servlet.function.ServerResponse;
@ -40,14 +38,6 @@ import org.springframework.web.servlet.function.ServerResponse;
@EnableWebMvc
public class McpServerConfig implements WebMvcConfigurer {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
converter.setSupportedMediaTypes(List.of(org.springframework.http.MediaType.APPLICATION_JSON,
org.springframework.http.MediaType.TEXT_EVENT_STREAM));
converters.add(converter);
}
private static final Logger logger = LoggerFactory.getLogger(McpServerConfig.class);
@Bean

View file

@ -1,8 +1,8 @@
# spring.main.web-application-type=none
spring.main.web-application-type=SERVLET
# NOTE: You must disable the banner and the console logging
# to allow the STDIO transport to work !!!
spring.main.banner-mode=off
# logging.pattern.console=
logging.pattern.console=
transport.mode=sse