news 2026/5/11 9:39:48

Spring AI 进阶之路05:集成 MCP 协议实现工具调用

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Spring AI 进阶之路05:集成 MCP 协议实现工具调用

引子

在上一篇文章中,我们通过集成 SearXNG,成功让大模型“睁眼看世界”,具备了获取互联网实时信息的能力。然而,无论是 RAG(检索增强生成)还是联网搜索,本质上都是让 AI“读”更多的书,获取更多的信息。但一个真正的智能助手,不仅要能“读”,还要能“写”“做”

试想这样一个场景:你希望 AI 帮你整理今天的股市数据,并生成一份 Excel 报表保存到桌面;或者你希望 AI 帮你给客户发送一封会议邀请邮件。在目前的架构下,大模型只能告诉你“邮件内容写好了,请你复制粘贴去发送”,它就像一个被困在罐子里的“超级大脑”,虽然博学,却无法触碰现实世界。

为了打破这个次元壁,我们需要引入MCP(Model Context Protocol,模型上下文协议)。关于它的概念不多赘述概念,网上相关的文章已经很多了,有需要了解请看MCP中文文档:https://docs.mcpcn.org/introduction。

本文将分为两个部分实战 MCP:

  1. 作为客户端(Client):调用现成的 MCP 服务。
  2. 作为服务端(Server):开发我们自己的 MCP 服务。

调用 MCP 服务:操作本地文件

Spring AI 提供了spring-ai-mcp-client,允许我们的应用连接到任何遵循 MCP 标准的服务器。这里我们以官方提供的文件系统 MCP 服务器为例,让 AI 具备在本地创建和读取文件的能力。

前提条件:由于文件系统 MCP 服务是基于 Node.js 的,请确保你的本地环境已安装 Node.js (v18+)。

1.添加依赖

pom.xml中引入 MCP Client 相关的依赖:

<dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-client</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-mcp</artifactId></dependency>

2. 配置 MCP Server 连接

MCP 支持两种连接模式:stdio(标准输入输出,适用于本地进程)和sse(Server-Sent Events,适用于网络服务)。对于本地文件系统服务,我们使用stdio模式。

resources目录下新建mcp-server.json文件,定义如何启动文件系统服务:

{"mcpServers":{"filesystem":{"command":"D:\\devolop\\node\\npx.cmd","args":["-y","@modelcontextprotocol/server-filesystem","D:\\devolop"]}}}

配置解析

  • command: 指向你的npx可执行文件路径(Windows 下通常是npx.cmd)。
  • args:
    • -y: 自动确认安装。
    • @modelcontextprotocol/server-filesystem: 官方的文件系统 MCP 服务包。
    • D:\\devolop:这是允许 AI 访问的根目录。为了安全起见,AI 只能操作这个目录及其子目录下的文件。

接着,在application.yml中启用 MCP Client 并加载上述配置:

spring:ai:mcp:client:enabled:truename:spring-ai-mcp-clienttype:ASYNC# 推荐使用异步非阻塞模式stdio:servers-configuration:classpath:mcp-server.json

3.代码改造

我们需要在ChatService初始化时,将 MCP Client 发现的工具注册到ChatClient中。

