Appearance
AI 服务 MCP 扩展与启动自动注册教程
本文以当前 muotai-ai 实现为准,说明 docreview 的 MCP 工具为什么能够在服务启动时进入 ai_tool,以及后续如何增加本地工具或独立的 Nacos MCP 服务。
1. 先区分两种 MCP
当前 AI 服务同时支持两条注册链路。两者都可能被模型看到,但代码入口、数据库字段和执行方式不同。
| 类型 | 典型代码 | 发现方式 | ai_tool 标识 | 调用方式 |
|---|---|---|---|---|
| 本地 MCP/本地工具 | DocReviewMcpService、VerifiedDocReviewMcpService | 扫描 AI 服务进程内的 Spring Bean | service_type=LOCAL、discover_mode=ANNOTATION_SCAN | 当前 JVM 内通过反射调用方法 |
| Nacos 远程 MCP | 独立 MCP 服务 | Nacos Naming + Nacos MCP Registry | service_type=MCP_REMOTE、discover_mode=NACOS | 通过 MCP client 调用远程服务的 tools/call |
这里的“本地 MCP”是项目内部对 LangChain4j @Tool 方法的称呼,不代表它会注册为一个独立的 Nacos MCP Server。要让其他服务复用能力,应采用远程 MCP 方式。
2. docreview 本地工具如何启动并入库
2.1 真实调用链
启动后的调用顺序如下:
text
Spring 根上下文刷新
|
v
LocalToolExecutor.onApplicationEvent(ContextRefreshedEvent)
|
v
LocalToolExecutor.init()
|
+-- 扫描所有 Spring Bean 的 declared methods
+-- 查找 dev.langchain4j.agent.tool.Tool
+-- 生成工具注册信息、参数 JSON Schema、返回值 Schema
+-- 写入内存 toolRegistry
+-- saveToolToDatabase() upsert ai_tool关键实现是:
com.pig4cloud.pigx.ai.agent.chatbot.tool.impl.LocalToolExecutorcom.pig4cloud.pigx.ai.docreview.mcp.DocReviewMcpServicecom.pig4cloud.pigx.ai.docreview.mcp.VerifiedDocReviewMcpService
LocalToolExecutor 只处理根应用上下文,避免 Feign 子上下文重复扫描;同时用 initialized 标志避免同一个上下文重复初始化。
2.2 docreview 当前注册的工具
DocReviewMcpService:
report_doc_review_progresssave_doc_review_riskssave_doc_review_redlinesave_doc_review_reportfinish_doc_review
VerifiedDocReviewMcpService:
save_verified_doc_review_risksfinish_verified_doc_review
这些方法使用的是:
java
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;不要替换成 org.springframework.ai.tool.annotation.Tool,否则当前 LocalToolExecutor 不会发现它们。
2.3 本地工具写入 ai_tool 的字段
扫描器第一次发现工具时,以工具名作为业务唯一 ID:
text
tool_id = @Tool(name=...) 的值
name = tool_id
service_type = LOCAL
discover_mode = ANNOTATION_SCAN
status = ACTIVE
version = 1.0.0
tags = local,langchain4j,auto-discovered同时会根据 Java 方法参数生成 parameter_schema,根据返回类型生成 response_schema,并在 metadata 中保存 Bean 类名、方法名和返回类型。
如果数据库中已经存在同名工具:
- 只有原记录同时满足
service_type=LOCAL和discover_mode=ANNOTATION_SCAN时,扫描器才会更新代码生成的描述、Schema 和元数据。 - 如果原记录来自
MCP_REMOTE、MCP_NACOS或人工配置,扫描器会跳过,不覆盖其他来源。
因此,新增本地工具不需要手工插入 ai_tool;只要 Bean 被 Spring 扫描到,重启 AI 服务即可完成内存注册和数据库 upsert。
3. 如何新增本地 MCP 工具
3.1 最小示例
在 muotai-ai-biz 的 Spring 扫描范围内新增一个 @Component:
java
package com.pig4cloud.pigx.ai.example.mcp;
import dev.langchain4j.agent.tool.P;
import dev.langchain4j.agent.tool.Tool;
import org.springframework.stereotype.Component;
@Component
public class InvoiceLocalTool {
@Tool(
name = "query_invoice_summary",
value = "根据发票号码查询发票摘要。成功返回摘要,查询不到时返回明确的错误信息。"
)
public String queryInvoiceSummary(
@P(value = "发票号码", required = true) String invoiceNo) {
// 调用本地 Service 或 Repository,避免在 Tool 方法中堆积业务逻辑。
return "invoice=" + invoiceNo;
}
}启动后可在日志中看到类似信息:
text
注册本地工具: query_invoice_summary -> InvoiceLocalTool.queryInvoiceSummary并在数据库验证:
sql
SELECT tool_id, name, service_type, discover_mode, status,
parameter_schema, response_schema
FROM ai_tool
WHERE tool_id = 'query_invoice_summary';3.2 编写约束
- 工具类必须是 Spring Bean,例如使用
@Component。 - 方法必须使用
dev.langchain4j.agent.tool.Tool。 @Tool(name=...)必须明确、稳定、全局唯一。- 工具名只能使用字母、数字、下划线和连字符;不要使用中文、空格、点号或斜杠。
- 参数使用
@P写清名称、说明和required,这样生成的 JSON Schema 才能被模型正确使用。 - 方法返回值应是容易序列化的值,例如
String、数字、布尔值或结构化对象。 - 业务逻辑放在 Service 中,Tool 方法只负责参数接收、调用和结果整理。
- 工具名不能与远程 MCP 或人工配置中的
tool_id冲突。
3.3 本地工具的边界
本地工具只存在于当前 AI 服务 JVM 内:
- 不需要 Nacos 服务名、端口和 MCP endpoint。
- 不会被其他微服务直接发现。
- 服务重启后由扫描器重新建立内存注册表。
- 数据库记录主要用于统一管理、Agent 绑定和生成工具规格。
如果工具需要独立部署、独立扩容、被多个服务复用,应该新增远程 Nacos MCP,而不是继续在 muotai-ai 中添加本地 Bean。
4. Nacos 远程 MCP 如何启动并自动入库
4.1 启动流程
远程 MCP 的自动注册入口是:
text
NacosMcpServiceAutoRegistrationConfig implements ApplicationRunner
|
+-- syncMcpServersFromRegistry()
| `-- 扫描 Nacos MCP Registry 的服务和 toolSpec
|
+-- discoverMcpServices(group)
| `-- 扫描 Nacos Naming 中以 mcp- 开头的服务
|
+-- syncService(service, group)
| `-- 获取健康实例
| `-- 获取 tools/list 或 Registry toolSpec
| `-- McpServiceSyncService.syncMcpTool()
|
`-- registerServiceListener(service, group)
`-- 服务实例变化时增量同步关键类:
NacosMcpServiceAutoRegistrationConfigNacosMcpServiceListenerConfigMcpServiceSyncServiceNacosNamingServiceConfig
启动同步和定时同步都使用同一个 McpServiceSyncService,因此新增 MCP 服务不需要在 AI 服务中额外写一个注册类。
4.2 发现和取工具的优先级
当前同步器按以下顺序获取工具定义:
- Nacos MCP Registry 的
McpServerDetailInfo.toolSpec。 - MCP 服务实例 Nacos 元数据中的
toolsJSON。 - 如果仍然拿不到有效工具列表,则跳过本次同步,不创建空工具记录。
因此,远程服务至少要保证 Registry 中有完整的工具定义,或者实例元数据中存在可解析的 tools 数组。工具定义应包含工具名、描述和 inputSchema。
4.3 关键配置
配置前缀为 ai.mcp.nacos-discovery,属性类是 NacosMcpServiceProperties。典型配置如下:
yaml
ai:
mcp:
nacos-discovery:
enabled: true
sync-on-startup: true
service-name-prefix: mcp-
nacos-groups:
- DEFAULT_GROUP
health-check-interval: 60000
listener-delay-ms: 1000
default-timeout-ms: 30000
auto-publish: true
exclude-services: []Nacos 连接配置来自 Spring Cloud Nacos 和 Alibaba MCP Nacos 配置:
yaml
spring:
cloud:
nacos:
username: ${NACOS_USERNAME}
password: ${NACOS_PASSWORD}
discovery:
server-addr: ${NACOS_HOST:wds-register}:${NACOS_PORT:8848}
ai:
alibaba:
mcp:
nacos:
server-addr: ${NACOS_HOST:wds-register}:${NACOS_PORT:8848}
username: ${NACOS_USERNAME}
password: ${NACOS_PASSWORD}实际项目使用 Nacos 配置中心时,以上配置也可能来自 application-<profile>.yml 或 muotai-ai-<profile>.yml,应以运行环境中最终合并后的配置为准。
默认行为:
| 配置 | 默认值 | 作用 |
|---|---|---|
enabled | true | 是否启用 MCP 自动发现和同步 |
sync-on-startup | true | 应用启动时是否立即全量同步 |
service-name-prefix | mcp- | 只有此前缀的 Naming 服务才会被识别 |
nacos-groups | DEFAULT_GROUP | 扫描的 Nacos 分组 |
health-check-interval | 60000 | 定期健康检查间隔,单位毫秒 |
listener-delay-ms | 1000 | 监听事件防抖时间,单位毫秒 |
default-timeout-ms | 30000 | 工具默认超时时间 |
auto-publish | true | 新同步工具默认写入 ACTIVE,否则写入 DISABLED |
4.4 远程同步写入的字段
McpServiceSyncService 创建工具时主要写入:
text
tool_id = 当前 MCP 工具名
name = 当前 MCP 工具名
description = MCP 工具描述
version = 实例元数据中的 mcp-version,默认 1.0.0
service_type = MCP_REMOTE
discover_mode = NACOS
nacos_service_name = Nacos 服务名
nacos_group = Nacos 分组
endpoint = 网关地址/服务路径,并可能带系统 MCP API Key
parameter_schema = MCP inputSchema,缺失时使用空 object Schema
response_schema = 默认 object Schema
status = auto-publish ? ACTIVE : DISABLED
metadata = 服务名、分组、实例数、工具名和最后同步时间同步按 serviceName@groupName 加锁,单个工具遇到数据库锁冲突最多重试三次。已存在的工具会更新描述、Schema、Nacos 归属、endpoint、实例数和同步时间。
4.5 服务下线和工具删除
当前实现的处理方式是:
- 没有实例或没有健康实例时,优先尝试从 Nacos MCP Registry 兜底同步;如果也失败,则跳过本次更新。
- 服务实例变化会触发监听器同步。
- 已注册服务由定时健康检查重新同步。
removeDeletedTools()会把服务当前不存在的工具标记为DISABLED,不会物理删除。- 当前启动流程没有启用删除服务记录的逻辑,
removeDeletedServices()调用被注释,因此数据库中可能保留历史服务工具记录。
5. 新增独立 Nacos MCP 服务的步骤
5.1 服务端必须提供的能力
独立 MCP 服务需要实现标准 MCP 协议的至少两个操作:
tools/list:返回工具名、描述和inputSchema。tools/call:根据工具名和参数执行实际业务并返回结果。
伪代码:
text
tools/list -> {
"tools": [
{
"name": "query_invoice_summary",
"description": "根据发票号码查询摘要",
"inputSchema": {
"type": "object",
"properties": {
"invoiceNo": {"type": "string", "description": "发票号码"}
},
"required": ["invoiceNo"]
}
}
]
}
tools/call(name="query_invoice_summary", arguments={"invoiceNo":"INV-001"})
-> 返回 MCP 标准结果5.2 注册到 Nacos
- 服务名使用
mcp-前缀,例如mcp-invoice-server。 - 使用与 AI 服务一致的 Nacos 地址、命名空间和分组。
- 服务启动后注册健康实例。
- 在 Nacos MCP Registry 中注册服务详情,包括名称、版本、协议、远程服务引用、endpoint 和
toolSpec。 toolSpec.tools中每个工具必须有稳定的name、description和inputSchema。- 如果服务依赖实例元数据兜底同步,可额外设置
toolsJSON、mcp-version、timeout、rate-limit、permissions、tags等元数据。 - 确认实例健康后,重启 AI 服务,或等待健康检查周期触发同步。
注册完成后可在 AI 数据库确认:
sql
SELECT tool_id, name, service_type, discover_mode,
nacos_service_name, nacos_group, endpoint, status
FROM ai_tool
WHERE nacos_service_name = 'mcp-invoice-server'
ORDER BY id;5.3 远程工具命名注意事项
当前 generateToolIdForTool() 直接返回 MCP 工具名,不包含服务名和分组。例如两个服务都提供 query_invoice_summary,会竞争同一个 ai_tool.tool_id 唯一键。
新增远程 MCP 时必须暂时保证工具名全局不重复,例如:
text
invoice_query_summary
vehicle_query_summary后续如果要支持不同服务提供同名工具,应先改造 ID 策略,例如使用 服务标识_工具名,并同步调整 Agent 配置、历史数据迁移和执行器查找逻辑。不要只修改数据库唯一索引。
6. 智能体如何使用已注册工具
工具进入 ai_tool 后,还需要被 Agent 配置引用,才会进入模型可用工具列表。
调用链如下:
text
Agent.toolIds
|
v
加载 ai_tool 记录
|
v
AiToolServiceImpl.buildToolSpecifications()
|
v
向模型发送工具名称、描述和 parameter_schema
|
v
ToolExecutorFactory 按 service_type 选择执行器注意事项:
- 仅写入
ai_tool不等于所有 Agent 自动可用;需要把工具 ID 绑定到目标 Agent。 MCP_REMOTE记录由McpRemoteToolExecutor处理。MCP_NACOS类型由McpNacosToolExecutor处理。当前数据库同步逻辑写入的是MCP_REMOTE,不要只根据类名判断实际路径。- 远程调用会使用数据库中的
endpoint,并结合nacos_service_name/nacos_group做服务发现;客户端随后执行 MCPtools/call。 parameter_schema会转换为 LangChain4j 的工具规格。Schema 不完整时,模型可能无法正确生成参数。
7. 数据库检查 SQL
7.1 查询所有 MCP 工具
sql
SELECT id, tool_id, name, service_type, discover_mode,
nacos_service_name, nacos_group, status, endpoint,
created_at, updated_at
FROM ai_tool
WHERE deleted_at IS NULL
AND service_type IN ('LOCAL', 'MCP_REMOTE', 'MCP_NACOS')
ORDER BY service_type, nacos_service_name, id;7.2 查询指定 Nacos 服务
sql
SELECT tool_id, description, parameter_schema, response_schema,
nacos_service_name, nacos_group, endpoint, status, metadata
FROM ai_tool
WHERE deleted_at IS NULL
AND nacos_service_name = 'mcp-invoice-server';7.3 查询禁用或不可用工具
sql
SELECT tool_id, service_type, nacos_service_name, nacos_group,
status, metadata, updated_at
FROM ai_tool
WHERE deleted_at IS NULL
AND status <> 'ACTIVE'
ORDER BY updated_at DESC;7.4 检查跨服务同名工具
sql
SELECT tool_id, COUNT(*) AS total,
GROUP_CONCAT(DISTINCT nacos_service_name ORDER BY nacos_service_name) AS services
FROM ai_tool
WHERE deleted_at IS NULL
AND service_type IN ('MCP_REMOTE', 'MCP_NACOS')
GROUP BY tool_id
HAVING COUNT(DISTINCT nacos_service_name) > 1;7.5 检查工具参数 Schema
sql
SELECT tool_id, JSON_PRETTY(parameter_schema) AS parameter_schema
FROM ai_tool
WHERE tool_id = 'query_invoice_summary';8. 日志和故障排查
8.1 建议关注的日志关键字
开始 Nacos MCP 服务自动发现发现 MCP 服务Nacos MCP Registry 工具同步完成创建新的 MCP 工具更新 MCP 工具注册 MCP 服务监听器MCP 服务自动发现失败无法从 MCP 服务获取工具列表
8.2 服务名没有 mcp- 前缀
现象:Nacos 中实例健康,但 AI 服务完全没有发现日志。
处理:确认 service-name-prefix 的值,默认必须是 mcp-;服务名例如 mcp-invoice-server。如果确实需要其他前缀,应修改 AI 服务配置,而不是手工插入 ai_tool。
8.3 Nacos 分组、命名空间或账号不一致
现象:Naming 能看到服务,但 Registry 查不到详情,或 AI 服务查询不到实例。
处理:核对以下值是否一致:
- Nacos server address
- namespace
- username/password
DEFAULT_GROUP或自定义 group- AI 服务
nacos-groups配置
8.4 实例不健康
现象:服务被发现,但工具没有入库或状态没有更新。
处理:先确认实例健康;同步器只优先使用健康实例。没有健康实例时会尝试 Registry 兜底,兜底失败会保留原记录,不会用空工具覆盖数据库。
8.5 Registry 没有 toolSpec
现象:服务和实例都存在,但日志显示工具列表为空。
处理:在 Nacos MCP Registry 补齐服务详情和 toolSpec.tools;或者在实例元数据提供合法的 tools JSON。每个工具至少应包含 name 和可用的 inputSchema。
8.6 tools 元数据 JSON 错误
现象:日志出现元数据解析失败。
处理:确认 tools 是 JSON 数组,而不是 Java 对象字符串或单个 JSON 对象。例如:
json
[
{
"name": "query_invoice_summary",
"description": "查询发票摘要",
"inputSchema": {
"type": "object",
"properties": {
"invoiceNo": {"type": "string"}
},
"required": ["invoiceNo"]
}
}
]8.7 工具名冲突
现象:数据库出现唯一键冲突、同名工具归属异常,或一个工具覆盖另一个服务的描述和 endpoint。
处理:使用全局唯一工具名;检查第 7.4 节 SQL。当前实现以工具名作为 tool_id,不能依赖服务名自动隔离。
8.8 Agent 未绑定工具 ID
现象:ai_tool 中有记录,但模型没有看到工具。
处理:将对应 ai_tool.id/工具 ID 绑定到目标 Agent,确认 Agent 加载配置时包含该工具,并检查工具状态为 ACTIVE。
8.9 endpoint、API Key 或网关地址错误
现象:工具已经入库,但调用时连接失败或返回 401/404。
处理:检查 endpoint 是否指向正确的 MCP 路径,网关地址是否与服务命名约定一致;系统会尝试从 UPMS 获取系统 MCP API Key,若未获取到,endpoint 可能不带 api_key 参数。必要时直接检查数据库中的 endpoint 和 AI 服务日志。
8.10 工具名包含中文或非法字符
现象:模型工具规格构建失败,或调用阶段提示工具名不合法。
处理:改成只包含 [A-Za-z0-9_-] 的名称,例如 query_invoice_summary;中文应放在 description 中。
9. 新增 MCP 的推荐检查清单
本地工具
- [ ] 类是 Spring
@Component。 - [ ] 方法使用
dev.langchain4j.agent.tool.Tool。 - [ ] 工具名全局唯一且只含合法字符。
- [ ] 参数使用
@P,说明和必填性完整。 - [ ] 重启 AI 服务后日志出现本地工具注册信息。
- [ ]
ai_tool中为LOCAL+ANNOTATION_SCAN+ACTIVE。 - [ ] 目标 Agent 已绑定工具。
Nacos 远程 MCP
- [ ] 服务名以
mcp-开头,或已调整service-name-prefix。 - [ ] Nacos 地址、namespace、账号和 group 与 AI 服务一致。
- [ ] 实现
tools/list和tools/call。 - [ ] Registry 中有有效
toolSpec,或实例元数据有合法toolsJSON。 - [ ] 实例健康。
- [ ] 工具名全局唯一,避免当前
tool_id冲突。 - [ ] 启动同步或定时同步日志显示工具创建/更新。
- [ ]
ai_tool中为MCP_REMOTE+NACOS+ACTIVE。 - [ ] 目标 Agent 已绑定工具。
- [ ] 实际调用 endpoint、API Key 和 MCP 路径可达。
10. 代码参考位置
- 本地扫描和入库:
muotai-ai/muotai-ai-biz/src/main/java/com/pig4cloud/pigx/ai/agent/chatbot/tool/impl/LocalToolExecutor.java - 文档审查本地工具:
muotai-ai/muotai-ai-biz/src/main/java/com/pig4cloud/pigx/ai/docreview/mcp/DocReviewMcpService.java - 已验证审查工具:
muotai-ai/muotai-ai-biz/src/main/java/com/pig4cloud/pigx/ai/docreview/mcp/VerifiedDocReviewMcpService.java - Nacos 启动同步:
muotai-ai/muotai-ai-biz/src/main/java/com/pig4cloud/pigx/ai/config/NacosMcpServiceAutoRegistrationConfig.java - Nacos 监听和定时发现:
muotai-ai/muotai-ai-biz/src/main/java/com/pig4cloud/pigx/ai/config/NacosMcpServiceListenerConfig.java - MCP 同步和 upsert:
muotai-ai/muotai-ai-biz/src/main/java/com/pig4cloud/pigx/ai/service/McpServiceSyncService.java - AI 工具实体:
muotai-ai/muotai-ai-biz/src/main/java/com/pig4cloud/pigx/ai/domain/entity/AiToolEntity.java - 工具表初始化:
muotai-ai/muotai-ai-biz/src/main/resources/db.migration/V0.0.1__create_ai_tool.sql - 发现模式扩展:
muotai-ai/muotai-ai-biz/src/main/resources/db.migration/V0.0.67__make_ai_tool_discovery_extensible.sql