ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

配置 MCP 服务端 sse-message-endpoint 与 sse-endpoint 的避坑清单:从 Spring AI 到 TaoToken 的 base-url 对齐

配置 MCP 服务端 sse-message-endpoint 与 sse-endpoint 的避坑清单:从 Spring AI 到 TaoToken 的 base-url 对齐 1. 从 404 说起sse-message-endpoint 与 base-url 的路径拼接陷阱如果你正在用 Spring AI 搭 MCP 服务端大概率踩过这个坑客户端连上了/api/v1/sse握手也成功了但服务端日志里紧接着冒出一个 404报错路径是/api/v1/mcp/message。你回头翻application.yml明明写的是sse-message-endpoint: /api/v1/mcp/messagebase-url: /api/v1看起来天衣无缝结果就是不通。把base-url注释掉再把sse-message-endpoint改成/api/v1/mcp/message反而正常了。这个现象的本质是 Spring AI MCP Server 在拼装 SSE 事件流里返回给客户端的endpoint字段时对base-url和sse-message-endpoint做了二次前缀叠加。SSE 协议本身是单向长连接服务端通过event: endpoint把「你接下来往哪个地址 POST 消息」告诉客户端。如果这个地址被拼错客户端就会拿着一个不存在的路径去发请求404 就来了。这篇内容面向本地调试和联调场景把sse-endpoint、sse-message-endpoint、base-url三者的关系拆开讲清楚给出可复制的application.yml、pom.xml、curl 验证命令以及把 base-url 对齐到 TaoToken 统一 API 通道后逐项核对端点行为的方法。适合正在用 Spring AI 1.1.x 接 MCP 服务端、被路径拼接绕晕的开发者。核心检索词就是 mcp、sse-message-endpoint、sse-endpoint、spring ai、base-url 这几个下面逐个落到配置和验证上。先说清楚两个端点的分工。sse-endpoint是客户端建立 SSE 长连接的入口客户端 GET 这个地址服务端保持连接并推送事件。sse-message-endpoint是消息回传通道客户端收到endpoint事件后往这个地址 POST JSON-RPC 消息。两者是「一收一发」的配对关系缺一不可。base-url则是服务端在生成endpoint事件时给 message 路径加的前缀。问题就出在这个前缀到底加几次、加在哪一层。我试过在本地 8085 端口起服务客户端配url: http://localhost:8085、sse-endpoint: /api/v1/sse服务端配base-url: /api/v1、sse-message-endpoint: /api/v1/mcp/message。抓包看到 SSE 流里返回的endpoint事件内容是/api/v1/api/v1/mcp/message前缀叠了两次客户端自然 404。这就是最典型的坑base-url和sse-message-endpoint里都带了/api/v1。理解了这个机制后面的配置就有章法了。要么让base-url留空、sse-message-endpoint写全路径要么base-url写前缀、sse-message-endpoint只写相对部分。两种都行但不能两边都写全。下面第二节先把 TaoToken 的接入准备讲清楚因为联调时你往往需要把模型调用也统一到一个通道上避免本地 Key 满天飞。2. TaoToken 接入准备统一 Key 与 API 通道本地调试 MCP 服务端时服务端本身可能还要调用大模型能力比如工具里做意图识别、结果润色。这时候如果每个服务都散落一个厂商 Key联调会非常乱。把模型调用统一到 TaoToken 的 API 通道好处是 Base URL 和 Key 只有一份换模型只改 Model ID端点行为也更容易对齐排查。TaoToken 的官网入口是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 基址是 https://taotoken.net/api 。注意 API 地址后面不加 UTM 参数配置里直接写这个基址即可。你需要先在控制台创建 API Key控制台地址是 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content Key 管理页在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。拿到 Key 之后建议先别急着往 Spring AI 里塞用最朴素的方式验证通道是否通。模型对话的在线调试页在 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 可以先在那里发一条消息确认 Key 有效、模型可选中。这一步能排除掉「Key 本身有问题」这类干扰项后面排查 MCP 端点 404 时就不会怀疑到模型通道上。如果你后续要做长期编码或 Agent 类任务Coding Plan 的入口是 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。Claude Code 相关的接入说明在 https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。这里要强调一个对齐思路MCP 服务端的base-url管的是 MCP 自己的 SSE 端点前缀和 TaoToken 的 API Base URL 是两码事不要混。TaoToken 的 Base URL 是给模型调用用的MCP 的 base-url 是给 SSE 端点拼接用的。联调时把这两个概念分开才不会出现「改了模型 Base URL 结果 MCP 端点 404」的乌龙。下面第三节给出完整的可复制配置。3. 可复制配置application.yml 与 pom.xml 对齐先给依赖。Spring AI MCP Server 用 WebMVC 版本BOM 版本对齐到 1.1.8Java 21。下面这段可以直接贴进pom.xmlAlibaba 的 BOM 按需保留不影响 MCP 本身。?xml version1.0 encodingUTF-8? project xmlnshttp://maven.apache.org/POM/4.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd modelVersion4.0.0/modelVersion groupIdcom.ai/groupId artifactIdmcp-server/artifactId version1.0-SNAPSHOT/version properties maven.compiler.source21/maven.compiler.source maven.compiler.target21/maven.compiler.target project.build.sourceEncodingUTF-8/project.build.sourceEncoding /properties parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.5.9/version /parent dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server-webmvc/artifactId /dependency /dependencies dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version1.1.8/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement /project然后是application.yml。这里给两种写法任选其一关键是别让前缀叠两次。写法 Abase-url留空sse-message-endpoint写全路径。这种最直观适合本地调试。spring: application: name: mcp-server ai: mcp: server: name: mcp-server1 version: 1.0.0 type: SYNC sse-endpoint: /api/v1/sse sse-message-endpoint: /api/v1/mcp/message stdio: false server: port: 8085写法 Bbase-url写前缀sse-message-endpoint只写相对部分。这种适合你确实需要统一前缀的场景。spring: application: name: mcp-server ai: mcp: server: name: mcp-server1 version: 1.0.0 type: SYNC base-url: /api/v1 sse-endpoint: /sse sse-message-endpoint: /mcp/message stdio: false server: port: 8085注意写法 B 里sse-endpoint也去掉了/api/v1因为base-url会作用到 SSE 入口的注册路径上。如果你只改 message 不改 sse客户端连的地址和服务端注册的地址就对不上会直接连不上而不是 404。这一点很多人忽略。客户端配置对应写法 Aspring: ai: mcp: client: mcp-server: url: http://localhost:8085 sse-endpoint: /api/v1/sse客户端配置对应写法 Bspring: ai: mcp: client: mcp-server: url: http://localhost:8085 sse-endpoint: /api/v1/sse客户端这边sse-endpoint始终写完整路径因为它不参与服务端的 base-url 拼接逻辑它只是告诉客户端「去哪连」。message 地址是服务端通过 SSE 事件下发的客户端不用配。如果你在服务端里还要调模型把 TaoToken 的通道配上Base URL 用 https://taotoken.net/api Key 从控制台拿Model ID 按你选的填。这三件套Base URL Key Model ID在 Cline MCP、Codex auth.json、CC Switch 这类工具里也是同样的结构配的时候逐项核对别把 MCP 的 base-url 和模型的 Base URL 填串了。4. 验证请求curl 抓 SSE 事件流与 message 回传配置写完别急着上客户端先用 curl 把 SSE 流抓出来看。这一步能直接看到服务端下发的endpoint事件内容路径对不对一目了然。curl -N -H Accept: text/event-stream http://localhost:8085/api/v1/sse-N关闭缓冲保证事件实时输出。正常的话你会看到类似这样的流event: endpoint data: /api/v1/mcp/message event: message data: {jsonrpc:2.0,id:1,result:{...}}重点看event: endpoint后面那行data。如果它是/api/v1/api/v1/mcp/message说明前缀叠了两次回到第三节改成写法 A 或写法 B。如果它是/api/v1/mcp/message说明拼接正确客户端可以正常 POST。拿到正确的 message 地址后手动发一条 JSON-RPC 初始化请求验证回传通道curl -X POST http://localhost:8085/api/v1/mcp/message \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:1,method:initialize,params:{protocolVersion:2024-11-05,capabilities:{},clientInfo:{name:curl-test,version:1.0}}}如果返回 200 且 body 里有result说明 message 通道通了。如果返回 404说明你 POST 的地址和服务端下发的地址不一致回去看 SSE 流里的endpoint事件。如果返回 400多半是 JSON-RPC 格式或 Content-Type 问题检查请求头。再验证一次 SSE 入口本身是否注册成功curl -I http://localhost:8085/api/v1/sse返回 200 或 405取决于方法都算正常返回 404 说明sse-endpoint路径没注册上检查base-url是否和sse-endpoint冲突。把 TaoToken 的模型通道也顺手验一下确认 Base URL 和 Key 可用curl https://taotoken.net/api/v1/models \ -H Authorization: Bearer $TAOTOKEN_API_KEY能列出模型列表就说明通道没问题。这一步和 MCP 端点验证分开做出问题时能快速定位是模型通道还是 MCP 端点的问题。5. 常见报错排查401、local proxy failed、reading choices、OAuth联调时遇到的报错不止 404下面按真实报错逐项对照。404 Not Found on /api/v1/mcp/message最常见就是本文主题。SSE 流里endpoint事件路径和客户端 POST 路径不一致。解决base-url和sse-message-endpoint不要同时带相同前缀二选一。401 Unauthorized模型通道的 Key 无效或没带上。检查Authorization: Bearer头确认 Key 从 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 复制完整没有多余空格。如果 MCP 服务端本身配了鉴权也要检查 SSE 请求头。local proxy failed本地代理配置干扰了请求。检查环境变量HTTP_PROXY、HTTPS_PROXY是否指向了不可用的地址本地调试时把NO_PROXY加上localhost,127.0.0.1。这个报错和 MCP 端点无关是网络层问题。Error reading choices / reading choices这是模型响应解析阶段的报错通常出现在服务端调模型时返回体格式不符合预期。检查 Base URL 是否写成了 https://taotoken.net/api 而不是带/v1的完整路径具体以接入文档为准Model ID 是否拼写正确。接入文档在 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 。OAuth 相关报错如果客户端或工具走了 OAuth 流程检查回调地址和 token 端点配置。Claude Code 接入场景的说明在 https://taotoken.net/ClaudeCodeAnthropic?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 按文档核对三件套。排查顺序建议先 curl 抓 SSE 流看endpoint事件再 curl POST message 地址最后才上完整客户端。这样能把问题范围缩到最小。每次改完配置重启服务别热加载Spring AI 的端点注册在启动时完成热加载可能不生效。6. 把 base-url 对齐到 TaoToken 通道后的核对清单当你把模型调用统一到 TaoToken 通道后MCP 端点行为和模型通道行为要分开核对避免互相干扰。下面这份清单可以逐项打勾。第一项确认 MCP 的base-url和 TaoToken 的 API Base URL 是两个独立配置。前者管 SSE 端点前缀后者管模型调用。配置里别把 https://taotoken.net/api 填到 MCP 的base-url上那会导致 SSE 端点路径变成https://taotoken.net/api/api/v1/sse这种荒谬结果。第二项SSE 流里的endpoint事件路径和客户端实际 POST 的路径必须逐字符一致。用 curl 抓一次肉眼比对。第三项模型通道的三件套Base URL Key Model ID在服务端配置里齐全。Base URL 用 https://taotoken.net/api Key 从控制台拿Model ID 按需选。这三件套在 Cline MCP、Codex auth.json、CC Switch 里结构相同配的时候逐项核对。第四项本地调试时NO_PROXY包含localhost,127.0.0.1避免 local proxy failed。第五项改完配置重启服务重新 curl 验证 SSE 流和 message 回传。第六项如果要做长期编码或 Agent 任务Coding Plan 入口在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 按需接入。最后给一个实用技巧在服务端加一行日志把生成的endpoint事件内容打出来。Spring AI 的 SSE 事件生成在McpServerSseController附近你可以在返回前打印一下最终路径。这样每次启动就能在日志里看到拼接结果不用每次都 curl。联调阶段这行日志能省不少时间。配置对齐之后MCP 服务端的 SSE 握手和 message 回传就能稳定跑通剩下的就是业务逻辑了。
返回列表