publicChatServiceImpl(ChatClient.BuilderchatClientBuilder,ToolCallbackProvidertools){// tools 会自动注入所有配置好的 MCP 工具this.chatClient=chatClientBuilder.defaultToolCallbacks(tools).build();}

4.效果测试

启动项目,观察控制台日志,可以看到MCP工具已经连接成功。

现在,我们在对话框中输入这些内容:

打开我们配置的D:\devolop目录,可以看到文件已经被成功创建。

开发 MCP 服务:邮件与时间工具

除了调用现有的工具,更常见的场景是将我们自己的业务逻辑(如查询内部系统、发送通知)封装成 MCP 工具供大模型调用。

为了演示,我们创建一个新的模块mcp-server,实现“获取当前时间”和“发送邮件”两个功能。

mcp-server模块的pom.xml中添加必要的依赖。除了 WebFlux(MCP Server 常用底层),我们还需要spring-boot-starter-mail来发送邮件,以及flexmark用于将 AI 生成的 Markdown 内容转换为邮件友好的 HTML。

<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>com.cc</groupId><artifactId>SpringAI-MCP-RAG-Dev</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>mcp-server</artifactId><properties><maven.compiler.source>17</maven.compiler.source><maven.compiler.target>17</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-bom</artifactId><version>1.0.0</version><type>pom</type><scope>import</scope></dependency></dependencies></dependencyManagement><dependencies><!-- MCP Server 依赖 --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-webflux</artifactId></dependency><!-- 邮件发送依赖 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-mail</artifactId></dependency><!-- Markdown 转 HTML 工具 --><dependency><groupId>com.vladsch.flexmark</groupId><artifactId>flexmark-all</artifactId><version>0.64.8</version></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.apache.commons</groupId><artifactId>commons-lang3</artifactId><version>3.17.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId></dependency></dependencies></project>

1.添加配置

application.yml中配置 OpenAI Key、Redis(用于向量存储或缓存)以及 SMTP 邮件服务信息。

spring:application:name:spring-ai-mcp-serverdata:redis:host:127.0.0.1port:9379password:123456ai:mcp:server:name:spring-ai-mcp-server-sseversion:1.0.0sse-endpoint:/ssetype:asyncmail:host:smtp.163.comport:465username:123@163.compassword:123456# 注意:这里通常是邮箱授权码,不是登录密码protocol:smtpdefault-encoding:UTF-8properties:mail:smtp:socketFactory:port:465class:javax.net.ssl.SSLSocketFactoryssl:enable:truelogging:level:root:infoserver:port:6080

启动项目,访问http://localhost:6080/sse,如果能正常启动,说明配置无误。

2. 开发时间查询工具

大模型本身对“现在是几点”没有概念,我们需要提供一个工具。

packagecom.cc.mcp.tool;importlombok.extern.slf4j.Slf4j;importorg.springframework.ai.tool.annotation.Tool;importorg.springframework.stereotype.Component;importjava.time.LocalDateTime;importjava.time.format.DateTimeFormatter;@Component@Slf4jpublicclassDateTool{// @Tool 注解将方法暴露为 MCP 工具// description 非常重要,大模型根据它来判断何时调用此工具@Tool(description="获取当前时间")publicStringgetCurrentTime(){log.info("=================调用MCP工具:获取当前时间=================");returnString.format("当前的时间是 %s",LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));}}

3. 开发邮件发送工具

这是一个稍微复杂一点的工具,需要定义参数结构。

packagecom.cc.mcp.tool;importcom.vladsch.flexmark.html.HtmlRenderer;importcom.vladsch.flexmark.parser.Parser;importcom.vladsch.flexmark.util.data.MutableDataSet;importjakarta.mail.MessagingException;importjakarta.mail.internet.MimeMessage;importlombok.*;importlombok.extern.slf4j.Slf4j;importorg.springframework.ai.tool.annotation.Tool;importorg.springframework.ai.tool.annotation.ToolParam;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.beans.factory.annotation.Value;importorg.springframework.mail.javamail.JavaMailSender;importorg.springframework.mail.javamail.MimeMessageHelper;importorg.springframework.stereotype.Component;@Component@Slf4jpublicclassEmailTool{privatefinalJavaMailSendermailSender;privatefinalStringfrom;@AutowiredprivateEmailTool(JavaMailSendermailSender,@Value("${spring.mail.username}")Stringfrom){this.mailSender=mailSender;this.from=from;}// 定义请求参数类,大模型会自动填充这些字段@Data@ToString@NoArgsConstructor@AllArgsConstructorpublicstaticclassEmailRequest{@ToolParam(description="收件人邮箱地址")privateStringemail;@ToolParam(description="发送邮件的标题/主题")privateStringsubject;@ToolParam(description="发送邮件的消息/正文内容")privateStringmessage;@ToolParam(description="发送邮件的内容类型,1为HTML格式,2为普通文本格式")privateIntegercontentType;}@Tool(description="给指定邮箱发送邮件信息。")publicStringsendEmail(EmailRequestemailRequest){log.info("=================调用MCP工具:sendEmail=================");log.info("请求详情: {}",emailRequest);IntegercontentType=emailRequest.getContentType();try{MimeMessagemimeMessage=mailSender.createMimeMessage();MimeMessageHelpermimeMessageHelper=newMimeMessageHelper(mimeMessage);mimeMessageHelper.setFrom(from);mimeMessageHelper.setTo(emailRequest.getEmail());mimeMessageHelper.setSubject(emailRequest.getSubject());// 智能处理:如果是 Markdown 格式,自动转 HTMLif(contentType!=null&&contentType==1){mimeMessageHelper.setText(convertMarkdownToHtml(emailRequest.getMessage()),true);}elseif(contentType!=null&&contentType==2){mimeMessageHelper.setText(emailRequest.getMessage(),true);}else{// 默认处理mimeMessageHelper.setText(emailRequest.getMessage());}mailSender.send(mimeMessage);return"邮件发送成功";}catch(MessagingExceptione){log.error("发送邮件失败",e);return"发送邮件失败: "+e.getMessage();}}/** * 将Markdown格式的字符串转换为HTML格式 */publicstaticStringconvertMarkdownToHtml(StringmarkdownStr){MutableDataSetdataSet=newMutableDataSet();Parserparser=Parser.builder(dataSet).build();HtmlRendererhtmlRenderer=HtmlRenderer.builder(dataSet).build();returnhtmlRenderer.render(parser.parse(markdownStr));}}

4. 注册工具

最后,在启动类或配置类中,将我们编写的 Tool Bean 注册到ToolCallbackProvider中。

package com.cc.mcp; import com.cc.mcp.tool.DateTool; import com.cc.mcp.tool.EmailTool; 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 Application { public static void main(String[] args) { SpringApplication.run(Application.class, args); } /** * 注册自定义 MCP 工具 * 这样 ChatClient 就能感知到这些工具的存在 */ @Bean public ToolCallbackProvider registerMCPTools(DateTool dateTool, EmailTool emailTool) { return MethodToolCallbackProvider.builder() .toolObjects(dateTool, emailTool) .build(); } }

5. 综合测试

启动项目,观察日志,确认工具已加载。

测试时间查询:


测试邮件发送:

增加记忆功能:让对话更连贯

在实际使用中,我们可能会分多轮对话来完成任务。但默认情况下,ChatClient是无状态的,它记不住上一句说了什么:

为了解决这个问题,我们需要引入Chat Memory。在ChatServiceImpl中注入ChatMemory,并将其配置到ChatClient中:

privatefinalChatClientchatClient;// 注入 ChatMemorypublicChatServiceImpl(ChatClient.BuilderchatClientBuilder,ToolCallbackProvidertools,ChatMemorychatMemory){this.chatClient=chatClientBuilder// 添加记忆 Advisor.defaultAdvisors(MessageChatMemoryAdvisor.builder(chatMemory).build()).defaultToolCallbacks(tools).build();}

配置完成后,模型就具备了上下文记忆能力,能够流畅地处理多轮意图确认。

小结

通过本篇文章,我们实现了 Spring AI 应用功能的重大飞跃:从单纯的“信息获取者”进化为了“任务执行者”。

  1. 利用MCP Client,我们轻松集成了现有的文件系统服务。
  2. 利用Spring AI Tool,我们开发了自定义的邮件和时间服务。
  3. 利用Chat Memory,我们赋予了 AI 记忆,使其交互更加自然。

现在,我们的 AI 已经可以操作文件、发送邮件了。但在企业级应用中,最核心的数据往往存储在数据库中。如何让大模型安全、准确地查询和操作数据库?下一篇,我们将探讨基于 MCP 的大模型与数据库交互开发

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/5 11:59:41

一个人能保持松弛感的来源

一个人能在任何事中保持松弛感&#xff0c;其根源并非源于对结果的不在乎或天生的淡定&#xff0c;而是一种**深刻的内心秩序和内在力量的展现**。它不是漂浮在表面的技巧&#xff0c;而是扎根于内心的稳定系统。 这种“随时随地”的松弛感&#xff0c;通常来源于以下几个相互关…

作者头像 李华
网站建设 2026/5/4 5:21:46

官网-工伤保险条例

官网:工伤保险条例_中华人民共和国人力资源和社会保障部 第一章 总 则* 第一条 为了保障因工作遭受事故伤害或者患职业病的职工获得医疗救治和经济补偿,促进工伤预防和职业康复,分散用人单位的工伤风险,制定本条例。 第二条 中华人民共和国境内的企业、事业单位、社会团…

作者头像 李华
网站建设 2026/5/5 6:20:32

官网-女职工劳动保护特别规定

官网:女职工劳动保护特别规定(国务院令第619号) 行政法规_ 法律法规 _中国政府网 第一条 为了减少和解决女职工在劳动中因生理特点造成的特殊困难,保护女职工健康,制定本规定。 第二条 中华人民共和国境内的国家机关、企业、事业单位、社会团体、个体经济组织以及其他…

作者头像 李华
网站建设 2026/4/30 8:22:50

如何作为初学者接近复杂的数据科学主题

原文&#xff1a;towardsdatascience.com/how-to-approach-complex-data-science-topics-as-a-beginner-33f60b657ba2?sourcecollection_archive---------6-----------------------#2024-07-25 https://towardsdatascience.medium.com/?sourcepost_page---byline--33f60b657b…

作者头像 李华
网站建设 2026/5/10 15:54:38

基于Spring Boot的社区失物招领系统的设计与实现毕设源码

博主介绍&#xff1a;✌ 专注于Java,python,✌关注✌私信我✌具体的问题&#xff0c;我会尽力帮助你。 一、研究目的 本研究旨在设计并实现一个基于Spring Boot框架的社区失物招领系统&#xff0c;以满足现代社区管理中对失物招领功能的需求。具体研究目的如下&#xff1a; 首…

作者头像 李华
网站建设 2026/5/11 3:46:22

核工业检测系统通信链路的国产化元器件安全等级评估

摘要&#xff1a;核能设施数字化仪控系统对总线通信链路的功能安全性与抗辐照能力提出了严苛要求&#xff0c;尤其是在反应堆本体及乏燃料池等高辐射场环境中。本文以国科安芯推出的AS32S601型MCU与ASM1042S2S型CANFD收发器为研究对象&#xff0c;基于质子加速器单粒子效应试验…

作者头像 李华