github MCP学习指南:https://github.com/yzfly/Awesome-MCP-ZH
MCP 能干什么?
MCP 能让 AI 从“嘴炮王”变成“实干家”,以下是几个例子:
连工具:用 Slack 发消息、用 GitHub 管代码、用 Blender 建 3D 模型。
查数据:直接看你电脑文件、数据库记录,甚至网上实时信息。
干复杂活儿:写网页时,AI 能查代码、生成图片、调试页面,一条龙搞定。
人机协作:AI 干一半问你意见,你点头它再继续。
例子:在 Cursor 里装个 Slack MCP 服务器,AI 能一边写代码一边发消息通知团队,超省事!
MCP服务端支持功能清单:
1、MCP客户端接入
什么是MCP:把 AI 想象成一个非常聪明的助手,但它只能在自己的房间里工作。MCP 服务集成就像给它安装了电话、网络和各种工具,让它能够:
📞 调用外部服务(如地图、天气)
💻 访问你的本地文件
🔧 执行各种实用工具
MCP (Model Context Protocol) 让 AI 具备了与外部世界交互的能力。PIG AI 支持两种集成模式:
1.SSE模式:连接云端服务
什么是 SSE 模式?
SSE (Server-Sent Events) 模式就像给 AI 接入了互联网。通过一个网址,AI 就能访问各种在线服务,比如:
🗺️ 百度地图:查地址、规划路线
🌤️ 天气服务:获取实时天气
📊 数据服务:查询股票、汇率等
简单理解:你提供一个服务网址,AI 就能调用这个服务的所有功能!

2.本地模式:让AI访问你的电脑

