
1. 为什么要在 Java 里折腾 MCP ServerMCP Server 说白了就是给大模型装的一双手模型本身只会生成文字但通过 MCP 协议它能调用你写好的 Java 方法去查数据库、读文件、调内部接口。对 Java 团队来说这意味着不用把已有业务逻辑重写一遍直接暴露成工具就能被模型用起来。我最近在做一个内部工单系统需要让模型能查工单状态、改优先级、拉历史记录。摆在面前的选择有两个spring ai mcp 和 solon ai mcp。前者背靠 Spring 官方生态后者是国产轻量框架。两个都试了一遍踩了不少坑这篇就把工具注册、传输层配置、启动流程这三块的差异讲清楚并给出两套能直接复制跑起来的最小实现。适合谁看手里有 JDK 8 存量项目、想快速接 MCP 的后端同学或者用 Spring Boot 3 JDK 17、追求生态完整性的团队。如果你还在纠结选哪个框架看完这篇应该能拍板。先说结论方向Spring AI MCP 的模块化分层更规范但配置链路长Solon AI MCP 注解驱动单文件就能跑起来对 JDK 版本也友好。两者都能把 endpoint 和鉴权参数指向 TaoToken 这类兼容 OpenAI 协议的服务下面会具体演示怎么改。2. TaoToken 前置准备Key、Base URL 与模型 ID不管用哪个框架MCP Server 本身只是工具提供方真正要调模型还得有个兼容的 API 入口。TaoToken 提供的就是这个入口它的 API 地址是 https://taotoken.net/api兼容 OpenAI 的 chat completions 协议所以 Spring AI 和 Solon AI 都能直接对接。你需要先拿到三样东西第一是 API Key。登录后在控制台的 API Keys 页面创建格式类似sk-开头的一串字符。这个 Key 要放进配置文件别硬编码在代码里。第二是 Base URL。注意区分两个地址官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 调用地址是 https://taotoken.net/api 。配置里填的是后者不要带 UTM 参数。第三是 Model ID。在模型对话页面能看到当前可用的模型列表选一个你需要的比如通用的对话模型或者偏代码的模型。MCP 场景下建议选工具调用能力强的不然模型可能不认你注册的 tool。提示Key 泄露等于别人能刷你的额度建议在控制台设置用量上限并且每个项目单独建 Key方便排查和吊销。把这三样记下来后面两套配置都要用。如果你还没建 Key先去 https://taotoken.net/api-keys 创建整个过程不到一分钟。3. 可复制配置两套 MCP Server 最小实现这一节是重点两套代码都能直接复制到项目里跑。先讲 Spring AI MCP再讲 Solon AI MCP最后给一个统一的 TaoToken 接入配置。3.1 Spring AI MCP 实现JDK 17Spring AI MCP 的依赖坐标是spring-ai-mcp-server-spring-boot-starter。注意版本M6 之后 API 有调整下面用的是较稳定的写法。pom.xml 加依赖dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-mcp-server-spring-boot-starter/artifactId version1.0.0-M6/version /dependency工具类用Tool注解暴露方法Service public class TicketService { Tool(description 根据工单ID查询当前状态) public String getTicketStatus(String ticketId) { // 实际项目里换成数据库查询 return 工单 ticketId 状态处理中; } Tool(description 修改工单优先级priority 取值 HIGH/MEDIUM/LOW) public String updatePriority(String ticketId, String priority) { return 工单 ticketId 优先级已改为 priority; } }关键一步是注册ToolCallbackProviderSpring AI 不会自动扫描Tool必须显式声明Configuration public class McpConfig { Bean public ToolCallbackProvider ticketTools(TicketService service) { return MethodToolCallbackProvider.builder() .toolObjects(service) .build(); } }传输层配置在 application.yml 里spring: ai: mcp: server: name: ticket-mcp-server version: 1.0.0 protocol: SSE sse-endpoint: /mcp/sse启动后 SSE 端点就是http://localhost:8080/mcp/sse。Spring AI 的传输层是三层架构客户端/服务器层负责协议协商会话层管理连接状态传输层处理 SSE 或 STDIO。这个分层的好处是换传输方式不用改业务代码坏处是配置项多第一次配容易漏。3.2 Solon AI MCP 实现JDK 8Solon AI MCP 的依赖是solon-ai-mcp版本用 3.3.1-M1 比较稳。它对 JDK 版本没硬性要求JDK 8 也能跑这点对存量系统很友好。pom.xmldependency groupIdorg.noear/groupId artifactIdsolon-ai-mcp/artifactId version3.3.1-M1/version /dependency工具定义和端点配置写在同一个类里注解驱动McpServerEndpoint(name ticket-service, sseEndpoint /mcp/sse) public class TicketTools { ToolMapping(description 根据工单ID查询当前状态) public String getTicketStatus(ToolParam(工单ID) String ticketId) { return 工单 ticketId 状态处理中; } ToolMapping(description 修改工单优先级) public String updatePriority(ToolParam(工单ID) String ticketId, ToolParam(优先级) String priority) { return 工单 ticketId 优先级已改为 priority; } }启动类只需要标准的 Solon 启动public class App { public static void main(String[] args) { Solon.start(App.class, args); } }对比一下就很明显Solon 不需要单独的配置类McpServerEndpoint一个注解搞定端点声明ToolMapping直接标在方法上。Spring AI 则要拆成工具类 配置类两个文件还得手动构建ToolCallbackProvider。3.3 把 endpoint 和鉴权指向 TaoTokenMCP Server 本身不调模型但你的客户端比如 Claude Code、Cline要调模型时需要把 Base URL 和 Key 指向 TaoToken。以常见的客户端配置为例JSON 片段如下{ mcpServers: { ticket-server: { url: http://localhost:8080/mcp/sse, env: { OPENAI_BASE_URL: https://taotoken.net/api, OPENAI_API_KEY: sk-你的Key, OPENAI_MODEL: 你的ModelID } } } }如果你用的是 Codex 的 auth.json写法类似{ base_url: https://taotoken.net/api, api_key: sk-你的Key, model: 你的ModelID }三件套缺一不可Base URL 指向 https://taotoken.net/api Key 用控制台创建的Model ID 填模型对话页面里看到的。少任何一个都会在调用时报错。4. 验证请求一次工具调用跑通连通性配置写完得验证真的能调通。分两步先确认 MCP Server 起来了再确认模型能通过 TaoToken 调用到工具。第一步启动 Spring Boot 或 Solon 应用看日志里有没有 SSE 端点注册成功的输出。Spring AI 会打印类似Registered SSE endpoint at /mcp/sse的日志Solon 会打印McpServerEndpoint registered: ticket-service。第二步用 curl 测 SSE 端点是否可达curl -N http://localhost:8080/mcp/sse正常会保持连接并返回事件流。如果直接断开说明端点没注册成功回去检查配置。第三步在客户端里发一条会触发工具调用的消息比如帮我查一下工单 T-1001 的状态。模型收到请求后会通过 TaoToken 的 API 返回一个 tool_call客户端再把这个调用转发给你的 MCP Server。成功的话你会看到类似这样的返回{ tool: getTicketStatus, arguments: {ticketId: T-1001}, result: 工单 T-1001 状态处理中 }实测下来Spring AI 在工具调用时对参数类型校验更严格如果Tool方法参数名和客户端传的不一致会直接报No such parameter。Solon 相对宽松但ToolParam的 description 建议写清楚否则模型可能传错参数。注意如果模型返回的是纯文本而不是 tool_call说明模型没识别出工具检查 Model ID 是否支持 function calling以及工具 description 是否足够明确。5. 本篇常见错排查这一节列几个我实际踩到的报错对照着排查能省不少时间。401 Unauthorized最常见。检查OPENAI_API_KEY是不是复制时带了空格或者 Key 被吊销了。TaoToken 的 Key 在控制台能看到状态确认是 active。另外确认 Base URL 是 https://taotoken.net/api 而不是官网地址。local proxy failed / connection refused客户端连不上 MCP Server。先确认应用真的启动了端口没被占用。Spring AI 默认端口 8080Solon 也是如果冲突改server.port。再确认 SSE 路径和配置里写的一致/mcp/sse和/mcp/sse/在某些客户端里行为不同。reading choices 报错这个通常出现在模型返回格式不符合预期时。检查 Model ID 是否填对有些模型不支持工具调用换一个支持 function calling 的。另外确认请求体里tools字段格式正确Spring AI 和 Solon 生成的格式略有差异。OAuth 相关报错如果你用的是 Claude Code 这类需要 OAuth 的客户端确认鉴权流程走完了。TaoToken 的 API Key 模式不需要 OAuth但客户端如果强制走 OAuth 流程需要在设置里切换成 API Key 模式。工具注册了但模型不调用检查Tool或ToolMapping的 description 是否具体。写查询工单不如写根据工单ID查询当前处理状态返回状态文本。模型靠 description 判断什么时候用这个工具写得太泛它就不调。JDK 版本不匹配Spring AI MCP 要求 JDK 17如果你项目是 JDK 8编译会直接报Unsupported class file major version。这种情况要么升级 JDK要么换 Solon AI MCP。6. 选型建议与接入入口两套框架跑下来我的判断是如果你的项目已经是 Spring Boot 3 JDK 17团队熟悉 Spring 生态选 Spring AI MCP它的分层设计在复杂场景下更好维护多端点、权限控制这些都有现成方案。如果你是 JDK 8 存量系统或者想快速验证原型Solon AI MCP 的注解驱动更省事单文件就能定义工具和端点。接入 TaoToken 的部分两者没区别都是改 Base URL、Key、Model ID 三件套。需要创建 Key 的去 https://taotoken.net/api-keys 想先看看模型列表和对话效果的去 https://taotoken.net/chat 接入文档在 https://taotoken.net/doc 。如果你打算长期跑编码类 Agent 任务可以了解下 Coding Planhttps://taotoken.net/coding-plan 。最后给个实用技巧MCP Server 的工具方法尽量保持幂等模型可能会重复调用同一个工具。查询类方法无所谓但修改类方法最好加个去重逻辑比如根据 ticketId 操作类型做短期缓存避免模型抽风连续改三次优先级。这个坑我在测试环境遇到过生产上提前防住能省很多事。