ARTICLE DETAIL

资讯详情

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

不会 MCP?用 Spring AI 一步搭建 Server 并改到 TaoToken

不会 MCP?用 Spring AI 一步搭建 Server 并改到 TaoToken 1. 从零理解 MCP Server 到底解决什么问题很多 Java 开发者第一次听到 MCP 会有点懵它既不是 RPC 框架也不是消息队列而是一套让 AI 客户端比如 Claude Desktop、Cline、Cursor能发现并调用你后端能力的协议。你可以把它理解成给 AI 用的 OpenAPI你写好工具方法AI 通过tools/list看到有哪些能力再通过tools/call传参调用返回结构化结果。传统做法是让 AI 直接调你的 REST 接口但问题很明显接口语义靠 prompt 描述、参数靠模型猜、返回格式不统一。MCP 把这些标准化了——工具名、描述、参数 schema、返回结构都由协议约定客户端不用为每个后端写适配代码。Spring AI 1.0 之后把 MCP Server 的自动装配做得很完整你只需要三件事加依赖、写Tool方法、注册ToolCallbackProvider。HTTP/SSE 的传输层、JSON-RPC 的协议解析、initialize握手全部由 starter 处理不用自己写 Controller。这篇面向 Spring Boot 3.4/3.5 Java 17 的开发者从 pom 依赖一路写到本地 curl 验证最后把 endpoint 和鉴权统一改到 TaoToken 通道。适合谁手上有现成业务 Service用户、订单、日志都行想快速把它暴露成 MCP 工具给 AI 用的人。2. TaoToken 前置准备统一通道与 Key 获取在写代码之前先把通道这件事定下来。MCP Server 本身跑在你本地或内网但 AI 客户端调用模型时需要一个稳定的模型入口。TaoToken 提供的就是这个统一入口一个 Base URL 一个 Key兼容 OpenAI 风格的/v1/chat/completions也支持 Anthropic 协议Claude Code、Cline、Codex 这类工具都能直接接。为什么要在 MCP 场景里提这个因为 MCP Server 只负责工具真正驱动工具调用的还是模型。你本地调试时可以用 curl 手动发tools/call但真实使用是 AI 客户端在跑客户端连模型 → 模型决定调哪个工具 → 客户端通过 SSE 把tools/call发到你的 Server。所以模型通道和 MCP 通道是两条线前者用 TaoToken 统一后者是你自己写的 Spring Boot 服务。获取 Key 的路径打开 https://taotoken.net/api-keys 登录后创建一个 API Key形如sk-xxxxxxxx。这个 Key 后面会用在两处一是 AI 客户端的模型配置二是如果你想让 MCP Server 内部再调模型比如工具里做摘要也可以复用。Base URL 记两个OpenAI 兼容https://taotoken.net/api/v1Anthropic 兼容https://taotoken.net/api模型 ID 按需选比如claude-sonnet-4-5、gpt-4o这类。文档在 https://taotoken.net/doc 接入细节和参数说明都在里面。想先在网页上验证模型通不通可以直接用 https://taotoken.net/models 对话测试确认 Key 有效再写代码能省掉一半排障时间。注意MCP Server 的 endpoint 是你自己的服务地址比如http://localhost:8081/sse不要和 TaoToken 的 Base URL 混在一起。前者是工具通道后者是模型通道。3. 可复制配置pom、application.yml 与 Tool 注册这一节是全文核心所有片段都能直接粘。先看依赖管理Spring AI 用 BOM 统一版本避免各 starter 版本打架。properties java.version17/java.version spring-ai.version1.0.0/spring-ai.version /properties dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version${spring-ai.version}/version typepom/type scopeimport/scope /dependency /dependencies /dependencyManagement dependencies dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server-webmvc/artifactId /dependency /dependencies选webmvc而不是webflux是因为大多数 Spring Boot 业务项目本身就是 MVC 栈混入 WebFlux 容易出线程模型问题。这个 starter 会自动装配WebMvcSseServerTransportProvider把/sse和/mcp/message挂到 DispatcherServlet 上。接着是配置文件建议单独放application-mcp.yml用spring.profiles.include引入避免污染主配置。spring: application: name: mirror-mcp-server ai: mcp: server: name: mirror-mcp-server version: 1.0.0 instructions: Mirror APP MCP tools for user profile and journal operations. sse-endpoint: /sse sse-message-endpoint: /mcp/message stdio: falsestdio: false表示走 HTTP/SSE 网络模式适合服务端部署如果做本地命令行工具才用 stdio。sse-endpoint是客户端建立长连接的路径sse-message-endpoint是客户端 POST 消息的路径这两个值客户端要能访问到。然后是工具类用Tool标方法、ToolParam标参数描述。注意这里不需要RestControllerSpring AI 会通过MethodToolCallbackProvider扫描。Service RequiredArgsConstructor public class MirrorMcpToolService { private final UsersService usersService; Tool(description 检查 Mirror MCP 服务是否可用) public ApiResponseString health() { return ApiResponse.success(mirror-mcp is ready); } Tool(description 根据用户ID获取用户资料) public ApiResponseUsersProfileDTO getUserProfile( ToolParam(description 用户ID) String userId) { if (!StringUtils.hasText(userId)) { return ApiResponse.error(userId不能为空); } Users user usersService.getByUserId(userId); if (user null) { return ApiResponse.error(用户不存在); } return ApiResponse.success(UsersProfileDTO.fromEntity(user)); } }最后在启动类注册ToolCallbackProvider把工具对象交给框架SpringBootApplication(scanBasePackages {com.mirror.app, com.mirror.mcp}) public class MirrorMcpServerApplication { public static void main(String[] args) { SpringApplication.run(MirrorMcpServerApplication.class, args); } Bean public ToolCallbackProvider mirrorMcpTools(MirrorMcpToolService mirrorMcpToolService) { return MethodToolCallbackProvider.builder() .toolObjects(mirrorMcpToolService) .build(); } }到这里 Server 端就齐了。scanBasePackages要覆盖到工具类所在包否则Tool方法扫不到tools/list会返回空数组——这是新手最常见的坑之一。4. 验证请求从 SSE 握手到 tools/call 成功返回启动服务后假设端口 8081先建立 SSE 连接。这一步必须保持终端不关因为它是长连接。curl -N -H Accept: text/event-stream http://localhost:8081/sse你会先收到一条 endpoint 事件data 里带着 sessionIddata: /mcp/message?sessionId3742b51e-0fd5-473a-a3bc-779ffdf205a4这个 sessionId 是后续所有调用的凭证。新开一个终端按顺序发三个请求。第一步 initialize 协商协议版本curl -X POST http://localhost:8081/mcp/message?sessionId3742b51e-0fd5-473a-a3bc-779ffdf205a4 \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:init-1,method:initialize,params:{protocolVersion:2024-11-05,capabilities:{experimental:{},roots:{listChanged:false},sampling:{}},clientInfo:{name:curl-client,version:0.1.0}}}第二步发 initialized 通知表示握手完成curl -X POST http://localhost:8081/mcp/message?sessionId3742b51e-0fd5-473a-a3bc-779ffdf205a4 \ -H Content-Type: application/json \ -d {jsonrpc:2.0,method:notifications/initialized,params:{}}第三步列工具确认getUserProfile和health都在curl -X POST http://localhost:8081/mcp/message?sessionId3742b51e-0fd5-473a-a3bc-779ffdf205a4 \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:tools-1,method:tools/list,params:{}}返回里能看到每个工具的name、description和inputSchemainputSchema就是ToolParam生成的。最后真正调用业务方法curl -X POST http://localhost:8081/mcp/message?sessionId3742b51e-0fd5-473a-a3bc-779ffdf205a4 \ -H Content-Type: application/json \ -d {jsonrpc:2.0,id:call-user-1,method:tools/call,params:{name:getUserProfile,arguments:{userId:8b004b18f9104694ab50fad99ff60d80}}}成功时返回结构里result.content[0].text就是你的ApiResponse序列化后的 JSON。如果 userId 不存在会返回你定义的用户不存在错误信息说明参数解析和业务逻辑都通了。整个链路背后是四层MethodToolCallbackProvider扫描Tool→McpToolUtils转成 MCP 的SyncToolSpecification→McpServerAutoConfiguration装进McpSyncServer→McpServerSseWebMvcAutoConfiguration暴露 HTTP 入口。运行时tools/call进来McpAsyncServer.toolsCallRequestHandler()按工具名路由最终回调MethodToolCallback#call把 JSON 参数反序列化成 Java 形参、反射调用、再把返回值转成CallToolResult。5. 本篇常见错排查401、local proxy failed 与 reading choices报错一401 Unauthorized模型侧如果你在 AI 客户端里配了 TaoToken 但报 401先检查 Key 是否带Bearer前缀以及 Base URL 是否写成了https://taotoken.net/api/v1OpenAI 兼容而不是漏掉/v1。Anthropic 协议走https://taotoken.net/api。三件套必须齐全Base URL Key Model ID缺一个都会 401 或 404。报错二local proxy failed这个通常出现在客户端配置了本地代理端口但服务没起。检查客户端里的 proxy 设置如果不需要就清空。MCP Server 本身是本地 HTTP 服务不需要经过任何代理直接http://localhost:8081/sse即可。报错三reading choices 相关解析失败模型返回体解析不到choices字段多半是 Base URL 指向了 Anthropic 协议端点却用了 OpenAI 格式的请求或者反过来。确认客户端协议类型和 Base URL 匹配OpenAI 格式用/api/v1Anthropic 格式用/api。报错四tools/list 返回空Tool方法没被扫到。检查三点scanBasePackages是否包含工具类包、ToolCallbackProviderBean 是否注册、方法是否是public。另外Tool方法不能是函数式接口实现框架会过滤掉。报错五OAuth 相关报错部分客户端默认走 OAuth 流程但你的 MCP Server 没配鉴权。如果只是本地调试客户端里关掉 OAuth 选项如果要上生产需要在 Server 前面加一层鉴权比如 Spring Security API Key 校验再让客户端带上对应 header。报错六sessionId 失效SSE 连接断了之后 sessionId 就作废后续 POST 会返回 session not found。重新跑一遍/sse拿新 sessionId 即可。生产环境建议客户端做好重连逻辑。6. 把 endpoint 与鉴权统一改到 TaoToken 通道前面验证的是本地直连。真实使用时AI 客户端需要同时配两条通道模型通道走 TaoToken工具通道走你的 MCP Server。以 Cline 为例模型配置里填 Base URLhttps://taotoken.net/api/v1、Key 用sk-xxx、Model ID 选claude-sonnet-4-5MCP 配置里填 Server 的 SSE 地址http://localhost:8081/sse。如果你用 Claude Code模型侧配置在~/.claude/settings.json或环境变量里把ANTHROPIC_BASE_URL指向https://taotoken.net/apiANTHROPIC_API_KEY填 TaoToken 的 Key。MCP 侧在~/.claude.json或项目级配置里加{ mcpServers: { mirror-mcp: { url: http://localhost:8081/sse } } }Codex 用户则在~/.codex/auth.json里配 Keyconfig.toml里配 Base URL 和 Model ID。三件套同样是 Base URL Key Model ID一个都不能少。长期跑编码任务或 Agent 场景建议用 Coding Plan配额和稳定性比按次调用更划算入口在 https://taotoken.net/coding-plan 。如果只是偶尔验证模型通不通用模型对话页面就够了https://taotoken.net/models 。接入文档和参数细节统一看 https://taotoken.net/doc API Key 管理在 https://taotoken.net/api-keys 。最后提醒一个实操细节MCP Server 部署到服务器后sse-endpoint建议加一层反向代理并启用 HTTPS客户端配置里把localhost换成你的域名。鉴权可以在反向代理层做也可以在 Spring Security 里加一个 Filter 校验 header 里的 token这样工具通道和模型通道各自独立、互不影响。
返回列表