GitHub user Similarityoung added a comment to the discussion: [MCP] MCP Milestones
# MCP Server 与 Nacos 集成设计方案 ## 概述 本评论描述了 Dubbo-go-pixiu 中 MCP Server 与 Nacos 集成的设计方案,实现动态配置管理和服务发现能力。该方案通过扩展 pkg/remote 模块提供统一的远程通信抽象,并在 pkg/adapter 层创建 mcpserver 适配器来实现配置的动态转换和生命周期管理。 ## 架构背景 ### 现有架构问题 当前dubbo-go-pixiu存在以下架构不一致性: 1. **分散的Nacos客户端实现** - `pkg/remote/nacos/client.go`: 服务发现客户端(naming_client.INamingClient) - `configcenter/nacos_load.go`: 配置管理客户端(config_client.IConfigClient) - 两套独立实现导致代码重复和维护困难 2. **静态MCP Server配置** - 当前`pkg/filter/mcp/mcpserver`只支持静态配置的工具 - 无法动态响应Nacos配置变化 - 缺乏与远程配置中心的集成能力 3. **缺乏统一抽象** - `pkg/remote` 缺乏配置管理能力 - `configcenter` 与 `pkg/remote` 职责重叠 - 没有统一的远程存储通信抽象 ### 目标架构 建立清晰的三层架构: 1. **pkg/remote**: 统一远程存储通信抽象层 2. **pkg/adapter**: 配置转换和生命周期管理层 3. **pkg/filter**: 协议处理层 ### 动态配置发现流程 本节流程图聚焦于**配置发现的逻辑**,阐述了网关如何从 Nacos 中一步步发现并聚合一个完整 MCP 服务所需的全部信息。 ```mermaid sequenceDiagram participant Pixiu as Pixiu 网关 participant Nacos loop 定期服务发现 Pixiu->>Nacos: 1. 搜索所有 MCP 服务<br>(查询 group='mcp-server-versions' 的配置) Nacos-->>Pixiu: 返回服务ID列表 end Note over Pixiu: 为每个新发现的服务启动一个独立的监听流程 Pixiu->>Nacos: 2. 监听服务版本<br>(Listen to `{serviceId}-mcp-versions.json`) Nacos-->>Pixiu: 推送版本更新 (例如: `latest: v1.0.0`) Note over Pixiu: 收到新版本后,开始监听该版本的具体规格文件 Pixiu->>Nacos: 3. 监听服务与工具规格<br>(Listen to `...-v1.0.0-mcp-server.json`)<br>(Listen to `...-v1.0.0-mcp-tools.json`) Nacos-->>Pixiu: 推送服务规格 (Service Spec) Note over Pixiu: 从服务规格中解析出后端服务名 (`serviceRef`) Pixiu->>Nacos: 4. 订阅后端服务实例<br>(Subscribe to `serviceRef`) Nacos-->>Pixiu: 推送实例列表 (e.g., [10.0.0.1, 10.0.0.2]) Nacos-->>Pixiu: 推送工具规格 (Tool Spec) Note over Pixiu: 当版本、服务规格、工具规格、实例列表<br>这四份信息都就绪后... Pixiu->>Pixiu: 5. 聚合生成完整的配置快照 Note over Pixiu: 快照已生成,准备在网关内部应用 ``` ## 设计方案 ### 1. 统一远程客户端抽象 (`pkg/remote`) 本层负责**屏蔽底层具体远程存储(如 Nacos、etcd)的实现差异**,为上层提供一个稳定、统一的交互接口。 #### 1.1 核心接口定义 我们将定义一个核心的 `RemoteClient` 接口,它通过组合另外两个接口来获得所需的能力。 * **`RemoteClient` 接口**: * **组合能力**: 它将内嵌 `ServiceDiscovery` 和 `ConfigManagement` 两个接口。 * **生命周期管理**: * `Start() error`: 启动客户端,建立与远程服务的连接。 * `Stop() error`: 关闭客户端,释放所有资源。 * **`ServiceDiscovery` 接口**: 负责服务发现相关的所有操作。 * **方法**: * `SelectInstances(serviceName string) ([]Instance, error)`: 根据服务名查询所有健康的服务实例列表。`Instance` 是一个我们自己定义的、与具体实现无关的结构体,包含 IP、端口、元数据等信息。 * `Subscribe(serviceName string, callback func([]Instance)) error`: 订阅一个服务的实例变化。当实例列表发生变更时,将异步调用传入的 `callback` 函数。 * `Unsubscribe(serviceName string) error`: 取消对某个服务的订阅。 * **`ConfigManagement` 接口**: 负责配置管理相关的所有操作。 * **方法**: * `GetConfig(dataId, group string) (string, error)`: 根据 `dataId` 和 `group` 获取一份配置,返回其原始内容(字符串)。 * `ListenConfig(dataId, group string, callback func(string)) error`: 监听一份配置的变更。当内容发生变化时,将异步调用传入的 `callback` 函数。 * `StopListen(dataId, group string) error`: 取消对某份配置的监听。 #### 1.2 Nacos 客户端实现 (`UnifiedNacosClient`) 这是 `RemoteClient` 接口在 Nacos 场景下的具体实现。 * **结构**: `UnifiedNacosClient` 是一个结构体 (struct)。 * **核心字段**: * `namingClient`: 持有一个 Nacos 官方的 `naming_client.INamingClient` 实例。 * `configClient`: 持有一个 Nacos 官方的 `config_client.IConfigClient` 实例。 * `config`: 保存用于初始化这两个客户端的配置信息。 * **职责**: * 实现 `RemoteClient` 接口的所有方法。 * 其方法的内部逻辑非常简单:将调用**代理 (delegate)** 给内部持有的 `namingClient` 或 `configClient` 去完成实际工作,并对返回结果进行必要的格式转换,使其符合我们自己定义的 `Instance` 等中立结构。 ### 2. MCP Server 适配器 (`pkg/adapter/mcpserver`) 本层是连接**远程数据源**和**网关核心业务逻辑**的桥梁,负责将从 `pkg/remote` 获取的原始配置数据,转化为网关内部可以消费的业务对象。 #### 2.1 适配器核心 (`MCPServerAdapter`) * **结构**: `MCPServerAdapter` 是一个结构体。 ##### 核心字段: * `remoteClient`: 持有一个 `remote.RemoteClient` 接口实例,它不知道底层是 Nacos 还是其他实现。 * `dynamicRegistry`: 持有一个指向 `DynamicToolRegistry` 的指针,用于将最终的工具配置更新到 MCP 过滤器中。 * `listeners`: 一个 `map`,用于管理所有 `ConfigListener` 实例,方便启停。 ##### 职责: * **初始化**: 通过 `Apply(config)` 方法接收配置,并创建出 `remoteClient` 实例。 * **启动**: `Start()` 方法会启动一个发现循环,扫描 Nacos 中所有需要处理的 MCP 服务,并为每个服务创建一个 `ConfigListener`。 * **停止**: `Stop()` 方法会优雅地停止所有的 `ConfigListener`,并关闭 `remoteClient`。 * **处理变更**: 提供一个内部方法(如 `onConfigUpdate`),供 `ConfigListener` 回调。当收到更新时,它会调用 `ConfigConverter` 进行转换,并将转换后的结果应用到 `DynamicToolRegistry`、`RouterManager` 和 `ClusterManager`。 #### 2.2 配置监听器 (`ConfigListener`) * **结构**: `ConfigListener` 是一个结构体,每个实例负责一个 MCP 服务的完整监听。 ##### 核心字段: * `serviceId`: 标识自己正在监听哪个 MCP 服务。 * `adapter`: 一个指回 `MCPServerAdapter` 的指针,用于回调。 * `stopChan`: 一个 channel,用于接收停止信号。 ##### 职责: * 封装**级联监听**的复杂业务流程。在其 `watch()` 方法中,它会: 1. 首先使用 `remoteClient.ListenConfig` 监听“版本文件”。 2. 在版本的回调中,取消旧监听,并创建对新的“服务规格”和“工具规格”文件的监听。 3. 在服务规格的回调中,使用 `remoteClient.Subscribe` 订阅后端服务的实例列表。 * 当所有相关配置(版本、规格、实例)都获取到或发生变化时,将这些零散的信息**聚合成一个完整的配置快照**,然后调用 `adapter.onConfigUpdate` 方法,将快照传递出去。 #### 2.3 配置转换器 (`ConfigConverter`) * **结构**: `ConfigConverter` 是一个**无状态**的工具类结构体,只包含方法。 ##### 职责: 负责数据模型的转换。 ##### 核心方法: * `ConvertToInternalModels(snapshot AggregatedConfig) (*InternalModels, error)`: * 接收 `ConfigListener` 聚合好的配置快照 `AggregatedConfig`。 * 将快照中的各类 JSON/YAML 字符串,解析并转换为网关内部的强类型业务对象,如 `[]mcpserver.Tool`、`model.Router`、`model.Cluster`。 * 将这些转换好的对象打包成 `InternalModels` 结构体返回。 ### 3. 集成点设计 #### 3.1 与 MCP Filter 集成 (`DynamicToolRegistry`) **目标**: 让 MCP 过滤器能动态地感知工具的变化。 **实现**: * 我们将改造现有的 `ToolRegistry`,使其成为 `DynamicToolRegistry`。 * 它将提供一个**线程安全**的方法:`UpdateTools(adapterId string, tools []mcpserver.Tool)`。 * `MCPServerAdapter` 在转换出新的工具列表后,会调用此方法。`DynamicToolRegistry` 内部会使用读写锁 (`sync.RWMutex`) 来安全地替换内存中的工具列表。 #### 3.2 路由与集群管理集成 **目标**: 动态地创建、更新或删除与 MCP 工具相关的路由和后端集群。 **实现**: * `MCPServerAdapter` 在调用 `ConfigConverter` 得到 `model.Router` 和 `model.Cluster` 对象后,将直接调用网关全局的管理器: * `server.GetRouterManager().AddRouter(router)` * `server.GetClusterManager().SetCluster(cluster)` * 这些管理器已经具备了处理动态更新的能力,我们只需将正确的配置喂给它们即可。 GitHub link: https://github.com/apache/dubbo-go-pixiu/discussions/703#discussioncomment-14261640 ---- This is an automatically sent email for notifications@dubbo.apache.org. To unsubscribe, please send an email to: notifications-unsubscr...@dubbo.apache.org --------------------------------------------------------------------- To unsubscribe, e-mail: notifications-unsubscr...@dubbo.apache.org For additional commands, e-mail: notifications-h...@dubbo.apache.org