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
