ARTICLE DETAIL

资讯详情

深耕编程入门与网站建设的一线实战洞察。

用 Solon AI 从零构建 MCP 工具服务:让 AI Agent 拥有真实世界的能力(TaoToken 统一 Key 接入版)

用 Solon AI 从零构建 MCP 工具服务:让 AI Agent 拥有真实世界的能力(TaoToken 统一 Key 接入版) 1. 为什么 Java 开发者需要自己写 MCP 工具服务你可能已经用过不少 AI 助手它们聊天很流畅但一旦你问「帮我查一下今天北京的天气」「把这条记录写进数据库」它们就开始含糊其辞。原因很简单模型本身只活在文本世界里它没有手也没有脚。MCPModel Context Protocol就是给模型装上手和脚的那套协议它定义了 AI 模型如何发现并调用外部工具——查天气、读文件、发请求、操作数据库都通过统一的工具描述暴露给模型。对 Java 开发者来说这件事以前有点尴尬。主流 MCP 示例大多用 Python 或 TypeScript 写Java 生态里要么依赖 Spring Boot 那一整套重配置要么得自己手搓 JSON-RPC。Solon AI 的出现改变了这个局面它基于 Solon 框架启动快、依赖少用McpTool注解就能把一个普通 Java 方法变成 AI 可调用的工具。你不需要理解协议底层的握手细节框架会帮你把方法签名、参数说明转成模型能读懂的 JSON Schema。这篇文章要交付的是一条完整链路用 Solon AI 搭一个 MCP 工具服务定义McpTool本地启动再通过 TaoToken 的统一 Key 和 API 通道把模型接进来让 Agent 真正调用你写的工具。适合谁有 Java 基础、想给 AI Agent 加真实世界能力、又不想被重型框架拖住的开发者。读完你能拿到可复制的工程骨架、配置片段和验证命令而不是一堆概念。我试过用纯手写 JSON-RPC 的方式对接模型光是处理工具描述和参数校验就写了两百多行换成 Solon AI 之后核心代码不到三十行。下面从环境准备开始一步步来。2. TaoToken 统一 Key 与 Solon AI 工程骨架准备在写工具之前先把「模型从哪来」这件事解决掉。MCP 服务本身只负责暴露工具真正决定调用哪个工具的是背后的模型。你需要一个能稳定访问模型 API 的通道TaoToken 在这里扮演的就是统一入口的角色一个 Key、一个 Base URL就能对接多种模型省去你在多个平台之间来回切换配置的麻烦。TaoToken 的官网是 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content API 地址是 https://taotoken.net/api 。注意 API 地址后面不加任何查询参数保持干净。你需要先去控制台创建一个 API Key路径在 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsoleutm_campaignrewrite 创建好的 Key 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 管理。如果你只是想先验证模型通不通可以用模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 快速试一句。工程骨架用 Maven 构建JDK 17 起步。pom.xml里加三个依赖Solon AI 核心、Solon Web用来起 HTTP 服务、fastjson2解析工具返回的 JSON。版本号建议用 2.7.x 系列和 Solon 主版本对齐。dependencies dependency groupIdorg.noear/groupId artifactIdsolon-ai/artifactId version2.7.0/version /dependency dependency groupIdorg.noear/groupId artifactIdsolon-web/artifactId version2.7.0/version /dependency dependency groupIdcom.alibaba.fastjson2/groupId artifactIdfastjson2/artifactId version2.0.40/version /dependency /dependencies目录结构保持简单src/main/java下放启动类和工具类src/main/resources下放app.yml配置文件。Solon 默认会扫描启动类所在包及其子包所以工具类放在启动类同级或子包里都能被自动发现。配置文件app.yml里写两件事服务端口和模型接入信息。模型这块用 TaoToken 的 Base URL 和你的 Key。注意 Key 不要硬编码进代码提交到仓库用环境变量或者本地配置文件这里为了演示直接写在 yml 里你实际用的时候记得换成${TAOTOKEN_API_KEY}这种占位。server: port: 8080 solon: ai: model: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} model-id: claude-sonnet-4-20250514这里model-id填你实际要用的模型标识TaoToken 支持多种模型具体可用的 ID 在文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里查。Base URL、Key、Model ID 这三件套是后面所有配置的基础缺一不可。如果你用的是 Claude Code 这类工具配置方式类似只是文件位置不同Claude Code 的接入说明在 https://taotoken.net/claudecode?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite 。环境准备好之后先别急着写复杂工具从最小的可运行服务开始确认 Solon 能起来、MCP 端点能响应再往上叠功能。这样出问题的时候排查范围小。3. 可复制的 McpTool 定义与 settings 配置片段现在进入核心部分定义工具。Solon AI 的工具定义靠两个注解——McpTool标在方法上McpParam标在参数上。框架会读取这些注解生成模型能理解的工具描述。描述写得越清楚模型选对工具、填对参数的概率越高。先写一个计算器工具验证整条链路。类上加Component让 Solon 扫描到方法上加McpTool每个参数加McpParam。import org.noear.solon.annotation.Component; import org.noear.solon.ai.mcp.annotation.McpTool; import org.noear.solon.ai.mcp.annotation.McpParam; Component public class CalculatorTools { McpTool(description 执行数学计算支持加、减、乘、除四则运算) public String calculate( McpParam(description 第一个数字) double a, McpParam(description 操作符可选 - * /) String operator, McpParam(description 第二个数字) double b) { double result; switch (operator) { case : result a b; break; case -: result a - b; break; case *: result a * b; break; case /: if (b 0) return 错误除数不能为零; result a / b; break; default: return 错误不支持的操作符 operator; } return String.format(%.2f %s %.2f %.2f, a, operator, b, result); } }启动类里把 Solon 跑起来MCP 端点默认挂在/mcp你也可以改。import org.noear.solon.Solon; public class McpServerApp { public static void main(String[] args) { Solon.start(McpServerApp.class, args); } }接下来是配置片段。如果你用的是支持 MCP 的客户端比如某些 IDE 插件或 Agent 工具它们通常读一个settings.json或类似的配置文件来发现 MCP 服务。下面这段是通用的 MCP 服务注册格式把本地 Solon 服务注册进去同时把模型通道指向 TaoToken。{ mcpServers: { solon-tools: { url: http://localhost:8080/mcp, transport: http } }, model: { baseUrl: https://taotoken.net/api, apiKey: 你的TaoToken Key, modelId: claude-sonnet-4-20250514 } }注意baseUrl是https://taotoken.net/api不要加多余的路径。apiKey从 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 拿。modelId按你实际用的模型填。这三件套——Base URL、Key、Model ID——在任何 MCP 客户端里都是必须的格式可能略有差异但字段含义一致。如果你用的是 Codex 这类工具它的auth.json里也是类似的三件套结构只是字段名可能叫base_url、api_key、model。Cline 的 MCP 配置则是在插件设置里填服务地址和模型信息。不管哪种核心都是把「工具服务地址」和「模型通道」两件事配清楚。工具描述里有个细节值得注意description不要写得太笼统。比如「查询天气」不如「查询指定城市的实时天气返回温度、湿度、天气状况」来得有用。模型是靠这段文字判断该不该调用这个工具的描述越具体误调用越少。参数描述同理McpParam里写清楚单位、格式、可选值能省掉很多模型填错参数的麻烦。4. 本地启动与 Agent 调用验证请求配置写完启动服务。命令行里跑mvn compile exec:java或者直接在 IDE 里运行McpServerApp的 main 方法。看到 Solon 打印出启动日志、端口 8080 监听成功就说明服务起来了。先用 curl 直接打 MCP 端点确认工具能被调用。MCP over HTTP 的请求体格式是 JSON-RPC 风格工具名和参数放在params里。curl -X POST http://localhost:8080/mcp \ -H Content-Type: application/json \ -d { jsonrpc: 2.0, id: 1, method: tools/call, params: { name: calculate, arguments: {a: 10, operator: , b: 5} } }正常返回应该包含10.00 5.00 15.00这个结果。如果返回的是工具列表而不是执行结果说明你调的是tools/list方法换成tools/call再试。这一步验证的是「工具服务本身能不能被调用」和模型无关。接下来验证模型能不能通过 TaoToken 通道调用这个工具。用模型对话页面 https://taotoken.net/chat?utm_sourcetaotoken_aicg_blog_endutm_contentchatutm_campaignrewrite 发一句「用计算器算一下 10 加 5」如果模型配置正确、工具注册正确它会返回工具调用请求你的 Solon 服务执行后把结果回传模型再组织成自然语言回答。如果你想在代码里验证可以用 Solon AI 的客户端能力发一个带 tools 的请求。核心是把 MCP 服务的工具描述作为tools参数传给模型模型返回tool_calls时你解析出工具名和参数调用本地 MCP 端点再把结果塞回对话。// 伪代码示意调用流程 // 1. 从 MCP 服务拉取工具列表 // 2. 把工具列表转成模型 API 的 tools 参数 // 3. 发送用户消息 tools 给 https://taotoken.net/api // 4. 解析返回的 tool_calls执行本地工具 // 5. 把工具结果作为新消息回传拿到最终回答实测下来最容易出问题的环节是工具描述和模型理解之间的偏差。比如你写了个getWeather工具但描述里没说是「实时」天气模型可能在你问「明天天气」时也调用它结果返回的是当前天气。解决办法是在描述里明确边界或者在工具内部对参数做校验返回清晰的错误提示让模型自己纠正。验证通过后你可以把计算器换成真实工具。比如查天气用 Java 原生HttpClient调外部 API解析 JSON 返回格式化字符串。注意外部 API 的 Key 不要和 TaoToken 的 Key 混在一起各管各的。工具方法里做好异常捕获网络超时、返回码非 200 这些情况都要返回人类可读的错误信息模型拿到错误信息后往往能自己决定重试还是换工具。5. 常见报错排查401、local proxy failed 与 reading choices接入过程中有几类报错出现频率很高这里逐个拆解。401 Unauthorized。这个最直接Key 不对或者没传。检查三件事apiKey字段有没有填、Key 有没有多余空格、Key 是不是从正确的控制台页面复制的。TaoToken 的 Key 在 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 管理如果你在别的地方复制了旧 Key可能已经失效。另外注意 Base URL 必须是https://taotoken.net/api写成https://taotoken.net/api/v1之类的路径可能导致鉴权失败。local proxy failed。这个报错通常出现在客户端尝试连接 MCP 服务时。原因一般是服务地址写错或者服务没起来。先确认http://localhost:8080/mcp这个地址在浏览器或 curl 里能通。如果服务起来了但客户端连不上检查客户端配置里的url字段有没有拼错端口是不是被占用。Solon 默认端口 8080如果你本机 8080 被别的程序占了改app.yml里的server.port同时更新客户端配置。reading choices 相关报错。这类错误一般出现在解析模型返回时提示读取choices字段失败。根因通常是模型返回的不是标准对话格式可能是返回了错误信息、或者返回结构和你代码里解析的字段不匹配。排查方法先把原始返回打印出来看确认choices数组存不存在。如果返回的是error字段那问题在请求侧检查模型 ID 是否正确、请求体格式是否符合预期。TaoToken 的文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里有各模型的请求格式说明对照检查。OAuth 相关报错。如果你用的是 Claude Code 这类带 OAuth 流程的工具报错可能提示 token 过期或授权失败。这类工具通常有自己的登录命令重新走一遍授权流程即可。注意 OAuth 和 API Key 是两套体系不要混用。Claude Code 的接入方式在 https://taotoken.net/claudecode?utm_sourcetaotoken_aicg_blog_endutm_contentclaudecodeutm_campaignrewrite 有说明按步骤配置 Base URL 和 Key。工具调用返回空或超时。检查工具方法里有没有阻塞操作。比如调外部 API 没设超时网络慢的时候会一直挂着。给HttpClient设个连接超时和读取超时比如 5 秒和 10 秒。另外工具方法的返回类型建议用String返回结构化 JSON 字符串模型解析起来更稳。如果返回的是复杂对象确保序列化没问题。排查顺序建议从外到内先确认 MCP 服务本身能通过 curl 调用再确认模型通道能通用模型对话页面发一句简单的话最后确认两者串起来时工具描述和参数匹配。大部分问题出在配置文件的字段拼写和地址格式上仔细核对三件套——Base URL、Key、Model ID。6. 把工具服务接到长期编码与 Agent 工作流工具服务跑通之后下一步是让它进入你的日常工作流。如果你只是偶尔验证一下用模型对话页面就够了。但如果你想让 Agent 在编码、调试、查文档这些场景里持续调用你的工具就需要一个稳定的通道和足够的调用额度。TaoToken 的 Coding Plan 就是为这种长期编码和 Agent 场景准备的地址在 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 。接入方式和你前面配的三件套一致Base URL 用https://taotoken.net/apiKey 用你在控制台创建的 KeyModel ID 按需选择。区别在于 Coding Plan 更适合高频、长时间的 Agent 调用不用每次担心额度问题。对于 MCP 工具服务这种「模型频繁决策、工具频繁执行」的场景稳定的通道比什么都重要。你可以把 Solon AI 的 MCP 服务打包成 jar用java -jar在后台跑然后让 Agent 客户端指向这个本地服务。工具可以逐步扩展查数据库、读本地文件、调内部 API、发通知。每加一个工具就在类上加Component方法上加McpTool重启服务Agent 就能发现新工具。Solon 的扫描机制让这个过程很轻不需要改配置文件。有个实用技巧给工具方法加日志记录每次调用的参数和返回。这样当模型选错工具或者填错参数时你能从日志里看到它到底传了什么反过来优化McpTool的描述。工具描述不是写一次就完事的根据实际调用情况迭代几轮命中率会明显提升。最后一步验证在 Agent 客户端里发一个需要多步工具调用的任务比如「查一下北京天气然后算一下温度换算成华氏度是多少」。如果模型能先调天气工具拿到摄氏温度再调计算器工具做换算最后组织成回答说明整条链路——Solon AI 工具服务、TaoToken 模型通道、Agent 决策——全部打通了。到这一步你的 AI Agent 就不再只是聊天而是真正能动手做事了。
返回列表