Spring AI 系列之使用 Spring AI 开发模型上下文协议(MCP)

news2025/6/4 2:16:00

1. 概述

现代网页应用越来越多地集成大型语言模型(LLMs)来构建解决方案,这些解决方案不仅限于基于常识的问答。

为了增强 AI 模型的响应能力,使其更具上下文感知,我们可以将其连接到外部资源,比如搜索引擎、数据库和文件系统。然而,整合和管理多种格式和协议不同的数据源是一个挑战。

由 Anthropic 提出的模型上下文协议(Model Context Protocol,简称 MCP)解决了这一整合难题,提供了一种标准化的方式,将AI驱动的应用与外部数据源连接。通过MCP,我们可以在原生大型语言模型基础上构建复杂的智能代理和工作流。

在本教程中,我们将通过实际实现MCP的客户端-服务器架构,结合 Spring AI 来理解 MCP 的概念。我们将创建一个简单的聊天机器人,并通过 MCP 服务器扩展其功能,实现网页搜索、文件系统操作以及访问自定义业务逻辑。


2. 模型上下文协议基础(Model Context Protocol )

在深入实现之前,让我们先仔细了解 MCP 及其各个组成部分:

MCP 遵循客户端-服务器架构,围绕以下几个关键组件展开:

  • MCP Host(主机):   我们的主应用程序,集成了大型语言模型(LLM),并需要通过它连接外部数据源。

  • MCP Clients(客户端):负责与 MCP 服务器建立并维护一对一连接的组件。

  • MCP Servers(服务器):  集成外部数据源的组件,向客户端暴露交互功能。

  • Tools(工具):指 MCP 服务器暴露供客户端调用的可执行函数或方法。

此外,为了实现客户端与服务器之间的通信,MCP 提供了两种传输通道:

  • 标准输入/输出(stdio)用于通过本地进程和命令行工具的标准输入输出流进行通信。

  • 服务器发送事件(Server-Sent Events,SSE)用于基于 HTTP 的客户端和服务器之间的通信。

MCP是一个复杂且内容丰富的话题,建议参考官方文档以获得更多详细信息。

3. 创建 MCP 主机

既然我们已经对 MCP 有了一个整体的了解,接下来就开始动手实践 MCP 架构的实现。

我们将使用 Anthropic 的 Claude 模型来构建一个聊天机器人,作为我们的 MCP 主机。当然,也可以使用 Hugging Face 或 Ollama 上的本地大型语言模型,具体使用哪个 AI 模型对文中例子并不是关键的。

3.1 依赖项

首先,我们来向项目的 pom.xml 文件中添加所需的依赖项:


<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-anthropic-spring-boot-starter</artifactId>
    <version>1.0.0-M6</version>
</dependency>
<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-client-spring-boot-starter</artifactId>
    <version>1.0.0-M6</version>
</dependency>

Anthropic starter 依赖是对 Anthropic 消息 API 的封装,我们将在应用中使用它与 Claude 模型进行交互。此外,我们还引入了 

MCP client starter 依赖,它允许我们在Spring Boot 应用中配置客户端,从而与MCP 服务器保持一对一连接。由于当前版本1.0.0-M6 是一个里程碑版本,我们还需要在 pom.xml 中添加 Spring Milestones 仓库:

<repositories>
    <repository>
        <id>spring-milestones</id>
        <name>Spring Milestones</name>
        <url>https://repo.spring.io/milestone</url>
        <snapshots>
            <enabled>false</enabled>
        </snapshots>
    </repository>
</repositories>

这个仓库用于发布里程碑版本,与标准的 Maven Central 仓库不同。鉴于我们在项目中使用了多个Spring AI的starter,接下来我们还将在 pom.xml中引入Spring AI的版本管理(Bill of Materials,BOM):

<dependencyManagement>
    <dependencies>
        <dependency>
            <groupId>org.springframework.ai</groupId>
            <artifactId>spring-ai-bom</artifactId>
            <version>1.0.0-M6</version>
            <type>pom</type>
            <scope>import</scope>
        </dependency>
    </dependencies>
</dependencyManagement>

添加了 BOM 之后,我们可以去掉两个 starter 依赖中的版本号。BOM 能避免版本冲突风险,确保我们的 Spring AI 依赖相互兼容。

接下来,我们在 application.yaml 文件中配置 Anthropic 的 API 密钥和聊天模型:

spring:
  ai:
    anthropic:
      api-key: ${ANTHROPIC_API_KEY}
      chat:
        options:
          model: claude-3-7-sonnet-20250219

我们使用 ${} 属性占位符从环境变量中加载 API 密钥的值。

