尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
Java 手写第一个 MCP Server:Spring AI MCP 半小时跑通 TaoToken 接入
1. Java 开发者为什么需要一个自己的 MCP ServerMCP Server 说白了就是给大模型开的一扇「工具窗口」模型本身只会输出文本它没法直接读你的数据库、查你的规则库、调你的内部接口。MCP 协议做的事就是把这层「模型想调工具」的意图翻译成一次真实的函数调用再把结果回填给模型。对 Java 开发者来说这件事以前要么用 Python 写个脚本凑合要么干脆放弃让模型凭记忆瞎编。Spring AI 2.0 把 MCP Server 的 starter 做进了 Spring Boot 体系意味着你可以用最熟的Service、Bean、application.yml这套东西半小时内把一个能对外提供工具的服务跑起来。这篇要解决的具体场景是你手头有一份团队内部的代码审查规则库41 条规则分并发安全、事务、安全、空指针、需求评审五关。你希望 AI 在审查代码时能实时按规则 id 拉回规则全文而不是靠它自己脑补。做法就是把这套规则库包装成一个 MCP Server对外暴露三个查询工具然后用一个客户端真调一把验证端到端链路通。适合谁看有 Spring Boot 基础、想给自己的 AI 工作流接一个自定义工具的 Java 后端或者你已经在用 Cline、Claude Code 这类客户端想给它们挂一个自己写的 MCP Server。全程不需要你懂 MCP 协议的报文细节Spring AI 把序列化、握手、工具注册都封好了你只需要写业务方法。版本这块先钉死因为 MCP 和 Spring AI 这两条线今年都变得快。Spring Boot 用 4.1.1Spring AI 用 2.0.1Java 21。有个坑要提前说Spring AI 2.0.1 已经不支持 Boot 3.x网上 2025 年那批教程大多是 Boot 3.x 配 1.0.0-M 系列的版本号依赖坐标对不上照抄容易起不来。另外传输协议的口径也变了Spring AI 2.0 里 SSE 传输已标记 deprecated官方推荐 Streamable HTTP端点是POST /mcp。我这回为了配合经典的SSEClientTransport客户端写法显式配了spring.ai.mcp.server.protocol: SSE用回老的/sse端点。新工程建议直接上 Streamable HTTP这里只是为了让客户端代码最短。2. TaoToken 前置统一 Key 与 API 通道怎么准备在写代码之前先把模型侧的通道准备好。MCP Server 本身不调模型它只负责提供工具真正调模型的是客户端那一侧。但如果你想让自己的验证脚本或者后续的 AI 应用能统一走一个 Key、一个 Base URL那 TaoToken 这层就值得先配好。它的作用是给你一个统一的 API 入口模型对话、编码 Agent、工具调用都从这一个口子走省得每个客户端各配一套 Key。第一步是拿 Key。打开https://taotoken.net/api-keys登录后创建一个 API Key复制出来存好。这个 Key 就是你后面所有请求的凭证别写进代码里提交到 Git用环境变量或者本地配置文件。第二步是确认 Base URL。TaoToken 的 API 地址是https://taotoken.net/api注意这个地址不带任何查询参数就是干干净净的根路径。你在客户端里配置的时候Base URL 填这个Key 填上一步拿到的Model ID 按你要用的模型填比如claude-sonnet-4-5或者gpt-4o这类。这三件套——Base URL、Key、Model ID——是任何 OpenAI 兼容客户端接入的标配缺一不可。第三步是验证通道通不通。最直接的办法是用 curl 打一发模型对话请求curl https://taotoken.net/api/v1/chat/completions \ -H Content-Type: application/json \ -H Authorization: Bearer $TAOTOKEN_API_KEY \ -d { model: claude-sonnet-4-5, messages: [{role: user, content: 回复一个字通}], max_tokens: 16 }如果返回里能看到choices数组和一段文本说明 Key 和通道都没问题。这一步别跳过后面 MCP 客户端调工具时如果报 401你至少能确定不是 Key 的问题。如果你用的是 Claude Code 这类编码 Agent配置方式略有不同。Claude Code 走的是 Anthropic 协议需要在 settings 里配ANTHROPIC_BASE_URL和ANTHROPIC_API_KEYBase URL 同样填https://taotoken.net/api。配完之后跑一个简单的对话测试确认 Agent 能正常响应。这一步做完你就有了一条稳定的模型通道接下来写 MCP Server 的时候心里有底。3. 可复制配置pom 依赖与 application.yml 片段建工程这块用 Spring Initializr 生成一个最简的 Boot 4.1.1 工程Java 21然后改 pom。关键依赖就两个但有个细节容易漏spring-ai-starter-mcp-server-webmvc只带spring-webmvc嵌入式 Tomcat 得靠spring-boot-starter-web提供。少了后者启动时连 Servlet 容器都找不到。parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version4.1.1/version /parent properties java.version21/java.version spring-ai.version2.0.1/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 dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency /dependencies然后是application.yml。这里每一行都有讲究尤其是 logging 那块是踩坑之后补上的server: port: 8080 spring: main: banner-mode: off web-application-type: servlet ai: mcp: server: name: review-rules-server version: 0.0.1 protocol: SSE logging: level: root: warn com.example.reviewrules: info org.springframework.boot: info org.apache.catalina.core: info io.modelcontextprotocol: info org.springframework.ai.mcp: infoname和version会在握手时作为服务端身份报给客户端。protocol: SSE是显式声明不写的话 2.0 默认走 Streamable HTTP。com.example.reviewrules: info这行必须放行原因在坑一里讲——Boot 的Started ...日志挂在主类 logger 下root 调成 warn 之后这行日志会被吞掉你会以为服务没起来。工具类本身是个普通Service规则数据用 Map 内置。每个工具是一个加了Tool注解的方法Tool(name getReviewRule, description 按规则 id 获取单条审查规则全文四段式适用条件、决策树、禁止写法、正反例, resultConverter PlainTextResultConverter.class) public String getReviewRule( ToolParam(description 规则 id如 concurrent-stock-deduct、tx-rpc-after-commit、ssrf-metadata) String ruleId) { Rule rule rules.get(ruleId); if (rule null) { return 未找到规则 [ ruleId ]。本 demo 可用 id rules.keySet().stream().collect(Collectors.joining(, )); } return 规则 rule.id() rule.gate() · rule.title() \n 来源 rule.origin() \n\n rule.body(); }Tool上三个属性值得说。name是工具对外的名字。description是给模型看的——模型看到的工具定义本质是一段 prompt 文本它靠读 description 决定调不调、传什么参数所以这句描述我写得比 JavaDoc 还认真。resultConverter先记住它出现过坑二会讲不加这个参数客户端收到的文本没法直接看。方法参数上的ToolParam同理它的 description 会进 JSON Schema模型靠它知道 ruleId 该填什么格式。光有Tool方法还不够得告诉 Spring AI 把它们注册成 MCP 工具。一个配置类搞定Configuration public class McpServerConfig { Bean public ToolCallbackProvider reviewRulesTools(ReviewRulesService reviewRulesService) { return MethodToolCallbackProvider.builder().toolObjects(reviewRulesService).build(); } }4. 验证请求Node 客户端真调一把mvn package之后java -jar启动日志里这三行最关键Tomcat initialized with port 8080 (http) Registered tools: 3 Started McpReviewRulesApplication in 5.646 secondsRegistered tools: 3三个工具注册成功。你可能要问了日志里还有一行 WARN 写着No tool methods found in the provided tool objects: []是不是有东西没扫到别怕。那是 Spring AI 2.0 新增的McpTool注解扫描器在找另一种注解我们没用它扫不到属正常我们的Tool走的是上面ToolCallbackProvider这条注册路径两码事。客户端我故意没用 Java 写用了 Node 加官方 JS SDK。Java 写的 Server 被另一门语言调通「协议」两个字才算坐实。核心代码如下import { Client } from modelcontextprotocol/sdk/client/index.js; import { SSEClientTransport } from modelcontextprotocol/sdk/client/sse.js; const transport new SSEClientTransport(new URL(http://localhost:8080/sse)); const client new Client( { name: review-rules-demo-client, version: 0.0.1 }, { capabilities: {} } ); await client.connect(transport); const { tools } await client.listTools(); console.log(tools/list 结果共, tools.length, 个工具); tools.forEach(t console.log( -, t.name, :, t.description)); const result await client.callTool({ name: getReviewRule, arguments: { ruleId: ssrf-metadata } }); console.log(result.content[0].text);跑起来真实输出原样贴在这里[client] 连接 MCP Server: http://localhost:8080/sse ... [client] SSE 连接成功 [client] tools/list 结果共 3 个工具 - getReviewRule : 按规则 id 获取单条审查规则全文四段式适用条件、决策树、禁止写法、正反例 - listReviewRules : 列出团队 AI 代码审查规则库的完整目录五关各多少条、规则总量、来源构成 - searchReviewRules : 按关键词模糊搜索审查规则返回命中规则的 id、所属关卡和摘要 [client] callTool getReviewRule({ ruleId: ssrf-metadata }) 返回 规则 ssrf-metadata安全关 · SSRF 白名单必须拦内网段与云元数据接口 来源推演立规 【适用条件】 任何由用户传入 URL、由服务端发起请求的代码头像抓取、网页摘要、 webhook 回调、图片转存。攻击面是服务端代替攻击者访问内网。 【决策树】 1. URL 是用户可控的吗 ├─ 否 → 走普通 HTTP 审查 └─ 是 → 2 2. 白名单校验覆盖了哪些目标 ├─ 只拦 127.0.0.1 → 不合格必须全量拦截 │ 10.0.0.0/8、172.16.0.0/12、192.168.0.0/16、 │ 169.254.169.254云元数据接口、[::1]、0.0.0.0 │ 以及 DNS 重绑定解析后再校验一次 └─ 域名白名单 解析后 IP 二次校验 → 合格 【禁止写法】 禁止只拦 127.0.0.1。云上 SSRF 的头号目标是 169.254.169.254 拿到临时凭证等于拿到整台机器的权限。也禁止只校验域名不校验解析结果。 [client] 连接已关闭demo 结束tools/list拿回 3 个工具callTool getReviewRule(ssrf-metadata)拿回安全关那条 SSRF 规则的完整全文。顺手又验了searchReviewRules(事务)命中事务关那条tx-rpc-after-commit摘要里写着「推演立规未真炸后拦回一次」——模糊搜索这条路径也是通的。这里补一句模型请求的循环因为很多人卡在「工具调了但模型没反应」。真实 AI 应用里完整链条是两趟模型请求第一趟用户提问加上工具清单启动时tools/list注入 system prompt模型决定调getReviewRule参数ruleIdssrf-metadata然后 Host 里的 MCP Client 发callToolServer 跑 Java 方法返回规则全文工具结果作为一条消息塞回对话上下文第二趟模型请求对话历史加工具结果模型基于规则全文生成最终回答。之所以要两趟是因为模型自己执行不了代码它只能输出「我想调这个工具、参数是什么」这段结构化文本真正动手的是 Client。这个循环有个实战推论description 写得好不好直接决定第一趟请求里模型选不选你的工具、参数填得对不对。5. 本篇常见错排查401、local proxy failed、reading choices、OAuth跑通之后把几个高频报错对照着过一遍省得你卡住时到处搜。401 Unauthorized。这个最常见出现在客户端调模型那一侧不是 MCP Server 本身。原因通常是 Key 没配、Key 过期、或者 Base URL 写错了。检查三件套Base URL 是不是https://taotoken.net/apiKey 是不是从https://taotoken.net/api-keys拿的那串Model ID 是不是客户端支持的。如果用的是 Claude Code确认ANTHROPIC_BASE_URL和ANTHROPIC_API_KEY都配了且没有多余的空格或换行。local proxy failed。这个报错通常出现在客户端尝试走本地代理但代理没起来的时候。如果你没配代理检查客户端设置里是不是残留了http_proxy或https_proxy环境变量。清掉之后重启客户端。注意这里说的是本地环境变量清理不是让你去配什么网络工具别搞混。reading choices 报错。这个一般出现在你手动 curl 或者脚本解析响应时返回的 JSON 里没有choices字段。原因可能是请求体格式不对比如messages写成了字符串而不是数组或者model字段填了一个不存在的模型名。把请求体对照文档检查一遍messages必须是[{role: user, content: ...}]这种结构。OAuth 相关报错。如果你用的是需要 OAuth 授权的客户端报错里出现invalid_grant或者token expired说明授权过期了。重新走一遍授权流程或者在客户端里重新登录。MCP Server 本身不涉及 OAuth这层是客户端和模型通道之间的事。MCP Server 侧的错误。如果客户端连不上/sse先确认服务真的起来了curl http://localhost:8080/sse应该返回 200 并且保持连接。如果返回 404检查protocol: SSE有没有配不配的话默认走 Streamable HTTP端点变成POST /mcp。如果返回 500看服务端日志多半是工具方法抛异常了。工具调了但返回空。检查Tool方法的返回值类型和resultConverter。如果返回 String 但没配PlainTextResultConverter客户端收到的是带引号的 JSON 字符串换行全变成\n。这个在坑二里详细讲了配一个十几行的转换器就好。6. 从验证到长期使用把 MCP Server 接进你的编码工作流验证通过只是第一步真正有价值的是把它接进你日常的编码工作流。如果你用的是 Cline 或者 Claude Code 这类支持 MCP 的客户端可以在配置里挂上这个 Server。以 Cline 的 MCP 配置为例在cline_mcp_settings.json里加一段{ mcpServers: { review-rules: { url: http://localhost:8080/sse, disabled: false, autoApprove: [getReviewRule, listReviewRules, searchReviewRules] } } }配好之后Cline 在审查代码时就能实时查你的规则库。autoApprove里列的工具会自动执行不用每次点确认。如果你用的是 Codex 那套配置写在auth.json同级的 MCP 配置里Base URL、Key、Model ID 三件套照旧。长期跑的话建议把 Server 做成一个常驻服务用systemd或者nohup挂后台。日志级别保持root: warn加主类info既干净又能看到关键启动信息。规则库更新的时候重新打包重启就行客户端不用动。如果你想让模型通道也统一管理TaoToken 的 Coding Plan 适合长期编码和 Agent 场景一个 Key 覆盖多个客户端。模型对话可以在https://taotoken.net/models里试接入文档在https://taotoken.net/docAPI Key 管理在https://taotoken.net/api-keys。这几个入口按需取用别一次全打开。最后说个真实经验MCP Server 的骨架就三件事——两个依赖、几个Tool方法、一个ToolCallbackProvider配置类半小时够用。真正花时间的是那些教程里没有的细节比如Started日志被吞、String 返回值被 JSON 序列化、Git Bash 后台化 kill 错进程。这些坑我都蹚过了你照着这篇走应该能省下那半天。
RELATED

