MCP 服务注册
Nacos 3.0 引入了革命性的 AI 服务注册能力,支持 MCP(Model Context Protocol)服务的自动注册与发现。本章介绍如何使用 Nacos 作为 MCP Registry 实现 AI 服务的管理。
概述
什么是 MCP
MCP(Model Context Protocol)是一个开放协议,用于连接 AI 模型与外部工具和数据源。通过 MCP,AI 应用可以:
- 调用外部工具获取实时数据
- 执行特定操作
- 访问各种数据源
Nacos MCP Registry 的优势
Nacos 3.0 作为 MCP Registry 提供:
- 动态服务管理:通过控制台添加、删除、更新 MCP 服务
- 动态描述更新:工具描述和参数定义支持运行时热更新
- 动态开关控制:运行时启用或禁用工具,无需重启服务
- 全栈集成:与 Spring AI Alibaba、Nacos MCP Router、Higress 网关无缝集成
架构图
┌─────────────────────────────────────────────────────────────────┐
│ Nacos MCP Registry 架构 │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ AI Agent 应用 │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Spring AI │ │ LangChain │ │ 其他框架 │ │ │
│ │ │ Alibaba │ │ │ │ │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ │ 发现 MCP 服务 │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Nacos MCP Registry │ │
│ │ ┌────────────────────────────────────────────────────┐ │ │
│ │ │ MCP 服务列表 │ │ │
│ │ │ • 服务名称、版本、描述 │ │ │
│ │ │ • 工具定义(Tool Definitions) │ │ │
│ │ │ • 服务地址、协议类型 │ │ │
│ │ └────────────────────────────────────────────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ │ 注册 MCP 服务 │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ MCP Server 服务 │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ Java 服务 │ │ Python 服务 │ │ 其他服务 │ │ │
│ │ │ (Spring AI) │ │ (FastMCP) │ │ │ │ │
│ │ └─────────────┘ └─────────────┘ └─────────────┘ │ │
│ └──────────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────────┘
快速开始
环境准备
- Nacos 3.0+ 服务已启动
- JDK 17+(Java 方式)
- Python 3.8+(Python 方式)
使用 Spring AI Alibaba 注册 MCP 服务
1. 添加依赖
<!-- Nacos MCP Registry Starter -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-mcp-registry</artifactId>
<version>1.0.0.3</version>
</dependency>
<!-- MCP Server (WebMVC) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-server-webmvc</artifactId>
<version>1.0.0</version>
</dependency>
2. 定义工具服务
使用 @Tool 注解定义 MCP 工具:
@Service
public class WeatherService {
/**
* 根据城市名称获取天气信息
*
* @param cityName 城市名称
* @return 天气信息
*/
@Tool(description = "根据城市名称获取天气信息")
public String getWeather(
@ToolParam(description = "城市名称,如:北京、上海") String cityName) {
// 实际应用中调用天气 API
return String.format("%s 今天天气晴朗,气温 25°C", cityName);
}
/**
* 获取空气质量指数
*
* @param cityName 城市名称
* @return 空气质量指数
*/
@Tool(description = "获取指定城市的空气质量指数")
public String getAirQuality(
@ToolParam(description = "城市名称") String cityName) {
// 模拟返回空气质量数据
return String.format("%s 空气质量指数:优(AQI 50)", cityName);
}
}
3. 配置自动注册
在 application.yml 中配置:
spring:
application:
name: weather-mcp-server
ai:
mcp:
server:
name: weather-service # MCP 服务名称
version: 1.0.0 # 服务版本
type: SYNC # 调用类型:SYNC(同步)或 ASYNC(异步)
instructions: 提供天气查询和空气质量查询服务
# Nacos 配置
alibaba:
cloud:
nacos:
server-addr: 127.0.0.1:8848
username: nacos
password: nacos
namespace: public
group: MCP_GROUP
4. 注册工具 Bean
在启动类中注册工具:
@SpringBootApplication
public class McpServerApplication {
public static void main(String[] args) {
SpringApplication.run(McpServerApplication.class, args);
}
@Bean
public ToolCallbackProvider weatherTools(WeatherService weatherService) {
return MethodToolCallbackProvider.builder()
.toolObjects(weatherService)
.build();
}
}
启动服务后,MCP 服务会自动注册到 Nacos。
使用 Python 注册 MCP 服务
1. 安装依赖
pip install nacos-mcp-wrapper-python
2. 创建 MCP 服务
使用 NacosMCP 类创建 MCP 服务,通过 @mcp.tool() 装饰器定义工具:
from nacos_mcp_wrapper.server.nacos_mcp import NacosMCP
from nacos_mcp_wrapper.server.nacos_settings import NacosSettings
# 创建 Nacos 配置
nacos_settings = NacosSettings()
nacos_settings.SERVER_ADDR = "127.0.0.1:8848" # Nacos 服务地址
nacos_settings.NAMESPACE = "public" # 命名空间
nacos_settings.USERNAME = "nacos" # 用户名
nacos_settings.PASSWORD = "nacos" # 密码
# 创建 MCP 服务实例
mcp = NacosMCP(
"finance-tools", # MCP 服务名称
nacos_settings=nacos_settings,
version="1.0.0", # 服务版本
port=18001 # 服务端口
)
# 注册工具:获取股票价格
@mcp.tool()
def get_stock_price(symbol: str) -> str:
"""
获取指定股票代码的当前价格
Args:
symbol: 股票代码,如 AAPL、GOOGL、MSFT
"""
# 模拟返回股票价格
prices = {
"AAPL": "178.50",
"GOOGL": "141.25",
"MSFT": "378.90"
}
price = prices.get(symbol, "未知股票")
return f"{symbol} 当前价格: ${price}"
# 注册工具:加法运算
@mcp.tool()
def add_numbers(a: int, b: int) -> int:
"""
计算两个整数的和
Args:
a: 第一个整数
b: 第二个整数
"""
return a + b
# 注册工具:减法运算
@mcp.tool()
def minus_numbers(a: int, b: int) -> int:
"""
计算两个整数的差
Args:
a: 被减数
b: 减数
"""
return a - b
if __name__ == "__main__":
try:
# 启动 MCP 服务,支持三种传输类型
mcp.run(transport="sse")
# mcp.run(transport="stdio")
# mcp.run(transport="streamable-http")
except Exception as e:
print(f"运行时错误: {e}")
3. 传输类型说明
Nacos MCP Python 支持三种传输类型:
| 传输类型 | 说明 | 适用场景 |
|---|---|---|
sse | Server-Sent Events | 远程服务,支持流式响应 |
stdio | 标准输入输出 | 本地进程通信 |
streamable-http | 可流式 HTTP | 远程服务,兼容性好 |
选择建议:
- 远程服务:推荐使用
sse或streamable-http - 本地开发测试:可使用
stdio - 需要穿越防火墙:推荐
streamable-http
在控制台管理 MCP 服务
查看 MCP 服务列表
- 登录 Nacos 控制台
- 进入「AI 服务」->「MCP 服务」
- 可以看到所有已注册的 MCP 服务
查看服务详情
点击服务名称可以查看:
- 服务基本信息(名称、版本、描述)
- 工具列表(Tool Definitions)
- 服务地址和协议类型
- 元数据信息
动态管理工具
Nacos 3.0 支持运行时动态管理 MCP 工具:
启用/禁用工具:
- 进入服务详情页
- 在工具列表中找到目标工具
- 点击开关按钮启用或禁用
修改工具描述:
- 点击工具的「编辑」按钮
- 修改工具描述或参数说明
- 保存后立即生效
AI Agent 调用 MCP 服务
使用 Spring AI Alibaba 调用
1. 添加依赖
<!-- OpenAI 模型配置(用于连接大模型) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-openai</artifactId>
<version>1.0.0</version>
</dependency>
<!-- Chat Client 配置 -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-autoconfigure-model-chat-client</artifactId>
<version>1.0.0</version>
</dependency>
<!-- Nacos MCP Registry -->
<dependency>
<groupId>com.alibaba.cloud.ai</groupId>
<artifactId>spring-ai-alibaba-starter-mcp-registry</artifactId>
<version>1.0.0.3</version>
</dependency>
<!-- MCP Client (WebFlux) -->
<dependency>
<groupId>org.springframework.ai</groupId>
<artifactId>spring-ai-starter-mcp-client-webflux</artifactId>
<version>1.0.0</version>
</dependency>
2. 创建 MCP 客户端
Spring AI Alibaba 提供两种客户端类型:
同步客户端:
@Autowired
private List<LoadbalancedMcpSyncClient> loadbalancedMcpSyncClients;
异步客户端:
@Autowired
private List<LoadbalancedMcpAsyncClient> loadbalancedMcpAsyncClients;
使用 ToolCallbackProvider(推荐):
// 同步工具回调
@Autowired
@Qualifier("loadbalancedSyncMcpToolCallbacks")
private ToolCallbackProvider syncToolCallbacks;
// 异步工具回调
@Autowired
@Qualifier("loadbalancedMcpAsyncToolCallbacks")
private ToolCallbackProvider asyncToolCallbacks;
3. 配置文件
spring:
application:
name: mcp-client-app
ai:
openai:
api-key: ${DASHSCOPE_API_KEY}
base-url: https://dashscope.aliyuncs.com/compatible-mode
chat:
options:
model: qwen-max
alibaba:
mcp:
nacos:
server-addr: 127.0.0.1:8848
namespace: public
group: MCP_GROUP
username: nacos
password: nacos
4. 完整调用示例
@SpringBootApplication
public class McpClientApplication {
public static void main(String[] args) {
SpringApplication.run(McpClientApplication.class, args);
}
@Bean
public CommandLineRunner chatDemo(
ChatClient.Builder chatClientBuilder,
@Qualifier("loadbalancedSyncMcpToolCallbacks") ToolCallbackProvider tools) {
return args -> {
// 构建 ChatClient,注入 MCP 工具
ChatClient chatClient = chatClientBuilder
.defaultToolCallbacks(tools.getToolCallbacks())
.build();
Scanner scanner = new Scanner(System.in);
System.out.println("MCP Client 已启动,输入问题进行对话(输入 'exit' 退出)");
while (true) {
System.out.print("\n>>> 问题: ");
String userInput = scanner.nextLine();
if ("exit".equalsIgnoreCase(userInput)) {
break;
}
if (userInput.isEmpty()) {
continue;
}
// 调用 AI 并自动使用 MCP 工具
String response = chatClient.prompt()
.user(userInput)
.call()
.content();
System.out.println("\n>>> 回答: " + response);
}
};
}
}
调用示例
用户输入:
请帮我查询北京今天的天气情况
AI Agent 会自动:
- 从 Nacos 发现 weather-service MCP 服务
- 调用 getWeather 工具
- 返回天气信息
响应:
北京今天天气晴朗,气温 25°C
与 Higress 网关集成
Nacos MCP Registry 可以与 Higress 网关集成,实现统一的流量管理和安全控制。
配置 Higress
# Higress 配置
mcp:
registry:
nacos:
server-addr: 127.0.0.1:8848
namespace: public
group: MCP_GROUP
架构示例
┌─────────────┐ ┌─────────────┐ ┌─────────────┐
│ AI Agent │ ──> │ Higress │ ──> │ MCP Server │
│ │ │ Gateway │ │ │
└─────────────┘ └─────────────┘ └─────────────┘
│
│ 服务发现
▼
┌─────────────┐
│ Nacos │
│ MCP Registry
└─────────────┘
通过网关可以实现:
- 统一的认证授权
- 流量控制和限流
- 请求日志和审计
- 服务路由和负载均衡
最佳实践
1. 服务命名规范
建议使用清晰、有意义的命名规范,便于管理和识别:
{业务域}-{功能描述}-{版本}
示例:
- weather-query-v1 # 天气查询服务 v1
- finance-stock-v1 # 金融股票服务 v1
- travel-booking-v1 # 旅行预订服务 v1
- order-process-async-v1 # 订单处理服务(异步)v1
命名约定:
- 使用小写字母和连字符
- 业务域在前,功能描述在后
- 版本号使用 v1、v2 等格式
- 异步服务添加 async 后缀
2. 版本管理策略
版本兼容性原则:
同一版本号下的工具定义必须保持兼容:
- 可以添加新工具
- 可以修改工具描述和参数描述
- 不能修改工具名称
- 不能修改参数名称和类型
- 不能删除工具或参数
版本升级流程:
1. 开发新版本服务(如 weather-query-v2)
2. 在 Nacos 中注册新版本
3. 更新 AI Agent 配置,逐步切换到新版本
4. 观察运行稳定后,下线旧版本
版本共存示例:
# AI Agent 可以同时使用多个版本
spring:
ai:
alibaba:
mcp:
clients:
- name: weather-query-v1 # 稳定版本
- name: weather-query-v2 # 新版本,灰度测试
3. 工具描述编写规范
清晰、详细的描述有助于 AI 正确理解和使用工具:
@Tool(description = """
根据城市名称获取天气预报信息。
支持的城市:
- 一线城市:北京、上海、广州、深圳
- 省会城市:杭州、南京、成都、武汉等
返回信息包括:
- 天气状况(晴、雨、阴等)
- 温度范围(最高/最低温度)
- 湿度百分比
- 风力等级和风向
- 空气质量指数(AQI)
""")
public String getWeatherForecast(
@ToolParam(description = "城市名称,必须是支持的中文城市名,如:北京、上海") String cityName,
@ToolParam(description = "预报天数,范围 1-7,默认 3 天", required = false) Integer days) {
// 实现
}
描述编写建议:
- 第一句话概括工具功能
- 列出重要的使用限制
- 说明返回内容的格式和含义
- 参数描述要包含格式要求和默认值
4. 错误处理与用户友好提示
合理的错误处理可以提升用户体验,帮助 AI 理解问题并做出合适的响应:
@Tool(description = "查询银行账户余额")
public String getAccountBalance(
@ToolParam(description = "银行账户号码") String accountNumber) {
try {
// 验证账户格式
if (!accountNumber.matches("\\d{16,19}")) {
return "错误:账户号码格式不正确,应为 16-19 位数字";
}
// 查询余额
BigDecimal balance = accountService.getBalance(accountNumber);
if (balance == null) {
return "错误:账户不存在或无权限访问";
}
return String.format("账户 %s 余额:¥%.2f",
maskAccountNumber(accountNumber), balance);
} catch (ServiceUnavailableException e) {
return "系统繁忙,请稍后重试";
} catch (Exception e) {
log.error("查询余额失败", e);
return "查询失败,请联系客服";
}
}
5. 敏感信息保护
对敏感数据进行脱敏处理,防止信息泄露:
private String maskAccountNumber(String accountNumber) {
if (accountNumber == null || accountNumber.length() < 8) {
return accountNumber;
}
// 保留前4位和后4位
return accountNumber.substring(0, 4) + "****" +
accountNumber.substring(accountNumber.length() - 4);
}
private String maskPhone(String phone) {
if (phone == null || phone.length() < 7) {
return phone;
}
// 保留前3位和后4位
return phone.substring(0, 3) + "****" + phone.substring(phone.length() - 4);
}
6. 多环境管理
使用命名空间隔离不同环境,确保开发、测试、生产环境互不影响:
命名空间配置:
- mcp-dev :开发环境
- mcp-test :测试环境
- mcp-staging :预发布环境
- mcp-prod :生产环境
不同环境的配置示例:
# application-dev.yml
spring:
ai:
alibaba:
mcp:
nacos:
namespace: mcp-dev
# application-prod.yml
spring:
ai:
alibaba:
mcp:
nacos:
namespace: mcp-prod
7. 监控与日志
添加监控指标:
@Service
public class MonitoredWeatherService {
private final MeterRegistry meterRegistry;
@Tool(description = "获取天气信息")
public String getWeather(String cityName) {
Timer.Sample sample = Timer.start(meterRegistry);
try {
String result = doGetWeather(cityName);
meterRegistry.counter("mcp.tool.success", "tool", "getWeather").increment();
return result;
} catch (Exception e) {
meterRegistry.counter("mcp.tool.error", "tool", "getWeather").increment();
throw e;
} finally {
sample.stop(meterRegistry.timer("mcp.tool.duration", "tool", "getWeather"));
}
}
}
日志记录最佳实践:
@Slf4j
@Service
public class LoggingWeatherService {
@Tool(description = "获取天气信息")
public String getWeather(String cityName) {
log.info("MCP工具调用开始: getWeather, 参数: cityName={}", cityName);
try {
String result = weatherApi.query(cityName);
log.info("MCP工具调用成功: getWeather, 结果长度: {}", result.length());
return result;
} catch (Exception e) {
log.error("MCP工具调用失败: getWeather, 错误: {}", e.getMessage(), e);
throw e;
}
}
}
8. 性能优化建议
工具实现优化:
// 推荐:异步处理耗时操作
@Tool(description = "批量查询天气")
public CompletableFuture<String> batchGetWeather(List<String> cities) {
return CompletableFuture.supplyAsync(() -> {
return cities.parallelStream()
.map(this::getWeather)
.collect(Collectors.joining("\n"));
});
}
// 推荐:添加缓存
@Cacheable(value = "weather", key = "#cityName", unless = "#result == null")
@Tool(description = "获取天气信息")
public String getWeather(String cityName) {
return weatherApi.query(cityName);
}
// 推荐:设置合理的超时
@Tool(description = "获取天气信息")
public String getWeather(String cityName) {
return weatherApi.queryWithTimeout(cityName, Duration.ofSeconds(5));
}
常见问题
1. 服务注册失败
错误信息:服务启动后未在 Nacos 控制台看到 MCP 服务
排查步骤:
- 检查 Nacos 服务是否正常运行
- 确认网络连通性,能够访问 Nacos 服务地址
- 验证认证信息(用户名、密码)是否正确
- 检查命名空间和分组配置是否正确
解决方案:
# 检查配置是否正确
alibaba:
cloud:
nacos:
server-addr: 127.0.0.1:8848 # 确保地址正确
namespace: public # 确保命名空间存在
group: MCP_GROUP # 确保分组正确
username: nacos # 确保用户名正确
password: nacos # 确保密码正确
2. MCP Server 数据不兼容
错误信息:mcp server info is not compatible 或 check mcp server compatible false
原因:Nacos 中已存在相同版本的 MCP Server 数据,但新注册的数据与原有数据不兼容。
兼容性检查项:
- MCP Server 协议(stdio、sse、streamable-http)是否一致
- 服务引用是否一致
- Tools 数据是否一致:
- Tools 名称
- Tools 数量
- 参数类型
- 参数是否可选
- 注意:Tools 描述和参数描述不要求一致
解决方案:
- 如果是有意更新工具定义,先在 Nacos 控制台删除旧版本的 MCP 服务
- 如果是启动了多个相同服务实例,确保它们的工具定义完全一致
3. AI Agent 无法发现服务
现象:AI Agent 无法找到已注册的 MCP 服务
排查步骤:
- 确认服务是否已在 Nacos 控制台正确显示
- 检查客户端配置的命名空间和分组是否与服务注册时一致
- 确认工具是否已启用(在控制台检查工具状态)
解决方案:
# 确保客户端和服务端配置一致
spring:
ai:
alibaba:
mcp:
nacos:
server-addr: 127.0.0.1:8848
namespace: public # 必须与服务注册时一致
group: MCP_GROUP # 必须与服务注册时一致
4. 工具调用超时
现象:调用 MCP 工具时返回超时错误
解决方案:
spring:
ai:
mcp:
client:
request-timeout: 30000 # 增加请求超时时间(毫秒)
connect-timeout: 10000 # 增加连接超时时间(毫秒)
同时优化工具实现,减少处理时间:
- 避免在工具中进行耗时的 I/O 操作
- 对于必须的耗时操作,考虑使用异步方式
- 设置合理的超时时间并优雅处理超时
5. 多实例负载均衡问题
现象:部署多个 MCP Server 实例时,请求未正确分发
解决方案:
spring:
ai:
alibaba:
mcp:
nacos:
# 启用负载均衡
loadbalancer:
enabled: true
# 负载均衡策略:random(随机)、round-robin(轮询)
strategy: round-robin
6. 工具描述中文乱码
现象:在 Nacos 控制台或 AI 响应中看到工具描述出现乱码
解决方案:
- 确保源代码文件使用 UTF-8 编码保存
- 确保数据库和 Nacos 的字符编码配置正确
- 在 Java 代码中明确指定编码:
@Tool(description = "根据城市名称获取天气信息")
public String getWeather(
@ToolParam(description = "城市名称,如:北京、上海") String cityName) {
// 实现
}