1. 为什么 SpringBoot 项目要接 MCP:从 CRUD 到「对话即服务」的落地场景
如果你手上有一个跑了很久的 SpringBoot 后端,接口一大堆,Swagger 文档几十页,业务方还是天天在群里问「这个查询怎么调」。这时候 MCP(Model Context Protocol)就是一个很自然的切入点:它把后端已有的能力包装成 AI 客户端能识别的「工具」,用户用自然语言说一句「帮我查一下张三写的书」,模型自己决定调哪个方法、传什么参数,再把结果整理成人话返回。
MCP 是什么?一句话,它是给大模型用的「工具插座协议」。传统做法是每个 AI 应用自己写 function calling 的 JSON Schema,模型换一家、客户端换一个就得重写一遍。MCP 把这层抽象出来:服务端按协议暴露工具,客户端按协议发现和调用,双方解耦。对 Java 后端来说,最大的好处是你不用改业务逻辑,只要在原有 Service 上加注解、注册成工具,就能被 Claude Desktop、Cline、Cursor 这类支持 MCP 的客户端直接调用。
适合谁?三类人最值得动手:一是手里有存量 SpringBoot 系统、想低成本加 AI 入口的后端;二是做企业内部工具平台、想让非技术同事用自然语言查数据的团队;三是想搞明白 MCP 到底怎么跑通、不想只看概念文章的开发者。这篇就按「最小闭环」来写:一个图书查询服务,从加依赖、写配置、暴露工具,到客户端连上、发一次请求、看到数据库真实返回,全程可复制。
需要提前说清楚的一点:MCP 服务端本身不负责「调用大模型」,它只负责把工具暴露出去。真正做推理、决定调哪个工具的是客户端背后的大模型。所以你会看到两个角色——MCP Server(你的 SpringBoot 应用)和 MCP Client(AI 客户端或你自己写的测试端)。理解这个分工,后面配置就不会绕晕。
我试过把公司一个内部订单查询服务按这个思路改造,原本要写一份对接文档给 AI 团队,改完之后对方直接在客户端里配个地址就能用,省掉的沟通成本比写代码本身还多。下面进入实操。
2. TaoToken 前置准备:拿到 Base URL、API Key 和可用 Model ID
在动手改 SpringBoot 之前,先把「模型侧」的凭证准备好。因为 MCP 工具调用最终要由大模型来驱动,你需要一个能访问模型的入口。这里用 TaoToken 作为统一接入层,它提供 OpenAI 兼容的接口,Base URL 固定是https://taotoken.net/api,你只需要拿一个 API Key,再选一个模型 ID 就能跑。
第一步,打开 https://taotoken.net/api ,注册并登录后进入控制台。控制台里能看到「API Keys」菜单,点进去创建一个新的 Key。建议按用途命名,比如springboot-mcp-demo,方便以后区分和吊销。创建后 Key 只显示一次,复制下来存到安全的地方,别直接提交到 Git。
第二步,确认你要用的 Model ID。在「模型对话」页面可以看到当前可用的模型列表,选一个支持工具调用(function calling / tool use)的模型,这点很关键——不是所有模型都能稳定地按 MCP 协议去调工具。选好后把模型名记下来,比如常见的claude-sonnet-4-5这类标识,具体以控制台实际展示为准。
第三步,如果你打算用 Claude Code 或 Cline 这类客户端来连你的 MCP Server,还需要在客户端侧配置接入信息。以 Claude Code 为例,它的配置文件里需要填三件套:Base URL、API Key、Model ID。Base URL 填https://taotoken.net/api,Key 填刚才创建的,Model ID 填你选的那个。这三样缺一不可,很多人连不上就是漏了 Model ID 或者 Base URL 多写了斜杠。
注意:API Key 属于敏感凭证,不要写死在
application.yml里提交到仓库。本地开发可以用环境变量,比如TAOTOKEN_API_KEY,配置里用${TAOTOKEN_API_KEY}引用。生产环境更要用密钥管理服务。
如果你只是想先验证 MCP Server 能不能被调用,不一定非要接 Claude Desktop,可以直接用 TaoToken 的「模型对话」页面配合一个支持 MCP 的客户端做联调,或者写个简单的 HTTP 测试端。前置准备到这里就够了:一个 Key、一个 Base URL、一个 Model ID。接下来进代码。
3. 可复制配置:pom.xml 依赖、application.yml 与 MCP Server 注册片段
这一节是全文的核心,所有片段都可以直接抄。先明确目标:把一个已有的BookService暴露成 MCP 工具,让客户端能通过 SSE 连上来调用。
3.1 pom.xml 依赖与仓库
Spring AI 的 MCP 相关依赖目前还在里程碑/快照阶段,中央仓库不一定有,所以要额外加仓库地址。下面这段直接贴进pom.xml:
<dependencies> <!-- Spring AI 核心 --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-core</artifactId> </dependency> <!-- MCP 服务端,WebMVC 版本,走 SSE --> <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId> </dependency> </dependencies> <repositories> <repository> <id>spring-milestones</id> <name>Spring Milestones</name> <url>https://repo.spring.io/milestone</url> <snapshots><enabled>false</enabled></snapshots> </repository> <repository> <id>spring-snapshots</id> <name>Spring Snapshots</name> <url>https://repo.spring.io/snapshot</url> <releases><enabled>false</enabled></releases> </repository> </repositories>注意这里只引了服务端 starter,没有引客户端。因为我们的 SpringBoot 应用扮演的是 MCP Server 角色,客户端是外部的 AI 工具。如果你还想在应用内部自己调模型,那才需要额外引模型 starter。
3.2 application.yml 配置
server: port: 8080 spring: ai: mcp: server: enabled: true name: book-management-server version: 1.0.0 type: SYNC sse-message-endpoint: /mcp/messagetype: SYNC表示同步调用模式,适合大多数 CRUD 场景。sse-message-endpoint是客户端发消息的路径,SSE 的连接端点通常是/sse,两者配合使用。启动后客户端连http://localhost:8080/sse就能发现工具。
3.3 用 @Tool 注解暴露方法
在原有 Service 实现类的方法上加注解,不用改方法体:
@Service @RequiredArgsConstructor public class BookServiceImpl implements BookService { @Resource private BookRepository bookRepository; @Override @Tool(name = "findBooksByAuthor", description = "根据作者精确查询图书") public List<Book> findBooksByAuthor( @ToolParam(description = "作者姓名") String author) { return bookRepository.findByAuthor(author); } @Override @Tool(name = "findBooksByCategory", description = "根据图书分类精确查询图书") public List<Book> findBooksByCategory( @ToolParam(description = "图书分类") String category) { return bookRepository.findByCategory(category); } }description写得好不好,直接决定模型能不能选对工具。别写「查询图书」这种模糊描述,要写清楚「根据作者精确查询」还是「根据书名模糊查询」。
3.4 注册 ToolCallbackProvider
光有注解还不够,要把这些工具注册到 MCP Server 上:
@Configuration public class McpServerConfig { @Bean public ToolCallbackProvider bookToolCallbackProvider(BookService bookService) { return MethodToolCallbackProvider.builder() .toolObjects(bookService) .build(); } }到这里,MCP Server 侧的配置就齐了。启动应用,控制台会打印 MCP Server 初始化的日志,看到book-management-server和注册的工具列表就说明成功。
4. 验证请求:客户端连接参数与一次工具调用的完整返回
配置写完不验证等于没写。这一节演示怎么连、怎么发请求、怎么确认工具真的被调用了。
4.1 客户端连接参数
以支持 MCP 的客户端为例,连接一个 SSE 类型的 MCP Server,需要填:
| 参数 | 值 | 说明 |
|---|---|---|
| 传输类型 | SSE | 对应服务端的 webmvc starter |
| URL | http://localhost:8080/sse | 服务端 SSE 端点 |
| 消息端点 | /mcp/message | 与 yml 中一致 |
| 名称 | book-management-server | 自定义,便于识别 |
如果你用的是 Claude Code,它的 MCP 配置通常写在settings.json或项目级配置里,结构类似:
{ "mcpServers": { "book-management-server": { "url": "http://localhost:8080/sse" } } }同时 Claude Code 自身访问模型还需要 Base URL、API Key、Model ID 三件套,Base URL 填https://taotoken.net/api,Key 用你在控制台创建的,Model ID 用你选的支持工具调用的模型。这三样和 MCP Server 的配置是两回事,别混在一起。
4.2 发一次真实请求
服务端启动后,先确认数据库里有测试数据。写一个CommandLineRunner在启动时插入几本书:
@Component @RequiredArgsConstructor public class DataInitializer implements CommandLineRunner { @Resource private BookRepository bookRepository; @Override public void run(String... args) { bookRepository.saveAll(Arrays.asList( new Book(null, "Spring实战(第6版)", "编程", "Craig Walls", LocalDate.of(2022, 1, 15), "9787115582247"), new Book(null, "深入理解Java虚拟机", "编程", "周志明", LocalDate.of(2019, 12, 1), "9787111641247"), new Book(null, "云原生架构", "架构设计", "张三", LocalDate.of(2023, 3, 15), "9781234567890") )); } }然后在客户端里输入:「帮我查一下作者是张三的书」。正常流程是:客户端把这句话和工具列表一起发给模型,模型判断应该调findBooksByAuthor,参数author=张三,客户端通过 MCP 协议把调用转发给你的 SpringBoot 服务,服务查库返回,客户端再把结果交给模型整理成自然语言。
预期返回类似:
根据查询,作者「张三」名下有 1 本图书: - 《云原生架构》,架构设计类,2023-03-15 出版,ISBN 9781234567890如果你在服务端日志里看到findBooksByAuthor被调用、SQL 执行了,就说明整条链路通了。这一步是整个最小闭环的关键验证点,别跳过。
5. 本篇常见错排查:401、local proxy failed、reading choices、OAuth 报错对照
实操里最容易卡住的不是代码,是各种报错。下面按真实遇到的顺序列。
401 Unauthorized。两种可能:一是 TaoToken 的 API Key 没填对或过期,去控制台重新生成;二是 Key 填了但 Base URL 写错,比如写成https://taotoken.net/api/多了斜杠,或者漏了/api。检查客户端配置里的 Base URL 和 Key 是否匹配。
local proxy failed / connection refused。这类报错通常是客户端连不上 MCP Server。先确认 SpringBoot 应用真的起来了,curl http://localhost:8080/sse能看到 SSE 流;再确认客户端填的 URL 和端口对得上;如果服务端和客户端不在同一台机器,localhost要换成实际 IP,并检查防火墙。
reading choices 相关报错。这多半是模型返回结构不符合预期,常见于用了不支持工具调用的模型。换一个明确支持 function calling / tool use 的 Model ID 再试。另外检查@Tool的description是否为空或过于模糊,模型选不出工具时也可能返回异常结构。
OAuth / 认证失败。如果你在客户端里配了 OAuth 流程但服务端没实现对应端点,就会报这个。MCP Server 本身不强制 OAuth,本地开发直接用 SSE + 无认证即可。生产环境要加认证的话,建议在 Spring Security 层做,而不是指望 MCP 协议自带。
工具列表为空。客户端连上了但看不到工具,检查McpServerConfig里的ToolCallbackProviderBean 是否被扫描到,@Tool注解的类是否是 Spring Bean。常见坑是把工具方法写在没被@Service或@Component标注的类里。
Codex auth.json 相关。如果你用 Codex 类客户端,认证信息在auth.json里,格式错了会直接启动失败。确认里面的 Base URL、Key、Model ID 三件套齐全,JSON 语法正确,别有多余逗号。
排查顺序建议:先看服务端日志有没有收到请求,再看客户端日志有没有发出请求,最后看模型侧返回。三段日志一对,问题基本定位。
6. 把 MCP 接进长期工作流:Coding Plan 与后续演进
跑通最小闭环之后,下一步就是把它用起来。如果你只是偶尔查一下数据,手动启动服务、手动连客户端就够了。但如果你想让 AI 长期帮你处理编码任务、自动调内部工具,那就需要一个稳定的接入方案。
TaoToken 的 Coding Plan 适合这种长期编码和 Agent 场景,它把模型调用和工具链的额度统一管理,不用每次手动换 Key。对于团队来说,把 MCP Server 部署到内网,客户端统一走 Coding Plan 接入,既省事又好审计。
具体操作上,你可以把 MCP Server 打成 jar 部署到测试环境,客户端配置里把 URL 换成测试环境地址。然后去 https://taotoken.net/api 的「接入文档」页面确认最新的连接参数格式,因为协议和客户端配置偶尔会更新,以文档为准最稳。想先验证模型能力,可以去「模型对话」页面直接试;要管理 Key 就去「API Keys」;长期编码任务则看「Coding Plan」。
最后给一个实用建议:MCP 工具的description要当成产品文案来写。模型选工具全靠它,写得清楚,调用准确率能差出一大截。我踩过的坑就是一开始描述太简略,模型老是调错方法,把描述补详细之后基本一次就对。这个细节比任何配置技巧都值钱。