此外,我们指定了 Anthropic 最新且最智能的模型 Claude 3.7 Sonnet,模型 ID 为 claude-3-7-sonnet-20250219。你也可以根据需求使用其他模型。

配置好上述属性后, Spring AI会自动创建一个类型为ChatModel的 Bean,方便我们与指定模型进行交互。


3.2 配置 MCP 客户端以连接 Brave Search 和文件系统服务器

接下来,让我们为两个预构建的 MCP 服务器实现——Brave Search 和 Filesystem,配置 MCP 客户端。这些服务器将使我们的聊天机器人能够执行网页搜索和文件系统操作。

首先,在 application.yaml 文件中注册 Brave Search MCP 服务器的 MCP 客户端:

spring:
  ai:
    mcp:
      client:
        stdio:
          connections:
            brave-search:
              command: npx
              args:
                - "-y"
                - "@modelcontextprotocol/server-brave-search"
              env:
                BRAVE_API_KEY: ${BRAVE_API_KEY}

这里我们配置了一个使用 stdio 传输的客户端。我们指定了通过 npx 命令来下载并运行基于TypeScript 的 

@modelcontextprotocol/server-brave-search 包,并使用 -y 参数自动确认所有安装提示。

此外,我们还提供了 BRAVE_API_KEY 作为环境变量。

接下来,我们配置一个用于文件系统 MCP 服务器的 MCP 客户端:

spring:
  ai:
    mcp:
      client:
        stdio:
          connections:
            filesystem:
              command: npx
              args:
                - "-y"
                - "@modelcontextprotocol/server-filesystem"
                - "./"

与之前的配置类似,我们指定了运行文件系统 MCP 服务器包所需的命令和参数。通过这个配置,我们的聊天机器人可以在指定目录执行创建、读取和写入文件等操作。

这里我们只配置了当前目录(./)作为文件系统操作的路径,但也可以通过将多个目录添加到 args 列表中来指定更多目录。

应用启动时,Spring AI 会扫描我们的配置,创建 MCP 客户端, 并与对应的MCP服务器建立连接。同时,它会创建一个类型为 SyncMcpToolCallbackProvider 的 Bean,提供所有配置的 MCP 服务器暴露的工具列表。


3.3 构建一个基础聊天机器人

在配置好AI模型和 MCP 客户端之后,我们来构建一个简单的聊天机器人:

@Bean
ChatClient chatClient(ChatModel chatModel, SyncMcpToolCallbackProvider toolCallbackProvider) {
    return ChatClient
      .builder(chatModel)
      .defaultTools(toolCallbackProvider.getToolCallbacks())
      .build();
}

我们首先使用 ChatModel 和 SyncMcpToolCallbackProvider 这两个 Bean 创建一个 ChatClient 类型的 Bean。ChatClient 类将作为我们与聊天完成模型(即 Claude 3.7 Sonnet)交互的主要入口。

接下来,我们注入ChatClient Bean 来创建一个新的 ChatbotService 类:

String chat(String question) {
    return chatClient
      .prompt()
      .user(question)
      .call()
      .content();
}

我们创建了一个chat()方法,在该方法中将用户的问题传递给 chatClient Bean,并直接返回 AI 模型的响应结果。

既然我们已经实现了服务层,接下来我们来基于它暴露一个 REST API:

@PostMapping("/chat")
ResponseEntity<ChatResponse> chat(@RequestBody ChatRequest chatRequest) {
    String answer = chatbotService.chat(chatRequest.question());
    return ResponseEntity.ok(new ChatResponse(answer));
}
record ChatRequest(String question) {}
record ChatResponse(String answer) {}

我们将在本教程后续部分使用上述 API 端点与聊天机器人进行交互。


4. 创建自定义 MCP 服务器

除了使用预构建的 MCP 服务器之外,我们还可以创建自己的 MCP 服务器,以便通过自定义业务逻辑扩展聊天机器人的功能。

接下来,我们来探索如何使用 Spring AI 创建自定义 MCP 服务器。

本节将创建一个新的 Spring Boot 应用。


4.1 依赖项

首先,在我们的 pom.xml 文件中添加必要的依赖:

<dependency>
    <groupId>org.springframework.ai</groupId>
    <artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
    <version>1.0.0-M6</version>
</dependency>

我们引入了 Spring AI 的 MCP 服务器依赖,该依赖提供了创建支持基于 HTTP 的 SSE 传输的自定义 MCP 服务器所需的相关类。


4.2 定义并暴露自定义工具

接下来,我们定义一些自定义工具,这些工具将由我们的 MCP 服务器对外暴露。

我们将创建一个 AuthorRepository 类,提供获取作者详情的方法:


