1. 为什么 MCP Server 跑起来了客户端却连不上很多人在 Spring Boot 里引入spring-ai-starter-mcp-server-webmvc之后日志里能看到 Tomcat 起来了、SSE 端点也注册了但用 MCP 客户端去连就是握手失败或者工具列表拉不出来。问题往往不在 Spring AI 本身而是两件事没对齐一是settings.json里客户端要连的地址和传输方式跟服务端实际暴露的不一致二是模型调用链路上的 API Key 没有统一出口每个工具各自读环境变量本地调试时经常漏配。这篇就围绕 MCP Server Boot Starter 的接入配置展开给你一份可以直接复制的settings.json骨架把 TaoToken 的统一 Key 和 API 通道填进去再走一遍启动后的连通性验证命令。适合正在本地快速跑通 MCP 服务、又想把 Key 管理收拢到一处的开发者。读完你能拿到三样东西一份能跑的配置骨架、一条能验证服务端 SSE 是否正常的 curl 命令、以及一套排查握手失败的检查顺序。MCP 全称 Model Context Protocol你可以把它理解成模型和外部工具之间的“USB 接口协议”服务端把工具、资源、提示模板按统一格式暴露出来客户端按同一套格式去发现和调用。Spring AI 的 Boot Starter 做的事就是把这套协议塞进 Spring Boot 的自动配置体系里让你用几个Bean和几行 yaml 就能起一个 MCP Server。2. 前置准备依赖、TaoToken Key 与通道位置先把依赖定下来。本地调试我一般选 WebMVC 版本因为它自带 web 容器SSE 端点开箱即用比 STDIO 更适合用 curl 直接验证。dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server-webmvc/artifactId /dependency如果你要的是命令行/桌面工具那种无 web 依赖的形态换成spring-ai-mcp-server-spring-boot-starter走 STDIO 传输。两者自动配置类不同WebMVC 会激活McpWebMvcServerAutoConfiguration同时把spring-boot-starter-web带进来。接下来是 Key 和通道。TaoToken 在这里扮演的是统一 API 出口你不需要在每个工具里散落不同的 Key而是让 MCP Server 内部调用模型时都走同一个 base URL 和同一个 Key。控制台里创建 Key 的入口在 https://taotoken.net/console Key 列表页在 https://taotoken.net/api-keys 。API 通道地址是https://taotoken.net/api注意这个地址不带任何查询参数直接作为 base URL 使用。我习惯把 Key 放在环境变量里而不是写死在settings.json或 yaml 中这样提交代码时不会泄露export TAOTOKEN_API_KEYsk-你的Key然后在 Spring 配置里引用它。下面这份application.yml是 WebMVC SYNC 的最小可用骨架注意base-url和sse-message-endpoint这两项它们直接决定客户端要连哪个路径。server: port: 8080 spring: ai: mcp: server: name: demo-mcp-server version: 1.0.0 type: SYNC instructions: 本地调试用的 MCP 服务暴露天气查询工具 sse-endpoint: /sse sse-message-endpoint: /mcp/message capabilities: tool: true resource: true prompt: true completion: true request-timeout: 30s关于typeSYNC 用McpSyncServer适合请求-响应式的直接调用ASYNC 用McpAsyncServer基于 Project Reactor适合非阻塞场景。本地调试先用 SYNC出问题好定位。3. 可复制的 settings.json 骨架与工具注册MCP 客户端侧的settings.json是连接配置的核心。不同客户端字段名略有差异但结构一致一个mcpServers对象里面每个键是一个服务名值是传输方式加地址。下面这份骨架以 SSE 传输为例把 TaoToken 的通道信息也一并放进去方便你在同一个文件里管理。{ mcpServers: { demo-spring-boot: { transport: sse, url: http://localhost:8080/sse, messageUrl: http://localhost:8080/mcp/message, headers: { Authorization: Bearer ${TAOTOKEN_API_KEY} }, env: { TAOTOKEN_BASE_URL: https://taotoken.net/api, TAOTOKEN_API_KEY: ${TAOTOKEN_API_KEY} }, timeout: 30000 } } }几个字段要重点核对。url对应服务端的sse-endpoint默认是/ssemessageUrl对应sse-message-endpoint默认是/mcp/message。如果你在 yaml 里改了base-url比如设成/api/v1那客户端这边两个地址都要加上前缀变成http://localhost:8080/api/v1/sse和http://localhost:8080/api/v1/mcp/message。这是最常见的连不上的原因改了一边忘了另一边。headers里的 Authorization 是给需要鉴权的场景用的。TaoToken 的 Key 通过环境变量注入settings.json里只写占位符避免明文落盘。服务端这边工具通过ToolCallbackProvider注册自动配置会扫描所有ToolCallback类型的 bean 并合并Service public class WeatherService { Tool(description 根据城市名查询天气) public String getWeather(String cityName) { return cityName 今天晴气温 22 度; } } SpringBootApplication public class McpServerApplication { public static void main(String[] args) { SpringApplication.run(McpServerApplication.class, args); } Bean public ToolCallbackProvider weatherTools(WeatherService weatherService) { return MethodToolCallbackProvider.builder() .toolObjects(weatherService) .build(); } }工具按名称去重同名工具只保留第一个出现的。如果你有多个 bean 提供工具自动配置会把它们合并成一个列表不用手动聚合。4. 启动与连通性验证curl 命令与预期返回配置写完启动应用./mvnw spring-boot:run看到 Tomcat 在 8080 端口启动、日志里出现 MCP Server 初始化相关的行就说明服务端起来了。接下来验证 SSE 端点是否真的在推事件。开一个终端执行curl -N -H Accept: text/event-stream http://localhost:8080/sse-N关闭缓冲让你能实时看到推送。预期返回类似event: endpoint data: /mcp/message?sessionId8f3a1c2e-...这行endpoint事件就是服务端告诉客户端“后续消息往这个地址发”。拿到sessionId之后再开一个终端发一条初始化请求curl -X POST http://localhost:8080/mcp/message?sessionId8f3a1c2e-... \ -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.0} } }如果服务端正常第一个终端会推回一条message事件内容是 initialize 的结果包含serverInfo和capabilities。看到capabilities.tools非空说明工具已经注册成功。再发一条tools/list就能拉到工具清单curl -X POST http://localhost:8080/mcp/message?sessionId8f3a1c2e-... \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:2,method:tools/list,params:{}}预期在 SSE 流里看到getWeather这个工具名。到这一步服务端和协议层就通了。如果你还想在浏览器里直接跟模型对话验证工具调用效果可以打开 https://taotoken.net/model-chat 把同一个 Key 填进去试一轮。5. 本篇常见错排查握手失败curl 连/sse直接断开。先确认依赖是 WebMVC 版本而不是 STDIO 版本。STDIO 版本不监听端口curl 当然连不上。再看spring.ai.mcp.server.enabled是不是被误设成 false。SSE 能连上但 POST 消息返回 404。九成是sse-message-endpoint和客户端messageUrl不一致。默认值/mcp/message容易被记成/mcp/messages多一个 s 就 404。核对 yaml 和settings.json两边。工具列表为空。检查capabilities.tool是否为 true以及ToolCallbackProviderbean 有没有被扫描到。如果用了Tool注解但没注册 provider自动配置不会凭空发现它。另外确认工具方法所在类是被 Spring 管理的 bean。请求超时。request-timeout默认 20 秒工具内部如果调用了外部模型接口链路慢的时候容易超。本地调试可以调到 30 到 60 秒。注意这个超时对所有请求生效包括工具调用、资源读取和提示操作。改了base-url后客户端连不上。base-url是前缀会拼在sse-endpoint和sse-message-endpoint前面。设成/api/v1后客户端两个地址都要带这个前缀漏改一个就连不通。Key 读取不到。环境变量在启动应用的 shell 里 export而不是在另一个终端。用echo $TAOTOKEN_API_KEY确认当前 shell 能看到。settings.json里的${TAOTOKEN_API_KEY}是占位符需要客户端支持环境变量替换不支持的话得用客户端自己的密钥管理方式。6. 把 Key 收拢到一处之后配置跑通之后你会发现真正省事的地方在于 Key 不再散落。MCP Server 内部调用模型走https://taotoken.net/api这一个通道客户端连接走settings.json里的一份配置环境变量只维护一个TAOTOKEN_API_KEY。后面加新工具、换模型改的都是同一处。如果你打算把这个 MCP Server 长期挂在本地做编码辅助或者 Agent 实验建议顺手看一下 Coding Plan 的额度管理方式入口在 https://taotoken.net/coding-plan 把长期调用的配额和临时调试的 Key 分开避免调试时把额度跑光。接入文档在 https://taotoken.net/doc 里面有各语言 SDK 的调用示例需要换语言实现时可以直接对照。最后留一个我踩过的坑settings.json改完记得重启客户端很多 MCP 客户端只在启动时读一次配置热改不生效会让你误以为配置写错了。
阅读完成 · 觉得有帮助?