ARTICLE DETAIL

资讯详情

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

solon ai mcp简单使用:把 MCP 服务端接入 TaoToken 统一 Key 通道

solon ai mcp简单使用:把 MCP 服务端接入 TaoToken 统一 Key 通道 1. Solon AI MCP 接入统一 Key 通道从多模型调用混乱到一次配置搞定如果你正在用 SolonOpenSolon写 Java 后端又想让项目里的 AI 能力支持 MCP 工具调用大概率会遇到一个很现实的问题模型来源太杂。本地 Ollama 跑一个 qwen线上又想接 Claude 或 GPT 系列每个模型一套 Key、一套 Base URL、一套鉴权方式代码里到处散落着配置改一次环境要翻好几个文件。Solon AI 本身对 MCP 的支持是完整的solon-ai-mcp可以让你把普通 Java 方法通过ToolMapping注解发布成 Tool 服务客户端再用McpClientWrapper把多个 MCP 服务端的工具聚合起来交给ChatModel调用。问题出在ChatModel这一层它需要一个具体的模型服务地址和凭证。当你想在多个模型之间切换或者团队里多人共用一套额度时Key 的管理就成了麻烦事。TaoToken 在这里扮演的角色是一个统一的模型调用通道。你只需要拿到一个 Key把ChatModel的请求地址指向 TaoToken 的 API 端点模型 ID 按需填写剩下的路由和鉴权由通道处理。这样 Solon 项目里的 MCP 工具调用逻辑完全不用动只改模型接入这一处配置就能在 Ollama、Claude、GPT 等模型之间灵活切换。这篇文章面向的是已经有 Solon 项目、并且已经跑通过solon-ai-mcp基础示例的开发者。我会从 MCP 服务端的注册讲起给出可复制的pom.xml依赖片段、Tool 服务代码、MCP 客户端配置然后重点演示如何把ChatModel接到 TaoToken 通道最后用一次完整的工具调用请求验证链路是否通畅。整个过程你可以跟着一步步操作遇到报错也有对照排查。适合谁看写过 Solon 的Component和Mapping对 MCP 的 Tool 发布有基本概念但还没把模型调用统一管理起来的 Java 开发者。如果你还没接触过 Solon AI建议先跑通官方的最小示例再回来这篇的重点在“接入统一通道”而不是“从零学 Solon”。2. TaoToken 前置准备拿到统一 Key 和 API 地址在改 Solon 代码之前先把 TaoToken 这边的准备工作做完。这一步不复杂但顺序别搞反否则后面调试时会分不清是 Key 的问题还是代码的问题。首先访问 TaoToken 官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册并登录。登录后进入控制台找到 API Keys 管理页面创建一个新的 Key。这个 Key 就是你后面在 Solon 配置里填的凭证格式通常是一串以特定前缀开头的字符串。创建时建议给它起一个能识别用途的名字比如solon-mcp-dev方便以后在多个项目之间区分。拿到 Key 之后你需要确认两件事Base URL 和可用的 Model ID。TaoToken 的 API 端点是 https://taotoken.net/api 注意这个地址后面不加 UTM 参数直接作为ChatModel的请求前缀使用。Model ID 则取决于你想调用哪个模型控制台的模型列表里会列出当前可用的标识符比如claude-sonnet-4-20250514、gpt-4o这类。你不需要记住所有模型先选一个你打算在 Solon 项目里用的记下它的 ID 就行。这里有一个容易踩的坑TaoToken 的 API 地址和模型对话页面的地址不是同一个。模型对话页面是给你在浏览器里直接测试用的而 API 地址是给代码调用的。如果你把浏览器地址填进ChatModel.of()请求会返回 404 或者重定向错误。正确的做法是只使用https://taotoken.net/api作为基础地址具体的路径由 Solon AI 的 provider 实现去拼接。另外如果你打算在团队里共用这个 Key建议在控制台里设置好额度限制或者按项目拆分多个 Key。Solon 项目里可以通过环境变量或者配置文件来读取 Key不要硬编码在 Java 代码里。后面我会给出具体的配置方式。准备工作做完后你手里应该有三样东西一个有效的 API Key、Base URLhttps://taotoken.net/api、一个你打算使用的 Model ID。接下来进入 Solon 项目的配置环节。3. 可复制配置pom 依赖、MCP 服务端与 ChatModel 接入这一节是整篇文章的核心操作部分。我会按照“依赖 → MCP 服务端 → MCP 客户端 → ChatModel 接入 TaoToken”的顺序给出完整代码你可以直接复制到自己的项目里只需要替换 Key 和 Model ID。3.1 pom.xml 依赖配置先确认你的pom.xml里有以下依赖。这里的关键是solon-ai-mcp和它依赖的 MCP SDK 版本要对齐否则运行时会报NoSuchMethodError或者类找不到。dependencies dependency groupIdorg.noear/groupId artifactIdsolon-web/artifactId /dependency dependency groupIdorg.noear/groupId artifactIdsolon-boot-undertow/artifactId /dependency dependency groupIdorg.noear/groupId artifactIdsolon-logging-logback/artifactId /dependency dependency groupIdorg.projectlombok/groupId artifactIdlombok/artifactId scopeprovided/scope /dependency dependency groupIdcn.hutool/groupId artifactIdhutool-all/artifactId version5.8.31/version /dependency dependency groupIdorg.noear/groupId artifactIdsolon-test/artifactId scopetest/scope /dependency dependency groupIdorg.noear/groupId artifactIdsolon-ai/artifactId /dependency dependency groupIdorg.noear/groupId artifactIdsolon-ai-mcp/artifactId exclusions exclusion groupIdio.modelcontextprotocol.sdk/groupId artifactIdmcp/artifactId /exclusion /exclusions /dependency dependency groupIdorg.noear.mcp.sdk/groupId artifactIdmcp/artifactId version0.9.0-M1/version /dependency /dependencies注意solon-ai-mcp里排除了io.modelcontextprotocol.sdk:mcp换成了org.noear.mcp.sdk:mcp:0.9.0-M1。这是 Solon 对 MCP 协议的一个适配版本如果你不排除原版 SDK可能会出现协议不兼容的情况。这个细节在官方文档里没有特别强调但实际跑的时候如果遇到 SSE 连接建立后立刻断开大概率就是这里没对齐。3.2 MCP 服务端发布 Tool 服务MCP 服务端的职责是把普通的 Java 方法暴露成 AI 可以调用的工具。Solon 用ToolMapping和ToolParam两个注解来完成这件事。下面是一个查询天气的 Tool 服务示例package com.wht.mcp.server; import org.noear.solon.ai.chat.annotation.ToolMapping; import org.noear.solon.ai.chat.annotation.ToolParam; import org.noear.solon.annotation.Component; Component public class McpServerTool { ToolMapping(description 查询天气预报) public String getWeather(ToolParam(description 城市位置) String location) { System.err.println(location: location); return location 晴30度; } }这里有一个编译参数需要注意ToolParam的description在运行时需要读取参数名如果你没有开启-parameters编译参数Solon 会拿不到参数名导致工具调用时参数映射失败。解决办法是在pom.xml的maven-compiler-plugin里加上compilerArgsarg-parameters/arg/compilerArgs或者在注解里显式指定name属性。再来看第二个 Tool 服务它根据天气推荐游玩地点package com.wht.mcp; import org.noear.solon.ai.chat.annotation.ToolMapping; import org.noear.solon.ai.chat.annotation.ToolParam; import org.noear.solon.annotation.Component; Component public class McpServerTool { ToolMapping(description 查询游玩地方) public String getSpot(ToolParam(description 天气) String weather) { System.err.println(weather: weather); return weather.contains(雨) ? 图书馆或者海洋馆 : 动物园或者植物园; } }这两个服务分别部署在两个不同的 Solon 工程里端口分别是 8080 和 8081。这样做的目的是模拟多个 MCP 服务端的场景客户端需要同时连接两个服务端并聚合它们的工具列表。3.3 MCP 客户端聚合多个服务端客户端的核心是McpClientWrapper它负责连接 MCP 服务端并获取工具列表。下面是完整的客户端代码package com.wht.mcp; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.util.StrUtil; import lombok.SneakyThrows; import org.noear.solon.ai.chat.ChatModel; import org.noear.solon.ai.chat.ChatResponse; import org.noear.solon.ai.chat.message.ChatMessage; import org.noear.solon.ai.mcp.client.McpClientWrapper; import java.util.List; import java.util.Scanner; public class McpClient { SneakyThrows public static void main(String[] args) { McpClientWrapper mcpClient1 new McpClientWrapper(http://localhost:8080, /mcp/sse); McpClientWrapper mcpClient2 new McpClientWrapper(http://localhost:8081, /mcp/sse); ChatModel chatModel ChatModel.of(https://taotoken.net/api) .provider(openai) .model(claude-sonnet-4-20250514) .apiKey(System.getenv(TAOTOKEN_API_KEY)) .defaultToolsAdd(mcpClient1.toTools()) .defaultToolsAdd(mcpClient2.toTools()) .build(); System.err.println(请开始向 AI 提问); Scanner scanner new Scanner(System.in); String userInput scanner.nextLine(); while (StrUtil.isNotEmpty(userInput)) { ChatMessage system ChatMessage.ofSystem(您是一名精通问题总结的助手我的问题中可能只包含一个请求也可能包含多个问题请帮我总结并抽取出来保证不会丢失关键信息.); ChatMessage user ChatMessage.ofUser(StrUtil.format(我现在的问题是“{}” 请仔细理解并总结直接返回答案不要进行其他额外的赘述。答案的模板必须遵循下面的形式\n 问题一###问题二###问题三\n 例如我的问题是“查询凤起路地铁站附近100米范围内的管线信息同时帮我查一下西湖区面积大于100的地下停车场信息”经过解析结果使用模板输出:\n\n 查询凤起路地铁站附近100米范围内的管线信息###查询西湖区面积大于100的地下停车场信息。\n, userInput)); ChatResponse systemChatResponse chatModel.prompt( CollUtil.newArrayList(user, system)).call(); System.err.println(用户的问题 systemChatResponse.getMessage()); ListChatMessage messageList CollUtil.newArrayList(); CollUtil.newArrayList(systemChatResponse.getMessage().getContent().split(###)) .forEach(question - { try { messageList.add(ChatMessage.ofUser(question)); ChatResponse response chatModel.prompt(messageList).call(); messageList.add(response.getMessage()); } catch (Exception e) { e.printStackTrace(); } }); System.err.println(AI的回答 CollUtil.getLast(messageList).getContent()); if (q.equals(userInput)) { break; } userInput scanner.nextLine(); } System.err.println(对话结束); } }这段代码里有几个关键点需要说明。第一ChatModel.of(https://taotoken.net/api)里的地址是 TaoToken 的 API 端点不是模型对话页面的地址。第二.provider(openai)表示使用 OpenAI 兼容的协议格式TaoToken 的 API 兼容这种格式所以这里填openai即可。第三.apiKey(System.getenv(TAOTOKEN_API_KEY))从环境变量读取 Key避免硬编码。第四.defaultToolsAdd()把两个 MCP 服务端的工具都注册到同一个 ChatModel 上这样模型在回答时可以根据需要调用任意一个工具。如果你用的是配置文件而不是环境变量可以在app.yml里这样写taotoken: api-key: ${TAOTOKEN_API_KEY} base-url: https://taotoken.net/api model: claude-sonnet-4-20250514然后在 Java 代码里用Inject或者Solon.cfg().get()读取。这样切换环境时只需要改配置文件不用动代码。4. 验证请求一次完整的工具调用链路配置写完之后必须实际跑一次请求来确认链路是通的。这一节我会给出具体的验证步骤和预期结果你可以对照着检查自己的运行情况。4.1 启动 MCP 服务端先启动两个 MCP 服务端工程。如果你用的是 Solon 的Solon.start()方式确保两个工程的端口分别是 8080 和 8081并且都注册了/mcp/sse这个端点。启动成功后控制台应该能看到类似Undertow started on port 8080的日志。你可以先用浏览器或者 curl 访问一下http://localhost:8080/mcp/sse如果返回一个 SSE 事件流内容可能是event: endpoint之类的说明 MCP 服务端已经正常工作了。如果返回 404检查一下 Solon 的 MCP 插件是否已经启用通常需要在app.yml里加上solon.ai.mcp.server.enable: true。4.2 运行 MCP 客户端在 IDE 里直接运行McpClient的main方法。运行之前确保环境变量TAOTOKEN_API_KEY已经设置好了。在 Linux 或 macOS 上可以用export TAOTOKEN_API_KEY你的Key在 Windows 上可以用set TAOTOKEN_API_KEY你的Key或者在 IDE 的 Run Configuration 里配置环境变量。程序启动后控制台会输出请开始向 AI 提问。这时候输入一个测试问题比如杭州今天天气怎么样适合去哪里玩4.3 预期结果与链路分析输入问题后程序会先调用一次 ChatModel让模型把问题拆解成多个子问题。然后对每个子问题分别调用 ChatModel这时候模型会根据注册的工具列表决定是否调用 MCP 工具。如果一切正常你会看到类似这样的输出用户的问题杭州今天天气怎么样###适合去哪里玩 location:杭州 weather:杭州晴30度 AI的回答杭州今天晴30度适合去动物园或者植物园。这个过程中发生了三次模型调用和两次工具调用。第一次模型调用负责拆解问题第二次模型调用触发了getWeather工具第三次模型调用触发了getSpot工具。所有的模型请求都经过了 TaoToken 的 API 端点你可以在 TaoToken 控制台的请求日志里看到对应的调用记录。如果你在控制台日志里看到了location:杭州和weather:杭州晴30度这两行输出说明 MCP 工具确实被调用了而且参数传递是正确的。如果只看到了模型回答但没有工具调用日志说明模型没有触发工具可能是工具描述不够清晰或者模型本身不支持 function calling。4.4 验证 TaoToken 通道是否生效要确认请求确实走了 TaoToken 通道最直接的方法是查看 TaoToken 控制台的用量统计。登录控制台后在请求日志或用量页面应该能看到刚才的几次调用记录包括模型 ID、请求时间、Token 消耗量。如果这里没有记录说明请求没有到达 TaoToken需要检查ChatModel.of()里的地址是否正确。另一个验证方法是临时把apiKey改成一个错误的值重新运行程序。如果请求返回 401 错误说明鉴权环节确实经过了 TaoToken。如果返回的是连接超时或者 404说明地址配置有问题。5. 常见报错排查401、local proxy failed、reading choices、OAuth这一节整理几个实际接入过程中最容易遇到的报错以及对应的排查思路。这些报错信息你可能会在控制台或者日志里看到对照着检查能省不少时间。5.1 401 Unauthorized这是最常见的鉴权失败报错。可能的原因有三个Key 没有正确设置、Key 已经失效、请求头里的鉴权格式不对。先检查环境变量TAOTOKEN_API_KEY是否真的被程序读到了。可以在代码里加一行System.err.println(System.getenv(TAOTOKEN_API_KEY))来确认。如果输出是null说明环境变量没设置成功检查一下 IDE 的 Run Configuration 或者 shell 的 export 语句。如果 Key 读到了但还是 401去 TaoToken 控制台确认这个 Key 是否还在有效期内有没有被禁用。另外注意有些 HTTP 客户端会自动在 Key 前面加Bearer前缀有些不会。Solon AI 的apiKey()方法通常会自动处理但如果你手动构造请求头需要确认格式是Authorization: Bearer 你的Key。5.2 local proxy failed 或 connection refused这个报错通常出现在 MCP 客户端连接 MCP 服务端的时候。如果你看到local proxy failed或者Connection refused先确认两个 MCP 服务端是否已经启动端口是否和代码里写的一致。McpClientWrapper的构造函数第一个参数是基础地址第二个参数是路径。如果你写的是new McpClientWrapper(http://localhost:8080, /mcp/sse)那么实际请求的地址是http://localhost:8080/mcp/sse。检查一下服务端是否真的在这个路径上暴露了 SSE 端点。还有一种情况是防火墙或者安全组拦截了本地端口。如果你在容器里运行确认端口映射是否正确。本地开发一般不会有这个问题但如果你用了 Docker需要把 8080 和 8081 端口暴露出来。5.3 reading choices 报错reading choices这个报错通常出现在解析模型响应的时候。TaoToken 返回的响应格式是 OpenAI 兼容的包含choices数组。如果 Solon AI 在解析时找不到choices字段就会报这个错。可能的原因是 Model ID 填错了导致 TaoToken 返回了一个错误响应而不是正常的模型输出。去控制台确认你填的 Model ID 是否在可用列表里。另一个原因是 provider 设置不对如果你填的是ollama但实际请求的是 TaoToken 的 OpenAI 兼容接口响应格式会对不上。记住接入 TaoToken 时 provider 填openai。如果确认 Model ID 和 provider 都没问题还是报reading choices可以打开 debug 日志看看原始响应内容。在app.yml里加上solon.logging.level: debug然后重新运行日志里会打印出完整的 HTTP 响应体方便定位问题。5.4 OAuth 相关报错如果你看到OAuth或者token refresh failed之类的报错说明请求被路由到了一个需要 OAuth 鉴权的端点。这种情况通常是因为 Base URL 填成了模型对话页面的地址而不是 API 地址。TaoToken 的 API 地址是https://taotoken.net/api这个地址走的是 Key 鉴权不需要 OAuth。如果你填的是其他地址可能会触发 OAuth 流程。检查ChatModel.of()里的地址确保只使用 API 端点。另外如果你在代码里同时配置了apiKey和 OAuth 相关的参数可能会冲突。Solon AI 的ChatModel默认使用apiKey鉴权不需要额外配置 OAuth。把多余的配置去掉只保留apiKey即可。5.5 工具没有被调用这个问题不算报错但很常见。模型返回了回答但没有触发任何 MCP 工具。原因通常是工具描述不够清晰或者模型本身不支持 function calling。先检查ToolMapping的description是否准确描述了工具的用途。描述越具体模型越容易判断什么时候该调用。比如“查询天气预报”就比“获取信息”要好得多。然后确认你使用的 Model ID 支持 function calling。不是所有模型都支持工具调用如果你选了一个不支持 tool use 的模型它只会直接回答而不会调用工具。在 TaoToken 控制台查看模型列表时注意看每个模型的能力标注选择支持 function calling 的模型。如果工具描述和模型都没问题但工具还是没被调用可以尝试在 system message 里明确告诉模型“你可以使用工具来获取实时信息”。有时候模型需要一点提示才会主动调用工具。6. 把统一 Key 通道用起来长期编码与 Agent 场景的接入建议走到这里你已经完成了 Solon AI MCP 服务端接入 TaoToken 统一 Key 通道的完整流程。从依赖配置、Tool 服务发布、MCP 客户端聚合到 ChatModel 指向 TaoToken API 端点再到实际验证和报错排查整条链路是通的。如果你打算把这个方案用在长期编码或者 Agent 场景里有几个实践建议可以参考。第一把 Key 和 Base URL 放在配置文件或环境变量里不要硬编码。团队协作时每个人用自己的 Key或者用一个共享 Key 但设置好额度限制。第二MCP 服务端的工具描述要持续优化工具越多模型判断调用哪个工具的难度越大清晰的描述能显著提升调用准确率。第三如果你需要频繁切换模型做对比测试可以在ChatModel构建时把 Model ID 参数化通过配置读取这样不用改代码就能换模型。对于需要长期运行的 Agent 服务建议关注 TaoToken 的 Coding Plan 方案它在额度和调用方式上更适合持续性的编码辅助场景。你可以在控制台里查看具体的套餐说明根据自己的调用量选择合适的方案。接入文档和 API Keys 管理都在控制台里可以找到。如果你在配置过程中遇到了这篇文章没覆盖的报错先去文档里查一下错误码的含义大部分常见问题都有说明。模型对话页面可以用来快速测试某个 Model ID 是否可用确认没问题后再填到 Solon 代码里。
返回列表