现代 Web 应用正加速与大语言模型(LLMs)深度融合,构建超越传统问答场景的智能解决方案。为突破模型知识边界,增强上下文理解能力,开发者普遍采用多源数据集成策略,将 LLM 与搜索引擎、数据库、文件系统等外部资源互联。然而,异构数据源的协议差异与格式壁垒,往往导致集成复杂度激增,成为制约 AI 应用规模化落地的关键瓶颈。因此,Anthropic公司推出了模型上下文协议(Model Context Protocol, MCP),通过标准化接口为 AI 应用与外部数据源建立统一交互通道。这一协议体系不仅实现了数据获取与操作的规范化,更构建起可扩展的智能体开发框架,使开发者能够基于原生 LLM 能力快速构建复杂工作流。
本文我们就来尝试通过 Spring AI 框架来构建MCP 客户端 - 服务器架构的实现方法。
什么是MCP
关于MCP的架构,这里可以看看ByteByteGo的这张架构图:
MCP遵循客户端 - 服务器架构,围绕几个关键组件:
- • MCP Host:用户使用的应用程序,比如:Claude客户端、Cursor这样的AI应用程序,它与大语言模型集成,提供 AI 交互环境以访问不同工具和数据源。
- • MCP Client:与MCP Server建立并维护一对一连接的组件。它属于AI应用程序的内部组件,使其能够与 MCP Server通信。例如,若需要 PostgreSQL 数据,MCP 客户端会将请求格式化为结构化消息发送给 MCP 服务器。
- • MCP Server:外部数据源集成并公开与之交互功能的组件。作为中间件连接 AI 模型与外部系统(如 PostgreSQL、Google Drive 或 API)。例如,当 Claude 分析 PostgreSQL 中的销售数据时,PostgreSQL 的 MCP 服务器会充当 Claude 与数据库之间的连接器。
下面我们就参考Spring AI的官方文档,来尝试应用简单的MCP,想要了解更多,读者可以点击链接查看官方文档。
创建MCP Host
下面我们将使用Anthropic的Claude模型构建一个聊天机器人,该模型将充当我们的MCP Host。
引入相关依赖
首先,将必要的依赖项添加到项目的pom.xml
文件中:
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>
<repositories>
<repository>
<id>spring-milestones</id>
<name>Spring Milestones</name>
<url>https://repo.spring.io/milestone</url>
<snapshots>
<enabled>false</enabled>
</snapshots>
</repository>
</repositories>
- • 下面的案例使用Anthropic的Claude模型,所以使用
spring-ai-anthropic-spring-boot-starter
,如果你使用其他模型,也可以使用其他启动器依赖项,比如:使用deepseek的话也可以参考之前的《Spring AI + Ollama 实现 deepseek的API服务和调用》去引入相关链接和调用实现。 - •
spring-ai-mcp-client-spring-boot-starter
是引入MCP的重点,用来实现将Spring Boot应用程序与MCP服务器保持一对一连接的客户端。 - • 由于Spring AI M6是一个里程碑版本,所以增加了相关
repository
的配置
接下来,在application.yaml文件中配置调用大模型的密钥和模型名称:
yaml
spring:
ai:
anthropic:
api-key: ${ANTHROPIC_API_KEY}
chat:
options:
model: claude-3-7-sonnet-20250219
- • 使用
${}
属性占位符从环境变量中加载API密钥的值。 - • 模型使用
claude-3-7-sonnet-20250219
, 你也可以根据需要使用其他模型。
配置上述属性后,Spring AI会自动创建一个ChatModel类型的bean,使我们能够与指定的模型进行交互。
为Brave Search和文件系统服务器配置MCP Client
现在,让我们为两个预构建的MCP服务器实现(Brave Search和文件系统)配置MCP客户端。这些服务器将使我们的聊天机器人能够执行网络搜索和文件系统操作。
首先,在application.yaml
文件中为Brave Search MCP Server注册一个MCP Client:
yaml
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命令来下载并运行@modelcontextprotocol/server-brave-search
,并使用-y
标志自动确认所有安装提示。
接下来,为文件系统MCP Server配置一个MCP Client:
yaml
spring:
ai:
mcp:
client:
stdio:
connections:
filesystem:
command: npx
args:
- "-y"
- "@modelcontextprotocol/server-filesystem"
- "./"
与之前的配置类似,我们通过命令行参数启动文件系统MCP服务器。该配置允许机器人在指定目录执行文件创建、读写操作(默认当前目录,可通过参数扩展多目录)。Spring AI启动时会自动扫描配置,创建MCP客户端连接服务器,并生成包含所有可用工具的SyncMcpToolCallbackProvider
Bean。
构建简单的聊天机器人
配置好人工智能模型和MCP Client后,让我们构建一个简单的聊天机器人:
scss
@Bean
ChatClient chatClient(ChatModel chatModel, SyncMcpToolCallbackProvider toolCallbackProvider) {
return ChatClient
.builder(chatModel)
.defaultTools(toolCallbackProvider.getToolCallbacks())
.build();
}
我们首先使用ChatModel
和SyncMcpToolCallbackProvider
创建一个ChatClient
,它将作为我们与模型交互的主要入口点。
接下来,创建一个新的ChatbotService
类,chat()
方法将用户的问题传递给聊天客户端bean,并简单返回人工智能模型的响应。:
scss
String chat(String question) {
return chatClient
.prompt()
.user(question)
.call()
.content();
}
再创建一个Controller,暴露一个REST API来实现聊天的交互:
less
@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) {}
构建 MCP Server
除了使用预构建的MCP服务器外,我们还可以创建自己的MCP服务器,用我们的业务逻辑扩展聊天机器人的功能。下面我们创建一个新的Spring Boot应用程序来尝试构建一个简单的MCP Server
引入相关依赖
首先,在pom.xml文件中包含必要的依赖项:
xml
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-mcp-server-webmvc-spring-boot-starter</artifactId>
<version>1.0.0-M6</version>
</dependency>
定义并暴露自定义工具
接下来,定义一些我们的MCP服务器将暴露的自定义工具。
我们创建一个AuthorRepository
类,该类提供获取作者详细信息的方法:
typescript
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) {
}
}
这里使用@Tool
注解对两个方法进行注解,并为每个方法提供简要描述。该描述有助于人工智能模型根据用户输入决定是否调用以及何时调用这些工具,并将结果纳入其响应中。
为了演示,这里直接硬编码返回信息,在实际应用程序中,这些工具通常会与数据库或外部API进行交互。
接下来,向MCP Server注册我们的作者工具:
scss
@Bean
ToolCallbackProvider authorTools() {
return MethodToolCallbackProvider
.builder()
.toolObjects(new AuthorRepository())
.build();
}
我们使用MethodToolCallbackProvider从AuthorRepository
类中定义的工具创建一个ToolCallbackProvider
。应用程序启动时,用@Tool
注解的方法将作为MCP工具暴露出来。
构建 MCP Client
最后,为了在聊天机器人应用程序中使用我们的自定义MCP服务器,我们需要针对它配置一个MCP客户端:
yaml
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 Server集成,让我们与它进行交互并进行测试。
我们将使用HTTPie CLI调用聊天机器人的API端点:
ini
http POST :8080/chat question="How much was Elon Musk's initial offer to buy OpenAI in 2025?"
在这里,我们向聊天机器人发送一个关于大语言模型知识截止日期之后发生的事件的简单问题。让我们看看得到的响应是什么:
bash
{
"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服务器执行文件系统操作:
ini
http POST :8080/chat question="Create a text file named 'mcp-demo.txt' with content 'This is awesome!'."
我们指示聊天机器人创建一个名为mcp-demo.txt
的文件,并包含特定内容。让我们看看它是否能够完成请求:
json
{
"answer": "The text file named 'mcp-demo.txt' has been successfully created with the content you specified."
}
聊天机器人给出了成功的响应。我们可以验证文件是否在我们在application.yaml
文件中指定的目录中创建。
最后,让我们验证聊天机器人是否可以调用我们的自定义MCP服务器暴露的工具之一。我们将通过提及文章标题来询问作者详细信息:
ini
http POST :8080/chat question="Who wrote the article 'Testing CORS in Spring Boot?' on Baeldung, and how can I contact them?"
让我们调用API,看看聊天机器人的响应是否包含硬编码的作者详细信息:
less
{
"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()
工具获取了作者详细信息。
结论
在本文中,我们探索了模型上下文协议,并使用Spring AI实现了MCP的Client-Server架构,就从Client-Server这一侧其实也挺简单的吧,核心难的其实还是能力的提供方,也就是Server段能调用到多少能力,往往一些专业的能力是由专业软件提供的,这就需要对方有API的支持,然后通过MCP协议来调用。
最后,灵魂一问,你目前有在AI应用中使用MCP Server吗?把你觉得好用的MCP Server在评论推荐一波吧!