class AuthorRepository {
    @Tool(description = "Get Baeldung author details using an article title")
    Author getAuthorByArticleTitle(String articleTitle) {
        return new Author("John Doe", "john.doe@baeldung.com");
    }
    @Tool(description = "Get highest rated Baeldung authors")
    List<Author> getTopAuthors() {
        return List.of(
          new Author("John Doe", "john.doe@baeldung.com"),
          new Author("Jane Doe", "jane.doe@baeldung.com")
        );
    }
    record Author(String name, String email) {
    }
}

在本示例中,我们返回的是硬编码的作者信息,但在真实应用中,这些工具通常会与数据库或外部 API 进行交互。

我们使用@Tool注解为两个方法添加标记,并为每个方法提供简要描述。这个描述有助于AI模型根据用户输入判断是否调用这些工具,并将结果整合到其响应中。

接下来,我们将这些工具注册到 MCP 服务器中:

@Bean
ToolCallbackProvider authorTools() {
    return MethodToolCallbackProvider
      .builder()
      .toolObjects(new AuthorRepository())
      .build();
}

我们使用 MethodToolCallbackProvider 从 AuthorRepository 类中定义的工具创建一个 ToolCallbackProvider 类型的 Bean。那些使用 @Tool 注解的方法会在应用启动时作为 MCP 工具对外暴露。


4.3 为自定义 MCP 服务器配置 MCP 客户端

最后,为了在我们的聊天机器人应用中使用这个自定义的 MCP 服务器,我们需要为它配置一个对应的 MCP 客户端:

spring:
  ai:
    mcp:
      client:
        sse:
          connections:
            author-tools-server:
              url: http://localhost:8081

在 application.yaml 文件中,我们为自定义 MCP 服务器配置了一个新的客户端。注意,这里我们使用的是 sse(服务器发送事件)传输类型。

此配置假设 MCP 服务器运行在 http://localhost:8081,如果你的服务器运行在不同的主机或端口,请确保更新该 URL。

通过这个配置,我们的MCP客户端现在除了可以调用Brave Search和文件系统MCP服务器提供的工具外,还可以调用自定义 MCP 服务器所暴露的工具。


5. 与我们的聊天机器人交互

现在我们已经构建好了聊天机器人,并将其集成了多个 MCP 服务器,接下来我们就来实际与它进行交互并测试效果。

我们将使用 HTTPie CLI 工具调用聊天机器人的 API 端点:

http POST :8080/chat question="How much was Elon Musk's initial offer to buy OpenAI in 2025?"

在这里,我们向聊天机器人发送了一个关于 LLM 知识截止日期之后发生事件的简单问题。让我们看看它会返回什么样的回答:

{
    "answer": "Elon Musk's initial offer to buy OpenAI was $97.4 billion. [Source](https://www.reuters.com/technology/openai-board-rejects-musks-974-billion-offer-2025-02-14/)."
}

正如我们所看到的,聊天机器人能够使用配置好的 Brave Search MCP 服务器执行网页搜索,并提供一个准确的答案以及相应的来源。

接下来,我们来验证聊天机器人是否可以通过 Filesystem MCP 服务器执行文件系统操作:

http POST :8080/chat question="Create a text file named 'mcp-demo.txt' with content 'This is awesome!'."

我们指示聊天机器人创建一个名为mcp-demo.txt的文件,并写入特定内容。让我们看看它是否能够完成这个请求:

{
    "answer": "The text file named 'mcp-demo.txt' has been successfully created with the content you specified."
}

聊天机器人返回了一个成功的响应。我们可以在 application.yaml 文件中指定的目录中验证该文件是否确实已被创建。

最后,我们来验证聊天机器人是否能够调用我们自定义 MCP 服务器所暴露的工具。我们将通过提及一篇文章的标题来询问作者的详细信息:

http POST :8080/chat question="Who wrote the article 'Testing CORS in Spring Boot?' on Baeldung, and how can I contact them?"

让我们调用这个 API,看看聊天机器人的响应中是否包含了我们预设的作者信息:

{
    "answer": "The article 'Testing CORS in Spring Boot' on Baeldung was written by John Doe. You can contact him via email at [john.doe@baeldung.com](mailto:john.doe@baeldung.com)."
}

上述响应验证了聊天机器人是通过我们自定义MCP服务器所暴露的getAuthorByArticleTitle() 工具获取信息的。

我们强烈建议你在本地搭建完整的代码环境,并尝试使用不同的提示语与聊天机器人进行交互,深入体验其功能。

6. 总结

在本文中,我们深入探讨了 模型上下文协议(Model Context Protocol, MCP),并通过 Spring AI 实现了其客户端-服务器架构。