相关推荐

AI Agent实战:从零搭建职业规划助手——SpringAI+大模型项目复盘(TaoToken统一Key接入版)

AI Agent实战:从零搭建职业规划助手——SpringAI+大模型项目复盘(TaoToken统一Key接入版)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

📅 2026/10/3 19:22:16
HarmonyOS Localization Kit + ResourceManager:多语言隐私文案的资源缺口扫描与回退拦截【鸿蒙心迹】

HarmonyOS Localization Kit + ResourceManager:多语言隐私文案的资源缺口扫描与回退拦截【鸿蒙心迹】

应用切到英文后,隐私页仍然能打开,按钮也能点,表面看没有异常。真正的问题藏在资源回退里:一条删除账号说明从 en_US 回退到了 base 中文,一条数据分析退出说明也没有目标语言定义。功能测试容易把它当作“有文字就行”…

📅 2026/10/3 19:17:16
第 13 篇:推理引擎一次猜几个字——草稿 + 验证(零门槛入门系列)

第 13 篇:推理引擎一次猜几个字——草稿 + 验证(零门槛入门系列)

上一篇:第 12 篇《重启不丢记忆》 | 下一篇:第 14 篇《一次服务很多人》 一句话导读:一次只生成一个词太慢,那就先猜几个、再让大模型一次性核对——猜对的直接白赚,猜错的无损丢弃。本篇讲清它的直觉与算术…

