使用 Spring AI 探索模型上下文协议 (MCP)
最后更新:2025 年 12 月 17 日
1. 概述
现代 Web 应用程序越来越多地与 大型语言模型 (LLMs) 集成,以构建解决方案,这些解决方案不仅限于基于通用知识的问答。
为了增强 AI 模型的响应并使其更具上下文感知能力,我们可以将其连接到外部资源,例如搜索引擎、数据库和文件系统。但是,集成和管理具有不同格式和协议的多个数据源是一个挑战。
模型上下文协议 (MCP) 由 Anthropic 引入,解决了这个集成挑战,并提供了一种标准化的方式来将 AI 驱动的应用程序与外部数据源连接起来。通过 MCP,我们可以在原生 LLM 之上构建复杂的代理和工作流程。
在本教程中,我们将通过使用 Spring AI 实际实现其客户端-服务器架构来理解 MCP 的概念。我们将创建一个简单的聊天机器人,并通过 MCP 服务器扩展其功能,以执行 Web 搜索、执行文件系统操作和访问自定义业务逻辑。
2. 模型上下文协议 101
在深入实现之前,让我们更详细地了解 MCP 及其各个组件
MCP 遵循客户端-服务器架构,围绕几个关键组件展开
- MCP Host:是我们的主应用程序,它与 LLM 集成,并需要它连接到外部数据源
- MCP Clients:是建立并维护与 MCP 服务器 1:1 连接的组件
- MCP Servers:是与外部数据源集成的组件,并暴露功能以与之交互
- Tools:指的是 MCP 服务器暴露给客户端调用的可执行函数/方法
此外,为了处理客户端和服务器之间的通信,MCP 提供了两个传输通道。
为了通过标准输入和输出流与本地进程和命令行工具实现通信,它提供了标准输入/输出 (stdio) 传输类型。或者,对于客户端和服务器之间的基于 HTTP 的通信,它提供了服务器发送事件 (SSE) 传输类型。
MCP 是一个复杂而广泛的主题,请参考 官方文档 以了解更多信息。
3. 创建 MCP Host
现在我们对 MCP 有了高级了解,让我们开始实际实现 MCP 架构。
我们将使用 Anthropic 的 Claude 模型构建一个聊天机器人,它将充当我们的 MCP host。或者,我们可以通过 Hugging Face 或 Ollama 使用本地 LLM,因为具体的 AI 模型对于此演示来说无关紧要。
3.1. 依赖项
让我们从向项目的 pom.xml 文件添加必要的依赖项开始
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-anthropic</artifactId>
<version>1.0.1</version>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client</artifactId>
<version>1.0.1</version>
</dependency>
Anthropic starter 依赖项 是围绕 Anthropic Message API 的包装器,我们将使用它在我们的应用程序中与 Claude 模型进行交互。
此外,我们导入了 MCP 客户端启动依赖,这将允许我们在 Spring Boot 应用程序中配置客户端,这些客户端与 MCP 服务器保持 1:1 的连接。
鉴于我们正在项目中使用了多个 Spring AI 启动器,让我们也在 pom.xml 中包含 Spring AI 物料清单 (BOM)。
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-bom</artifactId>
<version>1.0.1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
有了这个补充,我们现在可以从我们的两个启动依赖中删除 version 标签。BOM 消除了版本冲突的风险,并确保我们的 Spring AI 依赖项相互兼容。
接下来,让我们在 application.yaml 文件中配置我们的 Anthropic API 密钥和聊天模型。
spring:
ai:
anthropic:
api-key: ${ANTHROPIC_API_KEY}
chat:
options:
model: claude-opus-4-20250514
我们使用 ${} 属性占位符从 环境变量 加载 API 密钥的值。
此外,我们指定 Anthropic 的 Claude 4 Opus,使用 claude-opus-4-20250514 模型 ID。可以根据需求探索和使用 不同的模型。
在配置以上属性后,Spring AI 会自动创建一个类型为 ChatModel 的 bean,从而使我们能够与指定的模型进行交互。
3.2. 为 Brave Search 和 Filesystem 服务器配置 MCP 客户端
现在,让我们为两个预构建的 MCP 服务器实现配置 MCP 客户端:Brave Search 和 Filesystem。这些服务器将使我们的聊天机器人能够执行网络搜索和文件系统操作。
让我们从在 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 传输的 client。我们指定 npx command 来下载并运行基于 TypeScript 的 @modelcontextprotocol/server-brave-search 包,并使用 -y 标志确认所有安装提示。
此外,我们提供 BRAVE_API_KEY 作为环境变量。
接下来,让我们配置 Filesystem MCP 服务器的 MCP 客户端
spring:
ai:
mcp:
client:
stdio:
connections:
filesystem:
command: npx
args:
- "-y"
- "@modelcontextprotocol/server-filesystem"
- "./"
与之前的配置类似,我们指定运行 Filesystem MCP 服务器包 所需的 command 和参数。此设置允许我们的聊天机器人执行诸如在指定目录中创建、读取和写入文件的操作。
这里,我们仅配置当前目录 (./) 用于文件系统操作,但是,我们可以通过将它们添加到 args 列表中来指定多个目录。
在应用程序启动期间,Spring AI 将扫描我们的配置,创建 MCP 客户端,并与其相应的 MCP 服务器建立连接。它还会创建一个类型为 SyncMcpToolCallbackProvider 的 bean,该 bean 提供所有由配置的 MCP 服务器公开的工具列表。
3.3. 构建一个基本的聊天机器人
在配置了我们的 AI 模型和 MCP 客户端之后,让我们构建一个简单的聊天机器人
@Bean
ChatClient chatClient(ChatModel chatModel, SyncMcpToolCallbackProvider toolCallbackProvider) {
return ChatClient
.builder(chatModel)
.defaultToolCallbacks(toolCallbackProvider.getToolCallbacks())
.build();
}
我们首先使用 ChatModel 和 SyncMcpToolCallbackProvider bean 创建一个类型为 ChatClient 的 bean。ChatClient 类将作为我们与聊天完成模型(即 Claude 4 Opus)交互的主要入口点。
接下来,让我们注入 ChatClient bean 以创建一个新的 ChatbotService 类
String chat(String question) {
return chatClient
.prompt()
.user(question)
.call()
.content();
}
我们创建一个 chat() 方法,其中我们将用户的 question 传递给 chat client 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-starter-mcp-server-webmvc</artifactId>
<version>1.0.0</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", "[email protected]");
}
@Tool(description = "Get highest rated Baeldung authors")
List<Author> getTopAuthors() {
return List.of(
new Author("John Doe", "[email protected]"),
new Author("Jane Doe", "[email protected]")
);
}
record Author(String name, String email) {
}
}
对于我们的演示,我们返回硬编码的作者详细信息,但在实际应用程序中,这些工具通常会与数据库或外部 API 交互。
我们使用 @Tool 注解标注我们的两个方法,并为每个方法提供一个简短的 description 。description 帮助 AI 模型决定何时调用工具,并根据用户输入将结果合并到其响应中。
接下来,让我们将我们的作者工具注册到 MCP 服务器
@Bean
ToolCallbackProvider authorTools() {
return MethodToolCallbackProvider
.builder()
.toolObjects(new AuthorRepository())
.build();
}
我们使用 MethodToolCallbackProvider 从 AuthorRepository 类中定义的工具创建 ToolCallbackProvider bean。带有 @Tool 注解的方法将在应用程序启动时作为 MCP 工具公开。
或者,我们可以根据特定条件在运行时动态注册工具
@Bean
CommandLineRunner commandLineRunner(
McpSyncServer mcpSyncServer,
@Value("${com.baeldung.author-tools.enabled:false}") boolean authorToolsEnabled
) {
return args -> {
if (authorToolsEnabled) {
ToolCallback[] toolCallbacks = ToolCallbacks.from(new AuthorRepository());
List<SyncToolSpecification> tools = McpToolUtils.toSyncToolSpecifications(toolCallbacks);
tools.forEach(tool -> {
mcpSyncServer.addTool(tool);
mcpSyncServer.notifyToolsListChanged();
});
}
};
}
这里,我们注入 Spring AI 自动创建的 McpSyncServer bean,以根据配置属性有条件地注册我们的工具。与 addTool() 类似,McpSyncServer 类还提供了 removeTool() 方法来删除某些工具。
对于我们的演示,我们使用的是 CommandLineRunner 接口;但是,我们可以在调用 REST API 时或响应应用程序事件时添加/删除工具。这对于根据用户权限、订阅层级或其他业务逻辑启用或禁用功能而言,尤其 有用。
4.3. 配置自定义 MCP 服务器的 MCP 客户端
最后,为了在我们的聊天机器人应用程序中使用我们的自定义 MCP 服务器,我们需要配置一个针对它的 MCP 客户端
spring:
ai:
mcp:
client:
sse:
connections:
author-tools-server:
url: https://:8081
在 application.yaml 文件中,我们配置针对我们自定义 MCP 服务器的新客户端。请注意,我们在这里使用 SSE 传输类型。
此配置假定 MCP 服务器正在 https://:8081 运行。如果它在不同的主机或端口上运行,我们需要确保更新 url。
此外,如果我们启用了 MCP 服务器在运行时动态添加或删除工具,我们可以注册一个侦听器来检测这些工具的更改
@Bean
McpSyncClientCustomizer mcpSyncClientCustomizer() {
return (name, mcpClientSpec) -> {
mcpClientSpec.toolsChangeConsumer(tools -> {
logger.info("Detected tools changes.");
});
};
}
这里,我们定义一个 McpSyncClientCustomizer 类型的 bean,并使用 toolsChangeConsumer() 方法注册一个侦听器。虽然我们为了简单起见而只是在这里进行记录,但在实际应用程序中,我们可以 刷新 ChatClient bean 或 以编程方式重新启动 我们的应用程序。
有了这个配置,我们的 MCP 客户端现在可以调用我们的自定义服务器公开的工具,以及 Brave Search 和 Filesystem 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 服务器执行网络搜索,并提供准确的答案以及来源。
接下来,让我们验证聊天机器人是否可以使用文件系统 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 [[email protected]](mailto:[email protected])."
}
以上响应验证了聊天机器人使用我们自定义 MCP 服务器暴露的 getAuthorByArticleTitle() 工具来获取作者详细信息。
我们强烈建议在本地设置代码库,并使用不同的提示语与聊天机器人进行试验。
6. 结论
在本文中,我们探讨了模型上下文协议并使用 Spring AI 实现了其客户端-服务器架构。
首先,我们使用 Anthropic 的 Claude 4 Opus 模型构建了一个简单的聊天机器人,作为我们的 MCP 主机。
然后,为了为我们的聊天机器人提供网络搜索能力并使其能够执行文件系统操作,我们针对 Brave Search API 和文件系统的预构建 MCP 服务器实现配置了 MCP 客户端。
最后,我们创建了一个自定义 MCP 服务器,并在我们的 MCP 主机应用程序中配置了其相应的 MCP 客户端。
支持本文的代码可在 GitHub 上获取。 一旦你以 Baeldung Pro 会员 身份登录,就开始学习并在项目上进行编码。