首先,我们使用 Anthropic 的 Claude 3.7 Sonnet 模型构建了一个简单的聊天机器人,作为我们的 MCP 主机(Host)。

接着,为了让聊天机器人具备网页搜索能力并支持文件系统操作,我们分别为 Brave Search API 和 Filesystem 的MCP服务器配置了对应的 MCP 客户端。

最后,我们创建了一个自定义的MCP 服务器,并在MCP 主机应用中配置了对应的 MCP 客户端,使聊天机器人能够调用我们自己的业务逻辑工具。

 关注我不迷路,系列化的给您提供当代程序员需要掌握的现代AI工具和框架

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2396077.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

[Python] Python运维:系统性能信息模块psutil和系统批量运维管理器paramiko

初次学习&#xff0c;如有错误还请指正 目录 系统性能信息模块psutil 获取系统性能信息 CPU信息 内存信息 磁盘信息 网络信息 其他信息 进程信息 实用的IP地址处理模块IPy IP地址、网段的基本处理 多网络计算方法 系统批量运维管理器paramiko paramiko 的安装 Li…

Linux 简单模拟实现C语言文件流

&#x1f307;前言 在 C语言 的文件流中&#xff0c;存在一个 FILE 结构体类型&#xff0c;其中包含了文件的诸多读写信息以及重要的文件描述符 fd&#xff0c;在此类型之上&#xff0c;诞生了 C语言 文件相关操作&#xff0c;如 fopen、fclose、fwrite 等&#xff0c;这些函数…

小程序使用npm包的方法

有用的链接 npm init -y 这个命令很重要, 会初始化 package.json 再重新打开微信小程序开发工具 选择工具中npm构建 在程序中引用时在main.js中直接使用包名的方式引用即可 如安装的是generator包&#xff0c;npm构建后就会生成 const myPackage require(***-generato…

Rust 学习笔记:发布一个 crate 到 crates.io

Rust 学习笔记&#xff1a;发布一个 crate 到 crates.io Rust 学习笔记&#xff1a;发布一个 crate 到 crates.io提供有用的文档注释常用标题文档注释作为测试注释所包含的项目 使用 pub use 导出一个方便的公共 API设置 crates.io 账户添加 metadata 到一个新的 crate发布到 c…

Vert.x学习笔记-EventLoop与Context的关系

Vert.x学习笔记 1. EventLoop 的核心作用2. Context 的核心作用3. EventLoop 与 Context 的关系1. 事件循环&#xff08;EventLoop&#xff09;的核心职责2. 上下文&#xff08;Context&#xff09;的核心职责3. 事件循环与上下文的关系&#xff08;1&#xff09;一对一绑定&am…

2025030给荣品PRO-RK3566开发板单独升级Android13的boot.img

./build.sh init ./build.sh -K ./build.sh kernel 【导入配置文件】 Z:\Android13.0\rockdev\Image-rk3566_t\config.cfg 【更新的内核】 Z:\Android13.0\rockdev\Image-rk3566_t\boot.img 【导入分区表&#xff0c;使用原始的config.cfg会出错的^_】 Z:\Android13.0\rockdev\…

由enctype-引出post与get的关系,最后深究至请求/响应报文

本篇载自我的笔记&#xff0c;本次为第二次复习。我觉得我有能力理一下思路了。 --- 笔记截图。 enctype HTML 表单的 enctype&#xff08;Encode Type&#xff0c;编码类型&#xff09;属性用于控制表单数据在提交到服务器时的编码方式&#xff0c;不同取值的详细解析如下&a…

搭建基于VsCode的ESP32的开发环境教程

一、VsCode搜索ESP-IDF插件 根据插件处搜索找到ESP-IDF并安装 安装完成 二、配置安装ESP-IDF 配置IDF 按照如下配置&#xff0c;点击安装 安装完成 三、使用案例程序 创建一个闪光灯的例子程序&#xff0c;演示程序编译下载。 选择blink例子&#xff0c;闪烁LED的程序 选…

【MFC】初识MFC

目录 01 模态和非模态对话框 02 静态文本 static text 01 模态和非模态对话框 首先我们需要知道模态对话框和非模态对话框的区别&#xff1a; 模态对话框是一种阻塞时对话框&#xff0c;它会阻止用户与应用程序的其他部分进行交互&#xff0c;直到用户与该对话框进行交互并关…

如何通过数据分析优化项目决策

