SpringAIAlibaba学习使用 ---MCP
本文为学习记录文档,学习参考于三更草堂springAI视频
依旧田甜猫姐镇楼!!!!

MCP概述
为什么需要MCP?
在MCP出现之前,AI应用开发面临一个显著的效率瓶颈,常被称为“M×N”问题。这意味着,如果有M个不同的大模型(如GPT、Claude、文心一言等)需要与N种外部工具或数据源(如数据库、API、文件系统)进行交互,开发者就需要为每一种组合(M乘以N)编写特定的、通常不可复用的适配代码 这种点对点的集成方式导致了:
- 高昂的重复开发成本:每个新工具或新模型的引入都意味着大量的重复集成工作。
- 生态系统碎片化: 不同厂商的模型有不同的函数调用接口和规范,使得为一个模型开发的工具很难被其他模型直接使用。
- 复杂的维护负担: 当某个工具或模型的API发生变更时,所有与之相关的集成点都需要同步更新,维护成本非常高
什么是MCP?
MCP(Model Context Protocol,模型上下文协议)是Anthropic公司推出的开放协议,旨在标准化大语言模型与外部工具、数据源的交互方式。 官方文档:modelcontextprotocol.io/docs/learn/…
MCP相关概念
| 定义 | 解释 |
|---|---|
| MCP host【MCP主机】 | 使用mcp协议调用工具的应用程序。 例如claude code,我们自己写的spring ai应用等。它负责协调和管理一个或多个 MCP 客户端的 AI 应用程序。MCP 主机通过为每个 MCP 服务器创建一个 MCP 客户端来实现连接 |
| MCP client【MCP客户端】 | 与 MCP 服务器保持连接并从 MCP 服务器获取上下文,供 MCP 主机使用的组件 |
| MCP server 【MCP服务端】 | 给AI模型提供工具的服务 |

入门案例
目标:创建一个MCP Server去提供一个工具【这里是获取日期的工具】
1、工具代码
@Tool(description = "通过时区id获取当前时间")
public String getTimeByZoneId(@ToolParam(description = "时区id,比如 Asia/ShangHai") String zoneId) {
ZoneId zone = ZoneId.of(zoneId);
ZonedDateTime now = ZonedDateTime.now(zone);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return now.format(dateTimeFormatter);
}
然后使用MCP Client去获取这个MCP Server上的工具来提供给模型
2、创建MCP服务端
创建新工程后添加依赖
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
创建启动类
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class McpServerApplication {
public static void main(String[] args) {
SpringApplication.run(McpServerApplication.class, args);
}
}
定义工具类
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Component;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
@Component
public class TimeTools {
@Tool(description = "通过时区id获取当前时间")
public String getTimeByZoneId(@ToolParam(description = "时区id,比如 Asia/ShangHai") String zoneId) {
ZoneId zone = ZoneId.of(zoneId);
ZonedDateTime now = ZonedDateTime.now(zone);
DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
return now.format(dateTimeFormatter);
}
}
配置工具对外提供
import com.sangeng.tool.TimeTools;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class McpConfig {
@Bean
public ToolCallbackProvider weatherTools(TimeTools tools) {
return MethodToolCallbackProvider.builder()
.toolObjects(tools)
.build();
}
}
创建MCP客服端
配置文件
<!--mcp客户端依赖-->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-model-zhipuai</artifactId>
</dependency>
增加mcp服务端配置
# 服务器配置
server:
port: 8888
spring:
# 应用基本信息配置
application:
name: mcp-client # 应用名称
data:
redis:
host: 127.0.0.1
port: 6379
# Spring AI 配置
ai:
# 智谱AI大模型配置
zhipuai:
api-key: ************************* # 智谱API密钥(从环境变量ZHIPU_KEY获取)
chat:
options:
model: glm-4.6 # 使用的聊天模型名称(GLM-4.6)
embedding:
options:
model: embedding-3 # 使用的嵌入模型名称(embedding-3)
dimensions: 256 # 嵌入向量的维度(256维)
# 向量存储配置
vectorstore:
redis:
initialize-schema: true # 启动时自动创建Redis向量索引结构(首次部署需开启)
prefix: rag_prefix # Redis键名前缀,用于区分不同应用的向量数据
index: rag_index # Redis向量索引名称
mcp:
client:
sse:
connections:
server1:
url: http://localhost:8080 # mcp服务的url地址
fetcher-mcp:
url: http://localhost:3000
http:
client:
connect-timeout: 100000
配置工具信息到chatClient
private final VectorStore vectorStore;
private final ChatClient chatClient;
public CoffeeController(VectorStore vectorStore, ChatClient.Builder chatClientBuilder, ToolCallbackProvider toolCallbackProvider) {
this.vectorStore = vectorStore;
VectorStoreDocumentRetriever vectorStoreDocumentRetriever = VectorStoreDocumentRetriever.builder()
.vectorStore(vectorStore)
.topK(2)
.similarityThreshold(0.5)
.build();
RetrievalAugmentationAdvisor retrievalAugmentationAdvisor = RetrievalAugmentationAdvisor.builder()
.documentRetriever(vectorStoreDocumentRetriever)
.build();
this.chatClient = chatClientBuilder
.defaultAdvisors(retrievalAugmentationAdvisor)
.defaultToolCallbacks(toolCallbackProvider.getToolCallbacks())
.build();
}
网页信息爬取MCP
MCP地址: www.mcpworld.com/zh/detail/f…
docker部署mcp【任何部署方式都可以,docker比较简单】
docker-compose.yml:
version: '3.8'
services:
fetcher-mcp:
image: ghcr.io/jae-jae/fetcher-mcp:latest
container_name: fetcher-mcp
restart: unless-stopped
ports:
- '3000:3000'
environment:
- NODE_ENV=production
volumes:
- /tmp:/tmp
healthcheck:
test:
- CMD
- wget
- '--spider'
- '-q'
- http://localhost:3000
interval: 30s
timeout: 10s
retries: 3
使用 docker-compose up -d 启动
添加MCP服务端相关配置
# 服务器配置
server:
port: 8888
spring:
# 应用基本信息配置
application:
name: mcp-client # 应用名称
data:
redis:
host: 127.0.0.1
port: 6379
# Spring AI 配置
ai:
# 智谱AI大模型配置
zhipuai:
api-key: ************************* # 智谱API密钥(从环境变量ZHIPU_KEY获取)
chat:
options:
model: glm-4.6 # 使用的聊天模型名称(GLM-4.6)
embedding:
options:
model: embedding-3 # 使用的嵌入模型名称(embedding-3)
dimensions: 256 # 嵌入向量的维度(256维)
# 向量存储配置
vectorstore:
redis:
initialize-schema: true # 启动时自动创建Redis向量索引结构(首次部署需开启)
prefix: rag_prefix # Redis键名前缀,用于区分不同应用的向量数据
index: rag_index # Redis向量索引名称
mcp:
client:
sse:
connections:
server1:
url: http://localhost:8080 # mcp服务的url地址
fetcher-mcp:
url: http://localhost:3000 # mcp2服务的url地址
http:
client:
connect-timeout: 100000
controller编写
@GetMapping("/fetcher")
public String fetcher(@RequestParam("question") String question) {
return chatClient.prompt()
.system("你是一个网页爬取专家,你可以运用工具爬取指定网页的内容并且进行总结")
.user(question)
.call().content();
}
在调用时候可以通过断点看是否有用到配置的mcp