📅 2026/10/3 19:17:16
MORE NEWS

更多资讯

📰

不懂代码怎么制作微信小程序?手机就能操作,成本特别低速度还快

经常有人问我:我连代码长什么样都不知道,能不能自己做个微信小程序?以前答案是不能,现在完全可以了。以前做小程序确实得找开发,一个功能改半天,费用还不便宜。但现在零代码工具出来之后,不会编…

📰

Memoh config.toml 完整配置指南:15 个配置段一次讲透

Memoh config.toml 完整配置指南:15 个配置段一次讲透 【免费下载链接】Memoh ✨ The open-source multi-agent platform. Every agent gets its own computer, desktop, network, and long-term memory. You can bring your own key, or host your coding agent li…

📰

Super Agent Party架构揭秘:Electron+Python FastAPI混合架构的3.7万行代码之旅

Super Agent Party架构揭秘:ElectronPython FastAPI混合架构的3.7万行代码之旅 【免费下载链接】super-agent-party ⭐全能型AI伴侣!AI桌面女友 AI虚拟主播 AI即时通讯机器人 AI浏览器 AI智能家居 AI游戏 等你能想到的一切功能! 项目地…

📰

MySQL 数据库操作入门:从建库到备份,一篇讲清楚

1. 前言 最近在整理 MySQL 的学习笔记,发现数据库操作这块内容虽然基础,但知识点挺零散的。今天干脆把「库的操作」这部分系统地梳理一遍,从创建数据库、字符集设置,到修改、删除、备份恢复,一次讲明白。文章里的命令我…

📰

把Claude Code变成函数:AgentField Harness编排与6大编码Agent Provider实战

把Claude Code变成函数:AgentField Harness编排与6大编码Agent Provider实战 【免费下载链接】agentfield Build, run and scale AI agents like API and microservices 项目地址: https://gitcode.com/gh_mirrors/ag/agentfield AgentField 是一款开源的 AI…

📰

Academic Figure Generator 实时进度指南:SSE 流式推送与异步后台任务实现

Academic Figure Generator 实时进度指南:SSE 流式推送与异步后台任务实现 【免费下载链接】academic-figure-generator AI 驱动的学术论文配图生成平台。上传论文 → AI 分析内容生成 Prompt → 一键生成高质量科研配图,还有配套的skill可在主流agent中…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