ARTICLE DETAIL

资讯详情

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

Spring AI实战MCP:从客户端到服务端完整落地指南

Spring AI实战MCP:从客户端到服务端完整落地指南 最近 Java 圈子聊 MCP 的人越来越多尤其是 Spring AI 正式把 MCP 放进官方生态以后很多后端同学终于感觉“这事跟我有关了”。我前阵子正好用 Spring AI 完整落地了一个 MCP 客户端把自己的业务功能包成了一个 MCP Server再让大模型通过工具调用把整个流程串起来踩了不少坑也把手里的示例代码精简成了可以直接抄作业的版本。这篇就按零基础到进阶的顺序把这个链路讲透包括 MCP 和 Spring AI 的关系、依赖怎么选、客户端怎么写、自定义 Server 怎么做、以及我实际调试中遇到的各种问题。别管你是刚入门的 Java 新人还是已经在生产线上的后端开发照着做基本都能跑起来。网上的 MCP 教程大多围绕 Python 和 NodeJava 相关的零散资料确实少。但 Spring AI 对 MCP 的支持其实很成熟从 1.0 GA 版本开始MCP 客户端、MCP Server、工具自动注册这些核心能力都已经内建配置好依赖后本质就是写几个配置类和注解的事。1. 先把 MCP 和 Spring AI 这两件事讲透1.1 为什么 2025 年后所有 Java 后端都在聊 MCPMCP 的全称是 Model Context Protocol也就是模型上下文协议最早由 Anthropic 在 2024 年底开源目的很简单把 AI 模型和外部数据、工具之间做一个统一的标准接口。你可以抽象地理解成它给大模型开了一堆“插座”内置支持文件系统、数据库、搜索、网页、代码仓库等等。不同行业的人看到的东西完全不同前端看到的是 Chrome DevTools MCP运维看到的是服务器监控 MCP安全测试的人看到的是 Burp Suite MCP甚至还有 Blender 建模 MCP、Figma 设计稿 MCP。大家的核心诉求是一致的让 AI 不再只会聊天而是能真的去访问数据、操作工具、完成复杂的业务流程。那为什么 Java 开发者要特别关心因为企业核心系统绝大多数是 Java 写的。像审批流、订单中心、财务对账这类系统数据都在关系型数据库里逻辑都在 Spring Boot 服务里。如果想让 AI 助手帮用户查订单、算库存、生成报表就得让大模型安全地拿到这些能力。MCP 正好提供了统一通道而 Spring AI 又把这个协议内建成了 Java 生态的一员。你可以直接用 Java 写工具用一个 Tool 注解暴露给大模型然后用 Spring Boot 那一套熟悉的依赖注入、配置绑定、自动装配来管理工作区这种感觉跟以前写 Web 服务没有本质区别。1.2 MCP 的架构比你想的更简单MCP 采用的是一个典型的客户端服务器架构中间通过 JSON-RPC 2.0 消息通信传输方式常见的有 stdio 和 HTTP/SSE 两种Spring AI 从 1.0.6 版本开始完整支持了 WebFlux/WebMVC 下的 SSE 和 Streamable HTTP。整个链路里有三个角色MCP Host宿主程序比如 Claude Desktop、IDE或者我们自己的 Spring Boot 应用。MCP Client在 Host 内部与某个 Server 建立 1 对 1 会话的协议客户端负责发送 tools/list、tools/call 这些请求。MCP Server提供具体能力的轻量级程序里面注册了各种 tool、resource、prompt。简单类比一下MCP Server 就像餐厅的菜单工具就是菜单上的一道道菜模型是顾客客户端是服务员。顾客不需要知道后厨怎么运作只需要看菜单点菜服务员负责把菜端上来。MCP 协议规范了“菜单长什么样”“怎么点菜”“怎么上菜”剩下的业务细节都由 Server 实现。MCP 本身主要定义了三种核心能力工具模型主动调用、完成动作比如查天气、创建订单资源把数据作为上下文片段加载比如把某个 Markdown 文档内容塞给模型提示词模板可复用的 Prompt 片段比如一段生成 SQL 的标准模板。现在实际工程里大家用得最多的就是 ToolSpring AI 也是优先围绕 Tool 做了最成熟的自动注册机制。1.3 Spring AI 在 MCP 生态中的三板斧Spring AI 这块闭源到开源后对 MCP 的支持非常明确过去一年里能明显看到官方在逐步完善三个能力。第一是 MCP Client 的自动配置。你只要引入spring-ai-starter-mcp-client配置好 server 列表Spring AI 会帮你创建 MCP 会话把远端 Server 暴露的所有工具自动注册成ToolCallback再把这些工具装进ChatClient的工具上下文。写完代码你可能手都没碰一下协议工具就已经可以被模型调用了。第二是 MCP Server 搭建。通过spring-ai-starter-mcp-server配合Tool注解你可以把一个 Spring Bean 的方法直接暴露为 MCP 工具。Spring AI 会根据方法签名自动生成 JSON Schema 的输入参数定义并处理 stdio 或 WebMVC 传输。自己写一个 Server比想象中简单得多。第三是工具注册的中枢机制。Spring AI 有一个ToolCallbackProvider的抽象专门管理由 Tool 包装出来的ToolCallback。官方内置了MethodToolCallbackProvider会扫描某个类里所有标记了 Tool 的方法把它们包装成统一的回调对象。MCP Server 启动时会在启动类里用这个 Provider 把业务工具集合交给它。整体设计就是对内屏蔽协议细节对外统一暴露工具列表。2. 环境与依赖一次把版本选对2.1 JDK 和构建工具目前 Spring Boot 3.4.x 要求最低 Java 17如果你准备尝鲜 Spring Boot 3.5 或者更高版本Java 21 更稳妥。我自己用的是 JDK 17 跑生产环境本地开发用了 JDK 21两者在大多数 Spring AI 示例里都能正常编译运行。构建工具选 Maven 和 Gradle 都可以不过 Maven 生态的资料更全遇到依赖问题也好搜这里就用 Maven。环境准备清单JDK 17Maven 3.9IDEIDEA 或 Eclipse推荐 IDEAOpenAI API 的 Key或者兼容接口的 Key后面说通义千问的接入强调一个点Spring AI 的依赖是通过官方 BOM 牵引进来的所以必须在dependencyManagement里加入spring-ai-bom否则版本号对不上会出现 NoClassDefFoundError 或者 XML schema 解析失败。2.2 Spring Boot / Spring AI 版本搭配版本搭配是一个特别容易踩坑的环节。Spring AI 的版本号和 Spring Boot 不是一一对应的官方文档一般会给出兼容矩阵。在 1.0.x GA 正式发布后2.0 的里程碑版本也已经在社区活跃。对生产项目我建议至少关注两个选择场景推荐版本组合备注稳定生产首选Spring Boot 3.4.x Spring AI 1.0.x文档全资料多mcp 相关 API 最稳尝鲜新特性Spring Boot 3.5.x Spring AI 1.1.x/2.0.x注意部分类路径变化国内阿里云场景Spring Boot 3.4.x Spring AI Alibaba 1.0.xDASHSCOPE 接入体验好也支持 MCP我实际生产里用的是 Spring Boot 3.4.5 Spring AI 1.0.0运行得很稳。后来试了一下 Spring AI 2.0 的快照版变化点主要体现在模块拆分和部分 API 包名调整建议新项目可以直接考虑等它正式发布后再迁移到 2.0 也不晚。2.3 从 start.spring.io 开始创建项目去 start.spring.io选 Maven、Java 17依赖先不用勾选因为 Spring AI 需要通过 BOM 管理页面里还不一定列得全。直接生成一个空 Web 项目然后手动改pom.xml就行。pom.xml核心依赖写出来是这样的parent groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-parent/artifactId version3.4.5/version relativePath/ /parent properties java.version17/java.version spring-ai.version1.0.0/spring-ai.version /properties dependencies dependency groupIdorg.springframework.boot/groupId artifactIdspring-boot-starter-web/artifactId /dependency !-- OpenAI 模型接入也可以用 spring-ai-starter-model-ollama 之类替代 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-model-openai/artifactId /dependency !-- MCP 客户端 -- dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-client/artifactId /dependency dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-bom/artifactId version${spring-ai.version}/version typepom/type scopeimport/scope /dependency /dependencies如果你的模型提供方不是 OpenAI 官方比如通义千问、Kimi、DeepSeek 这类兼容 OpenAI 接口的服务依然可以用spring-ai-starter-model-openai只需要在配置里替换 base-url 和 api-key。2.4 必须要引入的依赖清单除了上面的核心依赖有几个依赖是排查时最容易漏的spring-ai-starter-mcp-client负责 MCP 客户端自动配置不引入这个就无法自动注册工具。spring-ai-starter-mcp-server负责服务端自动配置写自定义 Server 时必须加。如果使用 stdio 方式启动 npx 子进程需要额外的进程管理依赖其实是 Spring AI 内部已经封装好了不需要额外引进程库。如果使用 MCP Server 的 WebMVC 端点则还需要spring-ai-mcp-server-webmvc但一般 starter 里会传递依赖。如果使用 SSE 传输Spring Boot 的spring-boot-starter-webflux是需要的。再说一个很多人忽略的点。Spring AI 1.0.x 正式版要求 Spring Boot 版本不低于 3.4如果项目还是 Spring Boot 3.3.x容易出现McpClient找不到类等问题最先应该查 Boot 版本和 Spring AI 版本是不是都对上了。3. 第一个 MCP 客户端把现成的 MCP Server 拉进你的对话3.1 使用官方 Everything Server 当靶场直接手写逻辑之前最好先找一个现成的 MCP Server 来验证链路是否打通。官方提供了modelcontextprotocol/server-everything里面自带 echo、add、longContext 这类工具非常适合当“靶场”测试。它默认运行在 npx 环境里Spring AI 客户端配置好 stdio 传输就可以直接通过子进程拉起一个 Node 进程来当 MCP Server。这里有个比较关键的点如果你本机没有 Node 或者 npx 版本太低整个 stdio 传输就会一直失败表现为 MCP 客户端连接异常或者日志里没有任何工具被注册。先用npx --version确认环境没问题再继续。3.2 客户端的核心配置在application.yml里写客户端配置server: port: 8080 spring: application: name: mcp-client-demo ai: openai: base-url: https://api.openai.com api-key: ${OPENAI_API_KEY} chat: options: model: gpt-4o-mini mcp: client: name: mcp-client-demo version: 1.0.0 type: SYNC request-timeout: 30s servers: - connection: stdio command: npx args: - -y - modelcontextprotocol/server-everythingtype: SYNC表示使用同步客户端。对大多数场景来说同步更直观调试也简单异步客户端占用资源更少但链路里多了一层 CompletableFuture定位问题时没那么快。request-timeout别设太短50 秒以上比较稳有些工具执行本身就需要几秒时间短了容易触发超时误报。如果要连接远程 MCP Server配置大概是把connection改成http或websocket类型配好 URL 和认证字段。生产环境千万不要在 YAML 里写死 Token用环境变量 ${MCP_SERVER_TOKEN} 的方式注入否则代码一旦上传仓库Key 就等于泄露了。3.3 先写一个能复制的 Demo直接写一个 CommandLineRunner一启动就让大模型问一个需要工具才能回答的问题。比如问 everything server 里的 echo 工具“请使用 echo 工具回复 hello-world并返回工具的执行结果。”package com.example.mcpdemo; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ai.chat.client.ChatClient; import org.springframework.boot.CommandLineRunner; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; SpringBootApplication public class McpClientApplication { private static final Logger log LoggerFactory.getLogger(McpClientApplication.class); public static void main(String[] args) { SpringApplication.run(McpClientApplication.class, args); } Bean public CommandLineRunner demo(ChatClient.Builder chatClientBuilder) { return args - { ChatClient chatClient chatClientBuilder.build(); String response chatClient.prompt() .user(帮我调用 echo 工具内容为 hello from spring ai然后原样告诉我结果) .call() .content(); log.info(最终的模型回复{}, response); }; } }这里需要注意ChatClient.Builder会自动收集容器里所有的ToolCallback而 MCP 客户端自动配置会把远端工具的ToolCallback注册进容器。所以整个链路其实和普通函数调用一致模型觉得需要某个工具时就会发起调用。3.4 跑起来之后发生了什么把项目启动后日志里会看到 MCP 客户端连接、工具注册的日志然后模型开始做工具调用。整个流程大致是这样的用户发送“调用 echo 工具”的 Prompt。Spring AI 把工具定义和用户的 Prompt 一起发给模型。模型在响应里带上工具调用指令表示要调用echo。Spring AI 拦截这个指令调用 MCP Client 向 MCP Server 发送tools/call请求。MCP Server 执行echo返回结果。Spring AI 把结果回传给模型。模型根据结果组织最终自然语言回复。整个过程可能来回两轮日志中能看到工具调用相关信息包括返回的 content 块。第一次跑通这个流程以后你就已经完整经历了 MCP 的核心链路后面写自己的 Server 基本就是把这套流程再自己掌控一遍。4. 动手实现自己的 MCP Server4.1 用 Tool 注解定义业务工具自己实现 MCP Server 的核心是定义工具Spring AI 的机制非常简单在 Spring Bean 方法上标记Tool注解指定描述信息方法参数就是工具的输入字段。比如写一个天气查询工具package com.example.mcpserver.service; import org.springframework.ai.tool.annotation.Tool; import org.springframework.stereotype.Service; Service public class WeatherToolService { Tool(description 根据城市名称查询实时的天气情况返回天气描述、温度和湿度) public String getWeather(String city) { // 这里实际应该调第三方天气API为了演示返回模拟数据 return String.format(城市%s天气多云转晴温度22℃湿度45%%, city); } }就这么简单。一个超普通的 Spring Service方法上加了Tool它就变成了一个 MCP 工具。Spring AI 会根据方法名生成工具名getWeather根据参数名生成 JSON Schema 的必填字段。这里有一个常见陷阱如果方法参数没有加ToolParam(required false)默认情况下参数是必填的模型一定会传这个参数才发起工具调用。还可以为参数加上描述信息让模型更清楚该传什么Tool(description 根据城市查询天气) public String getWeather(ToolParam(description 城市名称比如 北京、上海) String city) { // ... }4.2 MCP Server 的自动配置要构建 MCP Server需要一个独立的 Spring Boot 工程或者把 server 代码放在同一个工程的另一个模块里。首先必须在依赖中加入dependency groupIdorg.springframework.ai/groupId artifactIdspring-ai-starter-mcp-server/artifactId /dependency然后配置传输方式。如果只作为本地 stdio Server 运行配置文件这样写spring: main: web-application-type: none ai: mcp: server: name: weather-mcp-server version: 1.0.0 transport: stdio再写一个启动类把工具注册进去package com.example.mcpserver; import com.example.mcpserver.service.WeatherToolService; import org.springframework.ai.tool.ToolCallbackProvider; import org.springframework.ai.tool.method.MethodToolCallbackProvider; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.context.annotation.Bean; SpringBootApplication public class McpServerApplication { public static void main(String[] args) { SpringApplication.run(McpServerApplication.class, args); } Bean public ToolCallbackProvider weatherTools(WeatherToolService service) { return MethodToolCallbackProvider.builder() .toolObjects(service) .build(); } }初始化完成之后工具就被暴露了。如果传输方式是 stdio本地客户端通过命令行进程连接如果改成 WebMVC 传输Spring AI 会自动暴露一个 HTTP 端点比如/mcp外部客户端可以直接通过 HTTP POST 访问。这里我必须强调一个观念一个 Spring Boot 应用既可以作为客户端调用远端 Server也可以作为 Server 暴露工具两者不冲突。实际项目中经常会遇到mcp-client模块和mcp-server模块分别启动中间通过本地端口或 npx 协议互相调用。4.3 自定义工具背后的 JSON-RPC 链路工具注册好了以后我们可以手动通过 HTTP 端点验证一下。比如传输方式为 WebMVC 时直接向/mcp发送一个 JSON-RPC 请求来查看工具列表{ jsonrpc: 2.0, id: 1, method: tools/list, params: {} }返回值会包含工具名、描述和 JSON Schema 的输入参数定义{ jsonrpc: 2.0, id: 1, result: { tools: [ { name: getWeather, description: 根据城市名称查询实时的天气情况返回天气描述、温度和湿度, inputSchema: { type: object, properties: { city: { type: string, description: 城市名称 } }, required: [city] } } ] } }调用工具时发送{ jsonrpc: 2.0, id: 2, method: tools/call, params: { name: getWeather, arguments: { city: 北京 } } }为什么要理解这条链路因为生产排错时直接对着 JSON-RPC 请求比对着日志更直观。工具没被注册、参数类型不对、传输协议不匹配通过这一个请求就能立刻看出来。自己具备手测 MCP 端点的能力以后遇到了问题就不会两眼一抹黑。5. 进阶把 MCP 工具装进 Agent / RAG / SQL 实战5.1 Agent 的基本形态与多工具协同MCP 的价值发挥最大化通常是配合一个 Agent 形态的程序。简单理解Agent 就是让大模型拥有“思考 - 调用工具 - 观察结果 - 再思考”的循环能力。Spring AI 提供了ChatClient的多轮对话能力和工具调用机制配合 MCP 的多个工具就能构建出一个很实用的 Agent 雏形。比如一个客服 Agent注册了订单查询、库存查询、物流查询三个 MCP 工具。用户问“帮我看看订单 12345 什么时候到货”大模型先查询电商系统里订单状态再查询物流系统信息最后汇总成自然语言回复用户。整个过程用户只发了一条消息但模型内部已经按需依次调用了多个工具。我在实际项目里是这么做的定义一个动态工具列表在运行时通过ToolCallbackProvider从 MCP Server 注册工具然后在ChatClient里配置defaultTools让模型能访问这些回调。同时配合MessageWindowChatMemory保存多轮记忆实现简单的多轮 Agent 对话Configuration public class AgentConfig { Bean public ChatClient chatClient(ChatClient.Builder builder, ToolCallbackProvider toolCallbackProvider) { return builder .defaultTools(toolCallbackProvider) .defaultSystem(你是一个智能客服助手可以查询订单、物流和库存信息) .build(); } Bean public ChatMemory chatMemory() { return MessageWindowChatMemory.builder() .maxMessages(20) .build(); } }5.2 用 MCP 把 RAG 检索暴露给大模型RAG检索增强生成是现在大模型应用里最常见的架构流程基本是把文档切块、向量化、存进向量数据库用户提问时先检索最相关内容再拼到 Prompt 里让模型回答。Spring AI 对 RAG 的支持很成熟内置了VectorStore接口和多种向量库实现。把 RAG 检索能力封装成 MCP 工具的思路有两层。如果你是消费方可以用一个 MCP Server 来暴露“内部文档搜索”工具大模型需要业务资料时直接调用如果你是提供方也可以把自己内部的检索能力打包成 MCP Server给多个业务系统共享。举个例子在企业内部做一个知识库问答系统我们可以在 Server 端写一个工具Tool(description 检索企业内部的运维知识库返回与问题最相关的文档片段) public String searchKnowledgeBase(String question, int topK) { // 内部调用 VectorStore 的 similaritySearch 方法 ListDocument documents vectorStore.similaritySearch( SearchRequest.builder() .query(question) .topK(topK) .build() ); return documents.stream() .map(Document::getText) .collect(Collectors.joining(\n---\n)); }这样一个工具模型就具备了对内部资料的精准访问能力而不用每次都把整个文档库塞进上下文在控制成本的同时也降低了幻觉概率。个人做了一些测试后发现RAG 场景中 MCP 的收益主要在统一入口和权限控制上多个系统可以通过同一个工具入口检索同时可以在工具层做数据权限过滤。5.3 数据库 NL2SQL 的 MCP 封装最近网上 “NL2SQL” 相关的词很热也就是把自然语言直接翻译成 SQL 查询数据库。这块如果直接在 Prompt 里给模型放任意的 SQL 执行权限风险爆炸。更稳妥的做法就是封装成一个 MCP 工具对内只暴露受控的查询能力对外只允许特定操作。我们在实际的 Java 项目里可以写一个 SQL 查询 MCP Server内置几个工具listTables列出当前数据库所有表名。getTableSchema获取某张表的字段结构。runSelectQuery执行只读 SQL 查询并返回格式化结果。然后引导模型的使用方式先让它列出表再看表结构最后生成合法的查询 SQL 并执行。服务端做一层校验通过正则或者 SQL 解析器确认语句确实只是 SELECT否则直接拒绝。Tool(description 执行只读 SQL 查询返回结果集) public String runSelectQuery(String sql) { if (!isReadOnlySql(sql)) { return 错误只允许执行 SELECT 查询; } ListMapString, Object rows jdbcTemplate.queryForList(sql); return new ObjectMapper().writeValueAsString(rows); }这套用法在生产里很有价值。原来业务方想要一张报表需要找数据开发写 SQL、捞数、导出、再整理现在通过一个只读查询 MCP Server运营同学直接用自然语言问“上个月华东区域的销售总额”大模型自动完成全程安全控制在工具层而不是模型层链路是可控的。5.4 Spring AI Alibaba 与 DashScope 的集成建议国内场景绕不开通义千问、DashScope 这一套。Spring AI Alibaba 是阿里在 Spring AI 基础上做的适配核心优势是提供了 DashScope 模型的 Spring Boot Starter对中文场景、企业内网部署和阿里云生态都比较友好。如果你主要面向国内业务依赖可以直接换成dependency groupIdcom.alibaba.cloud.ai/groupId artifactIdspring-ai-alibaba-starter/artifactId /dependency配置方面base-url 指向https://dashscope.aliyuncs.com/api-key 使用 DashScope 的 Key模型名用qwen-plus或qwen-turbo。Spring AI Alibaba 1.0.x 基于 Spring AI 生态所以 MCP 客户端机制和原版基本一致也可以直接配合 MCP 使用。区别主要体现在模型依赖的内置工具、模型名称映射以及部分阿里云产品的一体化整合上比如它可以直接把阿里云数据库、阿里云 OSS 等定义为开箱即用的 MCP 工具。这里有个经验如果一个项目既要求用 OpenAI 官方模型又要求支持国内模型最好的做法是把模型通过ChatClient做抽象隔离MCP 工具层保持不变到部署环境时通过配置切换模型供应商。Spring AI 在设计上支持这种模式MCP 工具不关心底层是哪个模型的。6. 避开这些坑排查经验与源码级观察6.1 高频问题排查速查表问题现象最可能原因解决思路启动后日志里没有 MCP 工具注册缺spring-ai-starter-mcp-client依赖检查依赖是否引入并确认 spring-ai BOM 版本stdio 方式连接 npx 一直失败本机没装 Node 或 npx或者 npx 命令路径不对终端先执行npx -y modelcontextprotocol/server-everything验证模型不调用工具直接答非所问工具描述不清晰或模型在选择工具时没识别到工具优化 Tool description让用途和输入参数描述更明确tools/call 请求返回超时request-timeout 设置太短把spring.ai.mcp.client.request-timeout调到 30s 以上工具参数总是缺少某字段参数未标注 ToolParam 或方法签名不太明确给每个参数补充 description 和默认值自定义 Server 启动后没暴露任何工具ToolCallbackProvider 没装配确认启动类里注入了 MethodToolCallbackProvider Bean连接远程 MCP Server 认证失败Token 直接写死在 YAML 或环境变量没注入改用环境变量方式加载并检查服务端认证策略工具返回了 JSON 但因为格式问题模型理解困难返回值太复杂字段名不够表意尽量返回结构清晰、带明确字段名的 JSON减少无关嵌套6.2 Debug 的正确姿势我踩过最多坑的就是 MCP 链路的问题定位因为整个链路隔着模型调用、客户端、协议传输、服务端等多层逻辑。一旦出现问题我建议按下面的顺序排查。先看模型层。把 MCP 工具临时停用直接用ChatClient调一条普通 Prompt确认模型接口本身没问题。如果模型都连不上工具侧再完美也没用。再看工具注册层。启动时设置logging.level.org.springframework.aiDEBUG观察日志里ToolCallbacks 是否被注册以及每个工具的名称和参数定义。Spring AI 启动阶段会打印被注册到我这个chatClient的工具列表一眼就能看出来。然后直接测协议层。如果 Server 是 HTTP 方式用 Postman 或 curl 发tools/list请求验证 Server 端是否正常工作。这一步能快速区分是 Server 问题还是客户端问题。最后看客户端调用层。在tools/call的 Completions 回调处打日志观察传入的参数和返回结果确认序列化格式有没有问题。6.3 从源码理解自动配置触发条件工具没注册这个现象光看配置容易好几次都发现不了。如果从源码层面理解触发条件定位速度快得多。Spring AI 客户端自动配置核心类是McpClientAutoConfiguration会对配置里每个 server 创建一个McpClient随后通过McpToolUtils和ToolCallbackProvider把工具注册进 Spring 容器。这个自动配置只有一个触发条件classpath 下存在spring-ai-starter-mcp-client并且配置中有spring.ai.mcp.client.servers列表。换个说法你没有配置 servers自动配置就算执行了也没东西可注册。Server 端自动配置核心类是McpServerAutoConfiguration它需要扫描到容器里的ToolCallbackProvider。Spring Boot 启动时如果没有注册ToolCallbackProvider的 Bean那 Server 暴露的工具就是空列表。很多人以为方法上加 Tool 就能自动暴露其实还差这最后一步要把包含该方法对象的 provider 上报给 McpServer 自动配置。提示如果你的 Service 类上有 Tool 方法但始终没有暴露请检查启动类中是否有一个MethodToolCallbackProvider或ToolCallbackProvider类型的 Bean。这是最常见的“工具找不到”根因。6.4 关于版本升级和长期维护的一点建议Spring AI 更新速度非常快几乎每个月都有新版本2.0 系列也在路上。我经历过的版本升级启发是不要盲目追新尤其是生产环境尽量固定在某个 1.0.x 的 patch 版本。如果看到新版本提供关键修复再升升级前主要关注三点spring.ai.mcp.client.servers配置的字段名是否变更。McpClient、ToolCallbackProvider包路径有没有移动。Tool注解是否新增了必需属性。我在一次升级中遇到工具名称从短名称变成了“类名#方法名”的形式导致模型调用不匹配后来把版本固定回去才解除问题。这类情况在 MCP 协议迭代期大概率还会遇到保持配置依附于版本、依赖仓库锁定版本号是更稳妥的做法。还有一点MCP Server 的暴露范围要控制好。如果工具里包含了删除操作、有权限敏感的数据查询务必在Tool(description ...)里写清楚触发条件和限制同时在工具内部做身份鉴权和参数校验。模型是不可靠的执行者防线要放在工具层不要指望模型的道德约束。这是我在真实项目里付出过代价后拿到的经验。最后分享一个我在实操里觉得最有实效的小技巧。第一次跑 MCP 的时候先用云端现成的官方 Everything Server 试验不写业务工具验证整个链路链路通了以后再写自己的 Tool。这样一旦出现问题可以明确区分是“协议链路问题”还是“业务工具问题”不会在一堆代码里瞎找半天。如果你现在正准备开始 Spring AI 的项目不妨先用十五分钟把上面的客户端 Demo 跑通你就能看到 AI 模型调用工具的全过程方向对了后面的路自然就顺了。
返回列表