首页 / 资讯中心 / 文章详情

基于SpringAI搭建查询IP归属地的MCP Server(SSE模式):TaoToken统一Key接入实践

基于SpringAI搭建查询IP归属地的MCP Server(SSE模式):TaoToken统一Key接入实践 ★ FEATURED ARTICLE
1. 从一次“查 IP 归属地”的重复劳动说起你可能遇到过这种场景排查线上日志看到一堆来源 IP想快速知道它们分别属于哪个省市、哪家运营商。手动打开网页一个个查查十几个就烦了。更麻烦的是团队里每个人都在用不同的 AI 工具有人用 Cherry Studio有人用 Cline有人用 Claude Code如果能把“查 IP 归属地”做成一个标准工具让这些客户端都能直接调用那才叫省事。这就是 MCP Server 的价值。MCPModel Context Protocol是让 AI 客户端发现并调用外部工具的一套协议而 SSE 模式则让服务端以 HTTP 长连接的方式把工具能力暴露出去客户端只要填一个 URL 就能接入。本文要做的就是用 SpringAI SpringBoot JDK 17 搭一个 SSE 模式的 MCP Server对外提供“根据 IP 查归属地”的工具并且把服务端调用外部 API 的鉴权通道统一收敛到 TaoToken 的 Key 上这样你只需要维护一份 Key就能同时管住模型调用和工具调用。适合谁看有 Java 基础、想快速跑通一个 MCP Server 的后端同学正在用 Cherry Studio / Cline / Claude Code 等客户端、想自己扩展工具能力的 AI 重度用户以及想把内部小工具标准化暴露给 AI 的团队开发者。整条链路我会给到可复制的application.yml、工具注册代码、SSE 连接验证步骤和 curl 调用示例目标是一次跑通。先说清楚一个概念避免后面混淆。MCP Server 本身不负责“理解自然语言”它只负责“暴露工具”。真正把用户那句“122.224.33.10 属于哪里”翻译成工具调用的是 MCP Client 背后的大模型。所以一个完整的链路是用户在客户端提问 → 客户端把可用工具列表发给模型 → 模型决定调用获取ip归属地工具 → 客户端通过 SSE 把调用请求发到你的 Server → Server 执行查询并返回结果 → 模型组织成自然语言回复。理解这条链路后面排查问题会轻松很多。2. TaoToken 统一 Key 接入把外部 API 通道收敛到一处在动手写代码之前先把“鉴权通道”这件事想明白。很多教程里工具类直接硬编码某个第三方 API 的地址或者把 Key 写在代码里这在个人 demo 阶段没问题但一旦工具有多个、要换供应商、要做额度统计就会变成一团乱麻。我的做法是所有对外请求统一走 TaoToken 的 API 通道用同一个 Key 管理。TaoToken 在这里扮演的角色是“统一入口”。你可以在它的控制台里创建 API Key然后无论是模型对话、还是工具内部要调用的外部能力都通过这个 Key 走同一个 Base URL。这样做的好处很直接Key 只有一份泄露了只需在一个地方轮换额度、调用记录集中可见换供应商时改配置而不是改代码。具体到操作层面你需要先拿到两样东西Base URL 和 API Key。Base URL 是https://taotoken.net/api注意这个地址不带任何查询参数是纯粹的 API 根路径。API Key 则要去控制台创建入口在https://taotoken.net/console/api-keys?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite进去之后点“创建 Key”复制出来保存好它只会完整显示一次。这里有个容易踩的坑很多人把官网首页地址和 API 地址搞混。官网是https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewrite用来注册、看文档、进控制台而代码里配置的 Base URL 必须是https://taotoken.net/api两者不能互换。我第一次配的时候就填了首页地址结果请求一直 404排查了半天才发现是路径问题。关于模型 ID如果你后续想让 MCP Server 内部也调用模型做二次处理比如把归属地结果翻译成更友好的描述可以在配置里指定 Model ID。常见的做法是把它和 Base URL、Key 一起放进application.yml三件套齐了才能正常发起请求。下面这段就是标准的配置形态你可以直接抄taotoken: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} model-id: your-model-id注意api-key我用了环境变量占位这是为了避免把 Key 提交到 Git。本地调试时可以在 IDEA 的 Run Configuration 里加环境变量或者用.env文件配合启动参数。生产环境则应该走配置中心或密钥管理服务不要明文写在 yml 里。还有一点值得强调TaoToken 的 Key 是“统一 Key”意味着你不需要为每个工具单独申请一套凭证。IP 归属地查询这个工具内部如果要调外部接口也走同一个通道。这样你的application.yml里只有一处鉴权配置维护成本最低。如果你团队里有人用 Claude Code 做编码有人用 Cline 做 Agent他们各自的客户端配置里填的也是同一个 Base URL 和 Key只是 Model ID 可能不同。这种“一处配置、多处复用”的模式是我实测下来最省心的。3. 可复制配置application.yml 与 MCP 工具注册代码这一节是全文的核心我会把项目结构、依赖、配置、工具类、服务类、配置类全部给全你照着贴就能跑。环境基线是 JDK 17、SpringBoot 3.5.0、SpringAI 1.0.0。先看项目依赖。用 Spring Initializr 建项目时勾选 “Model Context Protocol Server”生成的项目默认只支持 stdio 模式。要支持 SSE必须额外引入 WebMVC 的 starterdependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server-webmvc/artifactId /dependency这个依赖很关键少了它你的/sse端点根本不会注册启动后访问会直接 404。我见过不少人卡在这一步以为是配置写错了其实是依赖没加。接下来是application.yml这是整篇文章最该复制的一段server: port: 7080 spring: ai: mcp: server: name: ip-location-mcp-server version: 1.0.0 sse-endpoint: /sse taotoken: base-url: https://taotoken.net/api api-key: ${TAOTOKEN_API_KEY} model-id: your-model-id逐行解释一下。server.port设成 7080你可以改成任何没被占用的端口。spring.ai.mcp.server.name和version是服务标识客户端连接后能看到。sse-endpoint定义了 SSE 的访问路径最终地址就是http://localhost:7080/sse。下面的taotoken段是我们自定义的用来存放统一 Key 的三件套。然后是工具类负责真正去查 IP 归属地。这里我用一个 HTTP 工具发 GET 请求把返回的 JSON 解析成 DTOSlf4j public class IpSearchUtils { public static String getLocation(String ip) { String url https://opendata.baidu.com/api.php?query ip coresource_id6006oeutf8; try { String jsonStr HttpUtil.get(url); IpInfoDto dto JSONUtil.toBean(jsonStr, IpInfoDto.class); if (dto ! null dto.getData() ! null dto.getData().length 0) { return dto.getData()[0].getLocation(); } return null; } catch (Exception e) { log.warn(获取ip位置信息失败, e); return null; } } }对应的IpInfoDto你可以根据实际返回的 JSON 结构生成字段加好注释即可。这里不展开因为不同数据源的字段名不一样你按自己的响应体来。接着是 MCP 服务类用注解把方法声明成工具Service public class IpSearchService { Tool(name 获取ip归属地, description 根据ip获取归属地) public String getLocationByIp( ToolParam(description ip地址, 使用ipv4的格式) String ip) { if (Objects.isNull(ip)) { return 错误ip地址不能为空; } String location IpSearchUtils.getLocation(ip); if (Objects.isNull(location)) { return 错误未查找到ip的归属地; } return ip归属地 location; } }Tool的name和description会直接暴露给模型所以描述要写清楚模型才知道什么时候该调它。ToolParam是参数说明同样会传给模型帮助它正确填参。最后是配置类把服务里的工具注册出去Configuration public class McpConfig { Bean public ToolCallbackProvider toolCallbackProvider(IpSearchService service) { return MethodToolCallbackProvider.builder() .toolObjects(service) .build(); } }没有这个 Bean你的Tool方法不会被 MCP 框架扫描到客户端连接后工具列表是空的。这是第二个高频踩坑点。如果你还想让工具内部调用模型比如把归属地结果润色一下可以在服务类里注入ChatClient用taotoken.base-url和taotoken.api-key构造。但注意MCP Server 的核心职责是暴露工具模型调用是可选增强不要本末倒置。4. 验证请求SSE 连接与 curl 调用示例代码写完启动应用。看到 SpringBoot 正常起来、端口 7080 监听成功就可以验证了。第一步浏览器直接访问http://localhost:7080/sse。如果配置正确你会看到连接保持打开页面持续加载控制台里能看到 SSE 的事件流。这说明 SSE 端点已经工作。如果返回 404回去检查spring-ai-starter-mcp-server-webmvc依赖和sse-endpoint配置。第二步用 curl 验证工具调用。MCP over SSE 的调用分两步先建立 SSE 连接拿到一个 session再往消息端点 POST 请求。实际调试时更简单的方式是直接用客户端。但为了让你理解底层我给一个 curl 示例curl -N http://localhost:7080/sse-N表示禁用缓冲这样你能实时看到服务端推送的事件。你会看到类似event: endpoint和data: /mcp/message?sessionIdxxx的输出这个sessionId就是后续发消息要用的。拿到 sessionId 后发一个工具调用请求curl -X POST http://localhost:7080/mcp/message?sessionId你的sessionId \ -H Content-Type: application/json \ -d { jsonrpc: 2.0, id: 1, method: tools/call, params: { name: 获取ip归属地, arguments: { ip: 122.224.33.10 } } }如果一切正常SSE 连接上会推回结果内容里包含ip归属地浙江省杭州市 电信这样的文本。这一步跑通说明你的 MCP Server 已经能被程序调用了。第三步用 Cherry Studio 做端到端验证。打开 Cherry Studio进设置 → MCP 服务器 → 添加服务器 → 快速创建。名称随便填类型选sseURL 填http://localhost:7080/sse。保存后点开工具选项卡应该能看到获取ip归属地这个工具。然后新建对话在工具栏里选中这个 MCP 服务器输入“122.224.33.10 属于哪里”模型会自动调用工具并返回归属地。如果你用的是 Cline 或 Claude Code配置方式类似都是填 SSE URL。区别在于 Claude Code 走的是settings.json配置Cline 走的是 MCP 配置面板。无论哪个客户端Base URL、Key、Model ID 这三件套的填写逻辑是一致的Base URL 填https://taotoken.net/apiKey 填你创建的那串Model ID 按需选。验证成功的标志有三个SSE 端点能连上、curl 能拿到工具返回、客户端对话能触发工具调用。三个都过链路就通了。5. 本篇常见错排查401、local proxy failed 与工具列表为空这一节我把实际踩过的坑列出来对照报错找原因能省你不少时间。报错一401 Unauthorized。这个最常见原因通常是 Key 没配对或者没传。检查application.yml里的taotoken.api-key是否读到了环境变量本地调试时环境变量没生效就会是空值。另一个可能是 Base URL 写成了官网首页而不是https://taotoken.net/api路径不对会导致鉴权失败。还有一种情况是 Key 复制时带了空格肉眼看不出来建议重新复制一次。报错二local proxy failed 或连接被拒绝。这个报错通常出现在客户端侧说明客户端连不上你的 SSE 端点。先确认服务真的起来了netstat -ano | findstr 7080看端口有没有监听。如果端口正常检查防火墙是否拦了本地回环。还有一种可能是你填的 URL 少了/sse后缀或者用了https但服务是http。SSE 是长连接中间如果有反向代理要确保代理不缓冲、不超时。报错三reading choices 相关错误。这个一般出现在工具内部调用模型时返回体结构不符合预期。检查你的 Model ID 是否填对以及请求体格式是否符合 OpenAI 兼容规范。如果用的是 TaoToken 通道Base URL 和 Key 正确的前提下Model ID 写错会直接报模型不存在。报错四客户端工具列表为空。连接成功但看不到工具八成是McpConfig里的ToolCallbackProviderBean 没生效。检查配置类有没有加ConfigurationIpSearchService有没有加Service以及Tool注解有没有漏。还有一种情况是包扫描路径不对配置类不在启动类的同级或子包下。报错五OAuth 相关提示。如果你在客户端配置时看到 OAuth 字样说明客户端以为你要走 OAuth 鉴权。MCP SSE 模式下鉴权是在你的 Server 内部处理的客户端只需要填 URL。遇到这个提示检查客户端配置里有没有误开 OAuth 选项关掉即可。报错六Codex auth.json 配置问题。如果你同时用 Codex 类工具它的auth.json里需要填 Base URL 和 Key。格式不对会导致鉴权失败。正确做法是把https://taotoken.net/api填到 base_url 字段Key 填到 api_key 字段Model ID 单独指定。三件套缺一不可。排查的通用思路是先看服务端日志再看客户端日志最后看网络层。服务端日志会告诉你请求有没有进来、工具有没有被调用客户端日志会告诉你连接有没有建立、请求有没有发出。两边一对问题基本就定位了。6. 把工具接进你的日常 AI 工作流跑通之后你可以做几件事让它真正有用。第一把 IP 归属地查询和其他工具合并到一个 MCP Server 里比如加一个“查域名备案”或“查手机号归属地”统一走 TaoToken 的 Key这样客户端只需要配一个 SSE 地址就能用上全部工具。第二把服务部署到内网一台常开的机器上团队成员在各自客户端里填同一个 URL省去每人本地起服务的麻烦。第三如果你用 Coding Plan 做长期编码任务可以把 MCP Server 的地址写进项目配置让 Agent 在需要时自动调用。关于 Key 的管理我的建议是开发环境用环境变量生产环境用密钥管理永远不要把 Key 提交到代码仓库。TaoToken 控制台可以创建多个 Key你可以按项目或按人分配方便轮换和审计。如果哪天 Key 泄露了在控制台删掉重建即可所有走这个 Key 的调用会立即失效影响范围可控。最后留一个实用技巧SSE 连接是长连接如果客户端长时间不用会断开重连时 sessionId 会变。所以你的客户端配置里最好开启自动重连。另外MCP Server 本身是无状态的工具调用不依赖 session 里的上下文所以水平扩展很容易多起几个实例挂到负载均衡后面就行。整条链路跑下来你会发现最花时间的不是写代码而是配环境和排查连接问题。代码部分其实很少SpringAI 把 MCP 的协议细节都封装好了你只需要关注工具逻辑本身。把鉴权通道收敛到 TaoToken 之后后续加工具、换模型、做统计都变得简单。这套模式我已经在几个内部项目里用过稳定性没问题你可以放心照着搭。
阅读完成 · 觉得有帮助?
咨询建站