什么是本地模式?
本地模式就像给 AI 装了一个"机器人手臂",让它能够:
📁 读取和编辑你电脑上的文件
🔍 搜索本地文档内容
⚙️ 运行你电脑上的工具和命令
📊 分析本地数据文件
本地 (STDIO) 模式通过标准输入/输出协议,让 AI 运行你电脑上的命令行工具。
环境工具介绍
Node.js 工具
像一个"临时工具箱",需要什么工具就临时下载使用,用完就删除。
适用场景:运行各种 Node.js 的 MCP 工具
安装方式:
访问 Node.js 官网
下载并安装 Node.js (v18+)
安装完成后就可以使用
npx命令了
Python 工具
超快速的 Python 包管理器,比传统的 pip 更快更好用。
适用场景:运行各种 Python 的 MCP 工具
安装方式:参考 官方安装文档
3.实现原理和流程解析
1)新增MCP客户端服务
包含服务名称、描述、类型(SSE、STEAMABLE、STDIO),是否启用
SSE
包含SSE地址、请求头参数配置
STDIO
包含使用命令(uvx、npx、java、docker)、执行参数、环境变量
2)对话聊天
聊天实现流程同RAG知识库,只是在处理聊天请求时通过datasetId匹配MCP对应策略模式,采用的是McpChatRule规则
/**
* 处理MCP聊天请求
* <p>
* 主要流程: 1. 如果用户未指定MCP,通过向量搜索自动选择 2. 获取MCP配置并创建或获取MCP客户端 3. 使用MCP工具提供者构建助手服务 4.使用模板处理用户输入并返回流式响应
* @param chatMessageDTO 聊天上下文信息
* @return AI响应结果流
*/
@Override
public Flux<AiMessageResultDTO> process(ChatMessageDTO chatMessageDTO) {
List<Long> mcpIdList = new ArrayList<>();
// 如果用户未提供MCP,则自动选择
if (Objects.isNull(chatMessageDTO.getExtDetails())
|| StrUtil.isBlank(chatMessageDTO.getExtDetails().getMcpId())) {
mcpIdList = autoChoice(chatMessageDTO);
if (CollUtil.isEmpty(mcpIdList)) {
return Flux.just(new AiMessageResultDTO("未找到相关MCP配置,请点击下方+按钮选择目标MCP"));
}
}
else {
// 如果用户提供了MCP ID,则直接使用
mcpIdList.add(Long.parseLong(chatMessageDTO.getExtDetails().getMcpId()));
}
// 获取MCP配置
List<AiMcpConfigEntity> mcpConfigEntityList = mcpConfigMapper
.selectByIds(mcpIdList.stream().distinct().toList());
// 通过McpClientProvider获取或创建MCP客户端
List<McpClient> mcpClientList = mcpConfigEntityList.stream()
.map(mcpClientProvider::getOrCreateMcpClient)
.filter(Objects::nonNull)
.toList();
// 使用MCP客户端设置工具提供者
ToolProvider toolProvider = McpToolProvider.builder().mcpClients(mcpClientList).build();
// 根据请求的模型名称获取AI模型和助手服务
Pair<StreamingChatModel, AiStreamAssistantService> servicePair = modelProvider
.getAiStreamAssistant(chatMessageDTO.getModelName());
// 使用工具提供者构建助手服务
AiNoMemoryStreamAssistantService assistant = AiServices.builder(AiNoMemoryStreamAssistantService.class)
.streamingChatModel(servicePair.getKey())
.toolProvider(toolProvider)
.build();
// 使用模板处理聊天并返回响应流
Map<String, Object> promptData = Map.of("mcpName",
mcpClientList.stream().map(McpClient::key).collect(Collectors.joining(StrUtil.COMMA)), "inputMessage",
chatMessageDTO.getContent(), "accessToken", SecurityUtils.getToken(), systemTime, DateUtil.now());
TokenStream tokenStream = assistant.chatTokenStream(PromptBuilder.render("mcp.st", promptData));
return Flux.create(fluxSink -> {
tokenStream.beforeToolExecution(beforeToolExecution -> {
AiMessageResultDTO.ToolInfo toolInfo = new AiMessageResultDTO.ToolInfo();
toolInfo.setName(beforeToolExecution.request().name());
toolInfo.setParams(beforeToolExecution.request().arguments());
AiMessageResultDTO aiMessageResultDTO = new AiMessageResultDTO();
aiMessageResultDTO.setToolInfo(toolInfo);
fluxSink.next(aiMessageResultDTO);
})
.onPartialResponse(message -> fluxSink.next(new AiMessageResultDTO(message)))
.onCompleteResponse(chatResponse -> fluxSink.complete())
.onError(fluxSink::error)
.start();
});
}创建mcp客户端实例(MCP 本质是一个 工具集协议:客户端通过它可以发现、调用远程工具):
/**
* 创建MCP客户端实例
* <p>
* 根据配置的通信类型(SSE或STDIO)创建对应的传输器和客户端
* @param mcpConfig MCP配置信息
* @return MCP客户端实例
*/
private McpClient createMcpClient(AiMcpConfigEntity mcpConfig) {
// 根据MCP类型创建适当的传输器
McpTransport transport;
if (McpTypeEnums.SSE.getType().equals(mcpConfig.getMcpType())) {
transport = createHttpTransport(mcpConfig);
}
else if (McpTypeEnums.STEAMABLE.getType().equals(mcpConfig.getMcpType())) {
transport = createStreamableTransport(mcpConfig);
}
else {
transport = createStdioTransport(mcpConfig);
}
// 配置并构建MCP客户端
try {
return new DefaultMcpClient.Builder().transport(transport)
.logHandler(new DefaultMcpLogMessageHandler())
.build();
}
catch (Exception e) {
log.error("创建MCP客户端失败: {}, 错误信息: {}", mcpConfig.getName(), e.getMessage(), e);
return null;
}
}核心流程:
从数据库或配置中拿 MCP 配置。
通过封装类
McpClientProvider创建/获取McpClient,MCP 客户端是一个连接器,它知道如何和外部 MCP 服务交互用
McpToolProvider把 MCP 客户端包装成ToolProvider。McpToolProvider会把多个McpClient聚合到一起,形成统一的ToolProvider,告诉 LangChain4j:哪些工具可用,怎么调用结合 LangChain4j 的
StreamingChatModel创建 Assistant。LangChain4j 提供的AiServices机制,可以把模型和工具挂在一起,选定参数(StreamingChatModel使用的模型、toolProvider服务提供方、AssistantService无记忆聊天助手)使用 Prompt 模板触发对话,流式处理响应。模板会告诉AI用户的输入、可用mcp工具、系统上下文信息。接着流式输出:
tokenStream .beforeToolExecution(req -> { ... }) // 调用 MCP 工具前的事件(可记录日志、展示 UI) .onPartialResponse(msg -> { ... }) // 流式响应片段(边生成边输出) .onCompleteResponse(resp -> { ... })// AI 完成回答 .onError(err -> { ... }) // 异常处理 .start();
2、MCP服务端开发

