MCP 的 HTTP 传输已经从 HTTP+SSE 迁到 Streamable HTTP:旧端点是
/sse,新端点是/mcp。客户端报404 Not Found on GET request for ".../sse",说明请求打到了已经不存在的旧路径上。改用spring.ai.mcp.client.streamable-http.connections.<name>配置,url只写协议、主机、端口,路径交给默认值为/mcp的endpoint。版本差异要记住:Spring AI 1.0.0 的 MCP 客户端只有 stdio 和 SSE 两种 transport,Streamable HTTP 客户端到 1.1.0 才有,本文基线是 1.1.8。
Issue & Env(案发现场与环境)
- 业务场景:Spring Boot 应用通过
spring-ai-starter-mcp-client接一个远端 MCP Server。服务端进程或容器在跑,端口也通,客户端一连接就 404,工具列表始终是空的。 - 环境:Spring AI 1.1.8,Spring Boot 3.5.15,JDK 17。客户端配置还写着
spring.ai.mcp.client.sse.*,指向/sse;服务端已经只开放 Streamable HTTP 的/mcp。 - 一个容易误判的点:404 表示“服务活着,但没这个路径”,不是“连不上”。能拿到 HTTP 响应,说明网络、端口、网关都没问题,错的是 transport 类型和端点路径。
StackTrace(堆栈日志)
最先看到的通常是这一句,注意 URL 结尾的 /sse:
org.springframework.web.client.HttpClientErrorException$NotFound: 404 Not Found on GET request for "http://localhost:8080/sse"
完整堆栈从 HTTP 客户端一路冒到业务调用点:
org.springframework.web.client.HttpClientErrorException$NotFound: 404 Not Found on GET request for "http://localhost:8080/sse"
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:123)
at org.springframework.web.client.DefaultResponseErrorHandler.handleError(DefaultResponseErrorHandler.java:103)
at org.springframework.web.client.ResponseErrorHandler.handleError(ResponseErrorHandler.java:63)
at org.springframework.ai.mcp.client.common.transport.HttpClientSseClientTransport.lambda$start$0(HttpClientSseClientTransport.java:98)
at com.example.demo.mcp.McpToolService.callTool(McpToolService.java:33)
at com.example.demo.mcp.McpController.invoke(McpController.java:21)
at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:118)
如果打了请求日志,会看到客户端连的是某个已经不存在的旧路径,两种典型形态:
GET http://localhost:8080/sse 404
GET http://localhost:8080/mcp/sse 404
判断技巧用一条二值规则就够:
| 报错文案 | 含义 | 先查什么 |
|---|---|---|
Connection refused |
根本没连上 | 服务是否启动、端口是否写对 |
404 Not Found ... "/sse" |
连上了,路径不存在 | transport 和端点路径是否与新版 MCP 对齐 |
404 Not Found ... "/mcp" |
连上了,路径不存在 | 服务端是否真的开在 /mcp,或还没升级到 Streamable HTTP |
只要文案里出现 404 并且 URL 结尾是 /sse,先怀疑端点迁移,不要再往网络方向上查。
Reproduce(复现代码)
客户端按旧 SSE 配方写:
spring:
ai:
mcp:
client:
sse:
connections:
remote:
url: http://localhost:8081/sse
服务端只开放 Streamable HTTP 端点:
POST /mcp
GET /mcp
这段 YAML 语法没错,url 也指向了真实运行的服务,所以启动、注入、Bean 装配都不会报错。错的地方有两处:transport 选成了已 deprecated 的 SSE,路径又指向服务端从未提供的 /sse。请求打到不存在的路由上,服务端只能回 404。
Root Cause(根因分析)
端点模型变了:/sse → /mcp
HTTP+SSE 的模型是“客户端先 GET /sse 建立一条长连接,拿到一个 messages 回调地址,再往那个地址 POST 消息”。Streamable HTTP 把两步合成一步:同一个端点既接受 POST(发 JSON-RPC 请求),也接受 GET(需要时开服务端推送),路径约定为 /mcp。
端点名字变了,跟着一起变的还有三件事:
| 维度 | HTTP+SSE(deprecated) | Streamable HTTP |
|---|---|---|
| 客户端配置前缀 | spring.ai.mcp.client.sse |
spring.ai.mcp.client.streamable-http |
| 端点路径 | /sse(服务端自定,常见还有 /mcp/sse) |
/mcp(endpoint 的默认值) |
| 可用版本 | Spring AI 1.0.0 起 | Spring AI 1.1.0 起 |
规范已把 HTTP+SSE 标为 deprecated
MCP 官方规范把 HTTP+SSE transport 明确标记为 deprecated,并给出迁移目标是 Streamable HTTP。这不表示旧方案立刻失效,而是说新实现不再围绕它设计:新建服务端默认只挂 /mcp,老的 /sse 路由干脆不注册。404 就是这么来的。
版本差异:客户端支持两种,但不是同一时间点
Spring AI 1.0.0 的 MCP 客户端只有 stdio 和 SSE 两种 transport,Streamable HTTP 客户端是 1.1.0 才加进来的。所以排查前先确认版本:
- 项目跑在 1.1.8:
streamable-http配置可用,直接切过去。 - 项目还停在 1.0.0:没有
streamable-http配置项,只能升到 1.1 线,或者让服务端继续保留/sse兼容路由。
把 SSE 的配置键搬到只开 /mcp 的服务端,无论 URL 怎么写,结果都是 404。
The Fix(解决方案)
1. 客户端改成 Streamable HTTP 配置
spring:
ai:
mcp:
client:
streamable-http:
connections:
remote:
url: http://localhost:8081
endpoint: /mcp
两条规则:
url只写协议、主机和端口,不要带路径。endpoint的默认值就是/mcp,只有服务端挂在别的路径时才需要显式写这一行。
2. 用 curl 确认端点真实可用
curl -i -X POST http://localhost:8081/mcp \
-H "Content-Type: application/json" \
-H "Accept: application/json, text/event-stream" \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'
Accept 头必须同时带上 application/json 和 text/event-stream 两种类型,否则服务端可能直接拒掉请求,让你误判成端点不存在。
结果二值化判定:
- 返回
200且响应体里出现result:端点可用,问题只在客户端配置,回到第 1 步。 - 返回
404:路径不对。先确认服务端到底开在/mcp还是旧的/sse,再回头改配置。
3. 对齐版本依赖
- 客户端要用
streamable-http,Spring AI 必须在 1.1.0 及以上(本文基线 1.1.8),starter 用spring-ai-starter-mcp-client,版本交给 BOM 统一管理。 - 服务端一时只有
/sse:要么把服务端升到支持 Streamable HTTP,要么客户端在这段时间里继续用spring.ai.mcp.client.sse并指向服务端真实路径,两边 transport 必须一致。 - 换了 transport 之后顺手验证一次工具列表能不能拉全。只看到连接成功、工具为空,说明协议通了但服务端工具没注册,那是另一类问题。
小结
- 404 是“服务活着但没这个路径”,不是“连不上”;先看报错 URL 的结尾是
/sse还是/mcp。 - MCP 端点已从
/sse迁到/mcp,HTTP+SSE 在规范里标为 deprecated;Spring AI 用streamable-http配置对齐。 - 客户端侧只需
url(协议+主机+端口)加endpoint(默认/mcp)两项,url里不要带路径。 - 判断端点可用性用带双
Accept头的 curl:200加result即可用,404说明路径错。 - 版本差异要盯住:Streamable HTTP 客户端从 Spring AI 1.1.0 才有,1.0.0 只有 stdio 和 SSE。
References(参考来源)
- MCP Client Boot Starter — Spring AI 官方文档spring-docs
- Streamable HTTP — MCP 官方规范mcp-spec
- Deprecated Features — MCP 官方规范mcp-spec
- Upgrade Notes — Spring AI 官方文档spring-docs
