SpringAI(GA):Nacos2下的分布式MCP
原文链接地址:SpringAI(GA):Nacos2下的分布式MCP
教程说明
说明:本教程将采用2025年5月20日正式的GA版,给出如下内容
- 核心功能模块的快速上手教程
- 核心功能模块的源码级解读
- Spring ai alibaba增强的快速上手教程 + 源码级解读
版本:JDK21 + SpringBoot3.4.5 + SpringAI 1.0.0 + SpringAI Alibaba 1.0.0.2
将陆续完成如下章节教程。本章是第七章(MCP使用范式)下的Nacos2下的分布式MCP快速上手
代码开源如下:https://github.com/GTyingzi/spring-ai-tutorial
微信推文往届解读可参考:
第一章内容
SpringAI(GA)的chat:快速上手+自动注入源码解读
SpringAI(GA):ChatClient调用链路解读
第二章内容
SpringAI的Advisor:快速上手+源码解读
SpringAI(GA):Sqlite、Mysql、Redis消息存储快速上手
第三章内容
SpringAI(GA):Tool工具整合—快速上手
SpringAI(GA):Tool源码+工具触发链路解读
第五章内容
SpringAI(GA):内存、Redis、ES的向量数据库存储—快速上手
SpringAI(GA):向量数据库理论源码解读+Redis、Es接入源码
第六章内容
SpringAI(GA):RAG快速上手+模块化解读
SpringAI(GA):RAG下的ETL快速上手
SpringAI(GA):RAG下的ETL源码解读
整理不易,获取更好的观赏体验,可付费获取飞书云文档Spring AI最新教程权限,目前49.9,随着内容不断完善,会逐步涨价。
注:M6版快速上手教程+源码解读飞书云文档已免费提供
为鼓励大家积极参与为Spring Ai Alibaba开源社区:https://github.com/alibaba/spring-ai-alibaba/tree/main,为AI工程贡献力量,解决三个有效issue或提交一个有价值的PR,可免费获得当前SpringAI最新教程的飞书在线版
分布式 MCP
[!TIP]
背景:现阶段 MCP Client 和 MCP Server 是一对一的连接方式,若当前 MCP Server 挂掉了,那么 MCP Client 便不能使用 MCP Server 提供的工具能力。工具稳定性的提供得不到保证
解决:做了一些分布式 Client 连接的探索,一个 MCP Client 端可以连接多个 MCP Server(分布式部署),目前采用的方案如下:
- 新建一个包含服务名和对应连接的类
- 另外实现监听机制,可以动态的应对 MCP Server 节点上下线,去动态调整 mcpAsyncClientList
- (读操作)获取 MCP Server 相关信息的,采用从 mcpAsyncClientList 列表中随机中获取一个去发起请求,比如获取工具列表信息
- (写操作)对应 MCP Server 需要更改的信息,由 MCP Client 端发起,需要修改所有的 MCP Server
本篇是基于 Nacos2 的快速上手篇,基于 Nacos3 的可见 《Nacos3 的 MCP 分布式》
实战代码可见:https://github.com/GTyingzi/spring-ai-tutorial 下的 mcp 目录下的 mcp-nacos2-server、mcp-nacos2-client 模块
Nacos 准备
选择 Nacos2.*版本,新建一个命名空间,记住此时的命名空间 ID:“9ba5f1aa-b37d-493b-9057-72918a40ef35”
- Nacos 启动可见:Nacos
mcp-nacos2-server
pom 文件
导入 nacos2-mcp-server 的依赖
- 说明:目前 1.0.0.2 版本遗留了 bug,不支持填写命名空间 ID,1.0.0.3-SNAPSHOT 进行了修复
<properties><!-- Spring AI Alibaba --><spring-ai-alibaba.version>1.0.0.3-SNAPSHOT</spring-ai-alibaba.version>
</properties><dependencies><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-nacos2-mcp-server</artifactId></dependency><!-- MCP Server WebFlux 支持(也可换成 WebMvc) --><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-server-webflux</artifactId></dependency></dependencies>
application.yml
主要关注 spring.ai.alibaba.mcp.nacos 下的配置信息
server:port: 21000spring:main:banner-mode: offapplication:name: mcp-nacos2-serverai:mcp:server:name: webflux-mcp-serverversion: 1.0.0type: ASYNC # Recommended for reactive applicationsinstructions: "This reactive server provides time information tools and resources"sse-message-endpoint: /mcp/messagescapabilities:tool: trueresource: trueprompt: truecompletion: truealibaba:mcp:nacos:enabled: trueserver-addr: 127.0.0.1:8848username: nacospassword: nacosregistry:enabled: trueservice-namespace: 9ba5f1aa-b37d-493b-9057-72918a40ef35service-group: mcp-server
TimeService
提供一个时间工具服务
package com.spring.ai.tutorial.mcp.server.service;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ai.tool.annotation.Tool;
import org.springframework.ai.tool.annotation.ToolParam;
import org.springframework.stereotype.Service;import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;@Service
public class TimeService {private static final Logger logger = LoggerFactory.getLogger(TimeService.class);@Tool(description = "Get the time of a specified city.")public String getCityTimeMethod(@ToolParam(description = "Time zone id, such as Asia/Shanghai") String timeZoneId) {logger.info("The current time zone is {}", timeZoneId);return String.format("The current time zone is %s and the current time is " + "%s", timeZoneId,getTimeByZoneId(timeZoneId));}private String getTimeByZoneId(String zoneId) {// Get the time zone using ZoneIdZoneId zid = ZoneId.of(zoneId);// Get the current time in this time zoneZonedDateTime zonedDateTime = ZonedDateTime.now(zid);// Defining a formatterDateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss z");// Format ZonedDateTime as a stringString formattedDateTime = zonedDateTime.format(formatter);return formattedDateTime;}
}
Nacos2ServerApplication
package com.spring.ai.tutorial.mcp.server;import com.spring.ai.tutorial.mcp.server.service.TimeService;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.ai.tool.method.MethodToolCallbackProvider;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;@SpringBootApplication
public class Nacos2ServerApplication {public static void main(String[] args) {SpringApplication.run(Nacos2ServerApplication.class, args);}@Beanpublic ToolCallbackProvider timeTools(TimeService timeService) {return MethodToolCallbackProvider.builder().toolObjects(timeService).build();}
}
效果
我分别以 21000、21001 启动两个实例服务,对外统一暴露为“webflux-mcp-server”
在 nacos 中能找到服务名“webflux-mcp-server”+“-mcp-service”(默认填充的后缀规则),我们能发现此时已有两个实例
在配置管理处,也能找到我们的 mcp server、tool 的配置信息
这是 mcp server 信息
这是 tool 配置信息
mcp-nacos2-client
pom 文件
<properties><!-- Spring AI Alibaba --><spring-ai-alibaba.version>1.0.0.3-SNAPSHOT</spring-ai-alibaba.version>
</properties><dependencies><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-autoconfigure-model-openai</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-autoconfigure-model-chat-client</artifactId></dependency><dependency><groupId>com.alibaba.cloud.ai</groupId><artifactId>spring-ai-alibaba-starter-nacos2-mcp-client</artifactId></dependency><dependency><groupId>org.springframework.ai</groupId><artifactId>spring-ai-starter-mcp-client-webflux</artifactId></dependency></dependencies>
application.yml
主要关注如下配置:
nacos-enabled: true
:启动基于 Nacos 的分布式连接service-namespace
:若不填,则默认 publicserver1: webflux-mcp-server
:填 mcp server 的名称即可
server:port: 121100spring:application:name: mcp-nacos2-clientmain:web-application-type: noneai:openai:api-key: ${DASHSCOPEAPIKEY}base-url: https://dashscope.aliyuncs.com/compatible-modechat:options:model: qwen-maxmcp:client:enabled: truename: my-mcp-clientversion: 1.0.0request-timeout: 30stype: ASYNC # or ASYNC for reactive applicationsnacos-enabled: truealibaba:mcp:nacos:enabled: trueserver-addr: 127.0.0.1:8848username: nacospassword: nacosregistry:service-namespace: 9ba5f1aa-b37d-493b-9057-72918a40ef35service-group: mcp-serverclient:sse:connections:server1: webflux-mcp-server
Nacos2ClientApplication
- 排除掉自动注入类是用来动态加载第三方 restful 服务提供的工具《动态加载服务》目前我们这里没有第三方 restful,故注释掉
- 注入 loadbalancedMcpAsyncToolCallbacks 的 Bean
package com.spring.ai.tutorial.mcp.client;import com.alibaba.cloud.ai.autoconfigure.mcp.server.Nacos2DynamicMcpServerAutoConfiguration;
import org.springframework.ai.chat.client.ChatClient;
import org.springframework.ai.tool.ToolCallbackProvider;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;import java.util.Scanner;@SpringBootApplication(exclude = Nacos2DynamicMcpServerAutoConfiguration.class)
public class Nacos2ClientApplication {public static void main(String[] args) {SpringApplication.run(Nacos2ClientApplication.class, args);}@Beanpublic CommandLineRunner predefinedQuestions(ChatClient.Builder chatClientBuilder, @Qualifier("loadbalancedMcpAsyncToolCallbacks") ToolCallbackProvider tools,ConfigurableApplicationContext context) {return args -> {var chatClient = chatClientBuilder.defaultToolCallbacks(tools).build();Scanner scanner = new Scanner(System.in);while (true) {System.out.print("\n>>> QUESTION: ");String userInput = scanner.nextLine();if (userInput.equalsIgnoreCase("exit")) {break;}if (userInput.isEmpty()) {userInput = "北京时间现在几点钟";}System.out.println("\n>>> ASSISTANT: " + chatClient.prompt(userInput).call().content());}scanner.close();context.close();};}
}
效果
MCP Client 端先后触发两次工具请求
第一次工具由 MCP Server21000 端口进行处理
第二次工具由 MCP Server21001 端口进行处理
学习交流圈
你好,我是影子,曾先后在🐻、新能源、老铁就职,现在是一名AI研发工程师,同时作为Spring AI Alibaba开源社区的Committer,另外,本人长期维护一套飞书云文档笔记,涵盖后端、大数据系统化的面试资料,可私信免费获取
相关文章:

SpringAI(GA):Nacos2下的分布式MCP
原文链接地址:SpringAI(GA):Nacos2下的分布式MCP 教程说明 说明:本教程将采用2025年5月20日正式的GA版,给出如下内容 核心功能模块的快速上手教程核心功能模块的源码级解读Spring ai alibaba增强的快速上手教程 源码级解读 版…...
AC68U刷梅林384/386版本后不能 降级回380,升降级解决办法
前些时间手贱更新了路由器的固件,384.18版本。结果发现了一堆问题,比如客户端列表加载不出来,软件中心打不开等等。想着再刷一下新的固件,结果死活刷不上去。最后翻阅了大量前辈的帖子找到了相关的处理办法。现在路由器中开启SSH&…...

[AI绘画]sd学习记录(二)文生图参数进阶
目录 7.高分辨率修复:以小博大8.细化器(Refiner):两模型接力9.随机数种子(Seed):复现图片吧 本文接续https://blog.csdn.net/qq_23220445/article/details/148460878?spm1001.2014.3001.5501…...

CRM管理系统中的客户分类与标签管理技巧:提升转化率的核心策略
在客户关系管理(CRM)领域,有效的客户分类与标签管理是提升销售效率、优化营销ROI的关键。据统计,使用CRM管理系统进行科学客户分层的企业,客户转化率平均提升35%(企销客数据)。本文将深入解析在CRM管理软件中实施客户分类与标签管理的最佳实践…...

怎么解决cesium加载模型太黑,程序崩溃,不显示,位置不对模型太大,Cesium加载gltf/glb模型后变暗
有时候咱们cesium加载模型时候型太黑,程序崩溃,不显示,位置不对模型太大怎么办 需要处理 可以联系Q:424081801 谢谢 需要处理 可以联系Q:424081801 谢谢...

【AI系列】BM25 与向量检索
博客目录 引言:信息检索技术的演进第一部分:BM25 算法详解第二部分:向量检索技术解析第三部分:BM25 与向量检索的对比分析第四部分:融合与创新:混合检索系统 引言:信息检索技术的演进 在信息爆…...
windows10搭建nfs服务器
windows10搭建nfs服务器 Windows10搭建NFS服务 - fuzidage - 博客园...
simulink这边重新第二次仿真时,直接UE5崩溃,然后simulink没有响应
提问 : simulink这边重新第二次仿真时,直接UE5崩溃,然后simulink没有响应 simulink和UE5仿真的时候,simulink这边先停止仿真(也就是官方要求的顺序——注意:如果先在UE5那边停止仿真,如果UE5这…...
react 常见的闭包陷阱深入解析
一、引子 先来看一段代码,你能说出这段代码的问题在哪吗? const [count, setCount] = useState(0); useEffect(() => {const timer = setTimeout(() => {setCount(count + 1);}, 1000);return () => clearTimeout(timer); }, []);正确答案: 这段代码存在闭包陷阱…...
【CATIA的二次开发22】关于抽象对象Document概念详细总结
在CATIA VBA开发中,Document对象是最核心、最基础的对象之一。它代表了当前在CATIA会话中打开的一个文档(文件)。 几乎所有与文件操作、模型访问相关的操作都始于获取一个Document对象。 一、Document对象概述 1、获取Document对象: 当前活动文档: 最常见的方式是获取用户…...

模拟法解题的思路与算法分享
我们先来看思路与算法: 使用变长数组对栈进行模拟。 如果操作是 ,那么访问数组的后两个得分,将两个得分之和加到总得分,并且将两个得分之和入栈。如果操作是 D,那么访问数组的最后一个得分,将得分乘以 2 …...

mysql密码正确SpringBoot和Datagrip却连接不上
报错信息:SQLException: Access denied for user ‘root‘‘localhost‘ (using password: YES) 原因可能是是有端口号冲突 我这里是禅道端口与MySQL冲突,禅道端口也是3306,ctrlaltdelete打开任务管理器,关闭mysqlzt …...

高保真组件库:数字输入框
拖入一个文本框。 拖入一个矩形,作为整个数字输入框的边框,边框颜色为灰色DCDEE2,圆角半径为4。 拖入一个向上的箭头图标作为增加按钮,再拖入一个矩形,将向上箭头图标放入矩形内。矩形:18x15,边框颜色DCDEE2,边框左下可见,箭头图标:8x5,矩形置底,组合在一起命名”增…...
人工智能赋能高中学科教学的应用与前景研究
一、引言 1.1 研究背景 在科技飞速发展的当下,人工智能(Artificial Intelligence,简称 AI)已成为全球瞩目的关键技术领域,深刻地改变着人们的生活、工作和学习方式。从智能家居设备到智能交通系统,从医疗…...

【Linux】awk 命令详解及使用示例:结构化文本数据处理工具
【Linux】awk 命令详解及使用示例:结构化文本数据处理工具 引言 awk 是一种强大的文本处理工具和编程语言,专为处理结构化文本数据而设计。它的名称来源于其三位创始人的姓氏首字母:Alfred Aho、Peter Weinberger 和 Brian Kernighan。 基…...

紫光同创FPGA系列实现Aurora 8b/10b协议
特性 1.兼容XILINX aurora IP核 2.支持X1、X2、X4、X8模式(根据硬件条件选择模式) 3.支持FRAMING和STREAMING 用户接口 4.自动初始化和维护链路状态 5.支持热插拔 6.支持扰码、解扰 7.支持流量控制 8.支持crc用户数据 9.支持全双工或者半双工模式 10.最…...

DAY 44 预训练模型
知识点回顾: 预训练的概念常见的分类预训练模型图像预训练模型的发展史预训练的策略预训练代码实战:resnet18 (一)预训练的概念 我们发现准确率最开始随着epoch的增加而增加。随着循环的更新,参数在不断发生更新。 所以…...
[Harmony]颜色初始化
默认初始化颜色 let color: Color 0xFF00FF 创建一个工具,用十六进制颜色和RGBA初始化颜色 // 颜色工具类 export class ColorUtils {/*** 十六进制颜色初始化(支持透明度)* param hex 支持格式:#RRGGBB、#AARRGGBB、0xRRGGBB、…...
指针与函数参数传递详解 —— 值传递与地址传递的区别及应用
资料合集下载链接: https://pan.quark.cn/s/472bbdfcd014 在C语言中,函数参数的传递方式主要有两种:值传递和地址传递(通过指针)。理解两者的区别及应用对于正确操作数据和优化程序逻辑至关重要。本文将通过…...

【NLP中向量化方式】序号化,亚编码,词袋法等
1.序号化 将单词按照词典排序,给定从0或者1或者2开始的序号即可,一般情况有几 个特征的单词: PAD表示填充字符,UNK表示未知字符 在这个例子中,我们可以看到我们分别将3个文本分为了4个token,每个token用左侧的词典表示…...

C++学习-入门到精通【16】自定义模板的介绍
C学习-入门到精通【16】自定义模板的介绍 目录) C学习-入门到精通【16】自定义模板的介绍前言一、类模板创建一个自定义类模板:Stack\<T\> 二、使用函数模板来操作类模板特化的对象三、非类型形参四、模板类型形参的默认实参五、重载函数模板 前言…...
关于脏读,幻读,可重复读的学习
mysql 可以查询当前事务隔离级别 默认是RR repeatable-read 如果要测脏读 要配成未提交读 RU 读到了未提交的数据。 3.演示不可重复读 要改成提交读 RC 这个是指事务还未结束,其他事务修改了值。导致我两次读的不一样。 4.RR–可以解决不可重复读 小总结&…...

源码级拆解:如何搭建高并发「数字药店+医保购药」一体化平台?
在全民“掌上看病、线上购药”已成常态的今天,数字药店平台正在以惊人的速度扩张。而将数字药店与医保系统打通,实现线上医保购药,更是未来互联网医疗的关键拼图。 那么,如何从技术底层搭建一个 支持高并发、可扩展、安全合规的数…...
旅行商问题(TSP)的 C++ 动态规划解法教学攻略
一、问题描述 旅行商问题(TSP)是一个经典的组合优化问题。给定一个无向图,图中的顶点表示城市,边表示两个城市之间的路径,边的权重表示路径的距离。一个售货员需要从驻地出发,经过所有城市后回到驻地&…...
unix/linux,sudo,其内部结构机制
我们现在深入sudo的“引擎室”,探究其内部的结构和运作机制。这就像我们从观察行星运动,到深入研究万有引力定律的数学表达和物理内涵一样,是理解事物本质的关键一步。 sudo 的内部结构与机制详解 sudo 的执行流程可以看作是一系列精心设计的步骤,确保了授权的准确性和安…...

Hadoop 3.x 伪分布式 8088端口无法访问问题处理
【Hadoop】YARN ResourceManager 启动后 8088 端口无法访问问题排查与解决(伪分布式启动Hadoop) 在配置和启动 Hadoop YARN 模块时,发现虽然 ResourceManager 正常启动,JPS 进程中也显示无误,但通过浏览器访问 http://主机IP:8088 时却无法打…...
Redis线程安全深度解析:单线程模型的并发智慧
Redis线程安全深度解析:单线程模型的并发智慧 引言:Redis的线程模型迷思 “Redis是单线程的”——这个广为流传的说法既正确又不完全正确。Redis的线程安全机制实际上是一套精心设计的并发控制体系,它既保持了单线程的简单性,又…...

零基础在实践中学习网络安全-皮卡丘靶场(第十期-Over Permission 模块)
经过这么长时间的学习,我相信大家已经有了很大的信心,有可能会有看不起的意思,因为皮卡丘是基础靶场,但是俗话说"基础不牢,地动山摇",所以还请大家静下心来进行学习 来翻译一下是什么意思&#…...
北京大学肖臻老师《区块链技术与应用》公开课:12-BTC-比特币的匿名性
文章目录 1.比特币的匿名性不是真的匿名,相当于化名,现金是真的匿名, 2.如果银行用化名的话和比特币的匿名哪个匿名性更好? 银行匿名性比比特币好,因为比特币的区块链的账本是完全公开的,所有人都可以查&am…...
[Harmony]网络状态监听
权限 在module.json5中添加必要权限: // 声明应用需要请求的权限列表 "requestPermissions": [{"name": "ohos.permission.GET_NETWORK_INFO", // 网络信息权限"reason": "$string:network_info_reason","…...