SpringAI MCP Server开发避坑指南:SSE端点访问失败的7个常见原因
最近在帮团队搭建基于SpringAI的MCP Server时,遇到了一个让人头疼的问题:服务明明启动成功了,但SSE端点就是访问不了。控制台没有任何报错,浏览器访问/sse端点要么是404,要么是连接超时。这个问题困扰了我们整整两天,最后发现原因竟然是一个配置项的拼写错误。
如果你也在开发SpringAI MCP Server时遇到了SSE端点无法访问的问题,这篇文章就是为你准备的。我整理了7个最常见的坑点,每个都配有具体的排查步骤和解决方案。这些经验都是我们在实际项目中踩出来的,希望能帮你少走弯路。
1. 依赖冲突:WebMVC与WebFlux的隐形战争
第一个坑往往出现在项目依赖配置上。SpringAI提供了两个不同的SSE传输实现:spring-ai-starter-mcp-server-webmvc和spring-ai-starter-mcp-server-webflux。这两个starter不能同时使用,否则会导致Spring Boot的自动配置冲突。
1.1 如何识别依赖冲突
当你同时引入了两个starter时,Spring Boot会默认优先使用WebMVC的实现。但如果你项目中还有其他WebFlux的依赖,情况就会变得复杂。下面是一个典型的错误配置示例:
<!-- 错误示例:同时引入了两个SSE starter -->
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
<version>1.0.0-M7</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
<version>1.0.0-M7</version>
</dependency>
</dependencies>
注意:Spring Boot的默认行为是,当
DispatcherServlet和DispatcherHandler同时存在于classpath时,会优先使用DispatcherServlet(即WebMVC)。这意味着即使你引入了WebFlux starter,也可能被WebMVC覆盖。
1.2 正确的依赖配置
根据你的项目技术栈,选择其中一个starter:
如果你使用Spring WebMVC(传统的Servlet容器):
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
<version>1.0.0-M7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
如果你使用Spring WebFlux(响应式编程):
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
<version>1.0.0-M7</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-webflux</artifactId>
</dependency>
1.3 排查工具
要确认你的项目实际使用的是哪个Web框架,可以在启动类中添加以下代码:
@SpringBootApplication
public class McpServerApplication {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(McpServerApplication.class, args);
// 检查Web应用类型
String webApplicationType = context.getEnvironment()
.getProperty("spring.main.web-application-type");
System.out.println("Web应用类型: " + webApplicationType);
// 检查已注册的Bean
String[] beanNames = context.getBeanNamesForType(DispatcherServlet.class);
if (beanNames.length > 0) {
System.out.println("检测到WebMVC (DispatcherServlet)");
}
String[] handlerBeanNames = context.getBeanNamesForType(DispatcherHandler.class);
if (handlerBeanNames.length > 0) {
System.out.println("检测到WebFlux (DispatcherHandler)");
}
}
}
如果发现两个框架同时存在,可以通过在application.yml中显式指定来强制使用其中一个:
spring:
main:
web-application-type: servlet # 强制使用WebMVC
# 或者
# web-application-type: reactive # 强制使用WebFlux
2. 配置项拼写:一个字母引发的血案
这是最隐蔽也最常见的错误。SpringAI MCP Server的配置项有严格的命名规范,大小写和连字符都不能错。
2.1 关键配置项的正确写法
下面这个表格列出了所有与SSE端点相关的配置项及其正确写法:
| 配置项 | 正确写法 | 错误写法示例 | 影响 |
|---|---|---|---|
| SSE端点路径 | sse-endpoint |
sseEndpoint、sse_endpoint |
端点无法注册 |
| SSE消息端点 | sse-message-endpoint |
sseMessageEndpoint |
客户端无法发送消息 |
| 服务器类型 | type |
serverType |
同步/异步模式错误 |
| 服务器名称 | name |
serverName |
客户端连接标识错误 |
| 启用SSE | stdio: false |
enable-sse: true |
默认就是启用SSE |
2.2 完整的正确配置示例
spring:
ai:
mcp:
server:
# 服务器基本信息
name: weather-mcp-server
version: 1.0.0
type: SYNC # 或 ASYNC(WebFlux推荐使用ASYNC)
# SSE传输配置
sse-endpoint: /sse # 客户端连接端点
sse-message-endpoint: /mcp/messages # 客户端发送消息端点
# 可选:基础URL前缀
base-url: /api/v1 # 如果设置,完整端点将是 /api/v1/sse
# 可选:保持连接间隔
keep-alive-interval: 30s
# 必须禁用STDIO模式
stdio: false
# 能力配置
capabilities:
tool: true
resource: true
prompt: true
completion: true
2.3 配置验证脚本
创建一个简单的测试Controller来验证配置是否正确生效:
@RestController
@RequestMapping("/debug")
public class DebugController {
@Autowired
private Environment environment;
@GetMapping("/config")
public Map<String, Object> getMcpConfig() {
Map<String, Object> config = new HashMap<>();
// 检查所有MCP相关配置
String[] configKeys = {
"spring.ai.mcp.server.name",
"spring.ai.mcp.server.version",
"spring.ai.mcp.server.type",
"spring.ai.mcp.server.sse-endpoint",
"spring.ai.mcp.server.sse-message-endpoint",
"spring.ai.mcp.server.stdio",
"spring.ai.mcp.server.base-url"
};
for (String key : configKeys) {
config.put(key, environment.getProperty(key));
}
// 检查端点是否已注册
config.put("sse-endpoint-accessible",
checkEndpointAccessible("/sse"));
config.put("message-endpoint-accessible",
checkEndpointAccessible("/mcp/messages"));
return config;
}
private boolean checkEndpointAccessible(String path) {
try {
// 这里可以添加实际的端点检查逻辑
return true;
} catch (Exception e) {
return false;
}
}
}
启动服务后访问http://localhost:8080/debug/config,可以查看所有配置项的实际值。
3. 端口与上下文路径:被忽略的基础设置
即使所有配置都正确,如果端口或上下文路径设置有问题,客户端仍然无法连接到SSE端点。
3.1 端口冲突检测
Spring Boot应用默认使用8080端口,如果这个端口已被占用,服务会启动失败。但更隐蔽的情况是:服务启动了,但监听的端口不是你期望的。
检查当前应用实际监听的端口:
# Linux/Mac
lsof -i :8080
netstat -tuln | grep 8080
# Windows
netstat -ano | findstr :8080
在代码中动态获取端口信息:
@Component
public class PortChecker implements ApplicationListener<WebServerInitializedEvent> {
@Override
public void onApplicationEvent(WebServerInitializedEvent event) {
int port = event.getWebServer().getPort();
String contextPath = event.getApplicationContext()
.getEnvironment()
.getProperty("server.servlet.context-path", "");
System.out.println("应用实际监听的端口: " + port);
System.out.println("上下文路径: " + contextPath);
System.out.println("SSE端点完
195




被折叠的 条评论
为什么被折叠?



