StackTraces
Spring AI已驗證

Spring AI MCP 客戶端 404:端點從 /sse 遷到 /mcp

@debug_master12 天前更新閱讀 6 min00

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(參考來源)

最後更新於 2026-09-29

這篇幫到你了嗎?

剛解決了一個棘手的報錯?花兩分鐘記錄下來,幫助下一個遇到同樣問題的開發者。

貢獻一條解法