通过数据分析优化项目决策需从明确数据分析目标、选择适当的数据分析工具、确保数据质量、建立数据驱动文化等方面入手&#xff0c;其中&#xff0c;明确数据分析目标是优化决策过程的基础&#xff0c;只有清晰明确的数据分析目标才能指导有效的数据采集与分析&#xff0c;避免…

2024年数维杯国际大学生数学建模挑战赛B题空间变量协同估计方法研究解题全过程论文及程序

2024年数维杯国际大学生数学建模挑战赛 B题 空间变量协同估计方法研究 原题再现&#xff1a; 在数理统计学中&#xff0c;简单采样通常假设来自相同总体的采样点彼此独立。与数理统计相反&#xff0c;空间统计假设空间变量的采样点是相依的&#xff0c;并在其值中表现出某些趋…

leetcode hot100刷题日记——34.将有序数组转换为二叉搜索树

First Blood&#xff1a;什么是平衡二叉搜索树&#xff1f; 二叉搜索树&#xff08;BST&#xff09;的性质 左小右大&#xff1a;每个节点的左子树中所有节点的值都小于该节点的值&#xff0c;右子树中所有节点的值都大于该节点的值。 子树也是BST&#xff1a;左子树和右子树也…

网页自动化部署(webhook方法)

实现步骤&#xff1a; 宝塔安装宝塔WebHook 2.5插件。 github 上配置网页仓库&#xff08;或可在服务器的网页根目录clone&#xff09;。 配置宝塔WebHook 2.5 添加hook脚本&#xff1b; 编辑添加syncJC脚本&#xff1b; #!/bin/bash # 定义网站根目录 WEBROOT"/www…

AU6825集成音频DSP的2x32W数字型ClaSSD音频功率放大器(替代TAS5825)

1.特性 ● 输出配置 - 立体声 2.0: 2 x 32W (8Ω,24V,THD N 10%) - 立体声 2.0: 2 x 26W (8Ω,21V,THD N 1%) ● 供电电压范围 - PVDD:4.5V -26.4V - DVDD: 1.8V 或者 3.3V ● 静态功耗 - 37mA at PVDD12V ● 音频性能指标 - THDN ≤ 0.02% at 1W,1kHz - SNR ≥ 107dB (A-wei…

华为云Flexus+DeepSeek征文|DeepSeek-V3/R1商用服务体验全流程

华为云 Flexus 与 DeepSeek-V3/R1 的深度整合&#xff0c;构建了一套 “弹性算力 智能引擎” 的协同体系。 Flexus 系列云服务器基于柔性计算技术&#xff0c;通过动态资源调度&#xff08;如 Flexus X 实例&#xff09;实现 CPU / 内存的实时弹性分配&#xff0c;尤其适合大模…

C# NX二次开发-查找连续倒圆角面

在QQ群里有人问怎么通过一个选择一个倒圆角面来自动选中一组倒圆角面。 可以通过ufun函数 UF_MODL_ask_face_type 和 UF_MODL_ask_face_props 可判断处理选择相应的一组圆角面。 代码: Tag[] 查找连续倒圆角面(Tag faceTag) {theUf.Modl.AskFaceType(faceTag, out int typ…

今天遇到的bug

先呈现一下BUG现象。 这主要是一个传参问题&#xff0c;参数一直传不过去。后来我才发现&#xff0c;问题所在。 我们这里用的RquestBody接收参数&#xff0c;所有请求的参数需要用在body体中接收&#xff0c;但是我们用postman&#xff0c;用的是字符串查询方式传参&#x…

长安链智能合约命令解析(全集)

创建命令解析 ./cmc client contract user create \ --contract-namefact \ --runtime-typeWASMER \ --byte-code-path./testdata/claim-wasm-demo/rust-fact-2.0.0.wasm \ --version1.0 \ --sdk-conf-path./testdata/sdk_config.yml \ --admin-key-file-paths./testdata/cryp…

一、OpenCV的基本操作

目录 1、OpenCV的模块 2、OpenCV的基础操作 2.1图像的IO操作 2.2绘制几何图形 2.3获取并修改图像中的像素点 2.4 获取图像的属性 2.5图像通道的拆分与合并 2.6色彩空间的改变 3、OpenCV的算数操作 3.1图像的加法 3.2图像的混合 3.3总结 1、OpenCV的模块 2、OpenCV的基…

裂缝仪在线监测装置:工程安全领域的“实时守卫者”

在基础设施运维领域&#xff0c;裂缝扩展是威胁建筑结构安全的核心隐患之一。传统人工巡检方式存在效率低、时效性差、数据主观性强等局限&#xff0c;而裂缝仪在线监测装置通过技术迭代&#xff0c;实现了对结构裂缝的自动化、持续性追踪&#xff0c;为工程安全评估提供科学依…