MCP服务端开发:将现有的业务接口包装成 MCP 服务,让 AI 能够调用你的接口,通过自然语言让 AI 帮你查询业务数据
掌握了这个方法,你可以将任何业务接口都包装成 MCP 服务: • 用户管理:让 AI 帮你查询用户信息、重置密码等 • 订单系统:通过自然语言查询订单状态、统计数据 • 库存管理:询问库存数量、预警信息等 • 财务报表:生成各种维度的财务分析报告 • 日志分析:智能检索和分析系统日志
1.业务接口自动转mcp原理
在 MCP 协议下,服务端的职责是:提供一组工具 (Tools),供客户端调用。 这些工具其实就是通过 @Tool 注解方法,MCP 框架会扫描并注册这些方法,让它们能被 AI/客户端动态发现并调用。
1)配置加载
@PropertySource(value = "classpath:mcp-config.yaml", factory = YamlPropertySourceFactory.class)
@Configuration(proxyBeanMethods = false)
@Import(ToolAutoRegister.class)
public class PigxAiMcpAutoConfiguration {
@Bean
public PigxSecurityToolAspect toolAspect() {
return new PigxSecurityToolAspect();
}
}
@PropertySource+YamlPropertySourceFactory加载mcp-config.yaml,用来配置 MCP 服务端相关参数(比如mcp服务端名称、版本号,同步/异步调用、描述、sse-endpoint主通道地址用来建立sse长连接,sse-message-endpoint消息推送的接口地址、能力声明、基础访问路径base-url)。
@Configuration(proxyBeanMethods = false)声明配置类,不用代理方法(减少 Spring CGLIB 开销)。
@Import(ToolAutoRegister.class)把 工具自动注册逻辑(ToolAutoRegister)导入 Spring 容器。
2)工具自动注册器
MCP工具自动配置类:自动扫描并注册带有@Tool注解的方法
public class ToolAutoRegister implements BeanPostProcessor, ApplicationContextAware {
@Bean("controllerToolCallbackProvider")
public ToolCallbackProvider controllerToolCallbackProvider() {
List<Object> toolObjects = new ArrayList<>();
String[] restBeanNames = applicationContext.getBeanNamesForAnnotation(RestController.class);
for (String beanName : restBeanNames) {
Object bean = applicationContext.getBean(beanName);
Class<?> clazz = AopUtils.getTargetClass(bean);
boolean match = Arrays.stream(clazz.getDeclaredMethods())
.anyMatch(method -> method.isAnnotationPresent(Tool.class));
if (match) {
toolObjects.add(bean);
}
}
return MethodToolCallbackProvider.builder().toolObjects(toolObjects.toArray()).build();
}
}
扫描所有
@RestControllerBean。判断里面是否存在带
@Tool注解的方法。如果有,就把整个 Bean 交给
MethodToolCallbackProvider。
MethodToolCallbackProvider会基于反射把这些方法注册成 MCP 工具(ToolCallback),暴露给客户端。👉 这样,客户端通过 MCP 协议调用工具时,就能动态路由到这些方法
ApplicationContextAware:获取应用上下文,让一个 bean 拿到 Spring 容器的引用,这里是从容器里找出所有 ControllerBeanPostProcessor:在 Spring 容器创建 bean 的生命周期中,提供两个“钩子”方法,让 bean 初始化前后做增强或替换,这里是在 bean 初始化阶段扫描@Tool注解,收集工具方法。最后注册成SpringAI的 ToolCallbackProvider → 作为提供者让 MCP 框架知道有哪些工具能对外暴露
3)权限切面拦截
@Slf4j
@Aspect
@RequiredArgsConstructor
public class PigxSecurityToolAspect implements Ordered {
@SneakyThrows
@Around("@annotation(tool)")
public Object around(ProceedingJoinPoint pjp, Tool tool) {
MethodSignature signature = (MethodSignature) pjp.getSignature();
Method method = signature.getMethod();
HasPermission annotation = method.getAnnotation(HasPermission.class);
if (Objects.nonNull(annotation)) {
McpContextHolder.setAnnotation(annotation);
}
try {
return pjp.proceed(); // 执行工具方法
} finally {
McpContextHolder.clear();
}
}
@Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE + 1;
}
}
@Around("@annotation(tool)"):拦截所有带@Tool的方法。如果方法上还加了
@HasPermission,就存到McpContextHolder(ThreadLocal 里)。执行完方法后清理上下文,避免线程污染。
👉 这样,调用 MCP 工具时可以自动做权限校验。
4)上下文管理器
@UtilityClass
public class McpContextHolder {
private final ThreadLocal<HasPermission> THREAD_LOCAL = new TransmittableThreadLocal<>();
public void setAnnotation(HasPermission annotation) {
THREAD_LOCAL.set(annotation);
}
public HasPermission getAnnotation() {
return THREAD_LOCAL.get();
}
public void clear() {
THREAD_LOCAL.remove();
}
}
ThreadLocal保存每次工具调用时的权限注解(HasPermission)。
结合
PigxSecurityToolAspect,保证在一个请求上下文内,工具能知道自己需要什么权限。
用
TransmittableThreadLocal,确保线程池环境下也能传递。