diff --git a/internal/capability/mcp/config.go b/internal/capability/mcp/config.go index f9cd784..a887478 100644 --- a/internal/capability/mcp/config.go +++ b/internal/capability/mcp/config.go @@ -9,17 +9,16 @@ import ( "gopkg.in/yaml.v3" ) -// Load reads MCP server configuration from the process environment. It returns -// every configured server; callers filter on Enabled. +// Load 从进程环境读取 MCP server 配置,返回所有已配置的服务器; +// 由调用方按 Enabled 过滤。 func Load() (*Config, error) { return FromEnv(os.Environ()) } -// FromEnv builds a Config from a KEY=value pair slice such as os.Environ() or a -// test fixture. Named servers are read from MCP__* for indexes; the -// unnumbered MCP_* variables describe a single default server. When N is a -// positive index, one server is read per group and scanning stops at the first -// group with no NAME/COMMAND/URL set. +// FromEnv 从形如 os.Environ() 或测试夹具的 KEY=value 键值对切片构建 Config。 +// 带编号的服务器按索引从 MCP__* 读取;不带编号的 MCP_* 变量描述 +// 单台默认服务器。逐组读取(每组一台服务器),扫描在遇到第一组 +// NAME/COMMAND/URL 全空的配置时停止。 func FromEnv(pairs []string) (*Config, error) { env := make(map[string]string, len(pairs)) for _, p := range pairs { @@ -31,7 +30,7 @@ func FromEnv(pairs []string) (*Config, error) { return &Config{Servers: fromEnvMap(env)}, nil } -// FromYAML parses a YAML document describing MCP servers, for example: +// FromYAML 解析描述 MCP server 的 YAML 文档,例如: // // servers: // - name: calc @@ -48,7 +47,7 @@ func FromYAML(data []byte) (*Config, error) { return &Config{Servers: doc.Servers}, nil } -// fromEnvMap builds the server list from a resolved environment map. +// fromEnvMap 从已解析的环境变量 map 构建服务器列表。 func fromEnvMap(env map[string]string) []MCPConfig { var servers []MCPConfig if cfg, ok := readOne(env, "MCP"); ok { @@ -64,8 +63,8 @@ func fromEnvMap(env map[string]string) []MCPConfig { return servers } -// readOne reads a single MCPConfig from env using the given variable prefix -// (e.g. "MCP" or "MCP_0"). It reports ok=false when no identifying field is set. +// readOne 用给定的变量前缀(如 "MCP" 或 "MCP_0")从环境读取一台 MCPConfig; +// 没有任何标识字段时返回 ok=false。 func readOne(env map[string]string, prefix string) (MCPConfig, bool) { p := prefix if p == "" { @@ -88,8 +87,7 @@ func readOne(env map[string]string, prefix string) (MCPConfig, bool) { }, true } -// splitArgs splits a comma-separated args value, trimming spaces and empty -// entries. +// splitArgs 拆分逗号分隔的 args 值,去掉空白与空项。 func splitArgs(raw string) []string { raw = strings.TrimSpace(raw) if raw == "" { @@ -105,7 +103,7 @@ func splitArgs(raw string) []string { return out } -// parseBool parses a boolean value, defaulting to def on empty or invalid input. +// parseBool 解析布尔值;输入为空或非法时返回默认值 def。 func parseBool(raw string, def bool) bool { raw = strings.TrimSpace(raw) if raw == "" { diff --git a/internal/capability/mcp/registry.go b/internal/capability/mcp/registry.go index bb58bbd..1bed1c0 100644 --- a/internal/capability/mcp/registry.go +++ b/internal/capability/mcp/registry.go @@ -10,8 +10,8 @@ import ( "git.yeij.top/AskaEth/Cyrene_v2/internal/capability/registry" ) -// Registry connects an MCP client and auto-registers its discovered tools into -// the shared capability registry, making them available to every character. +// Registry 连接一台 MCP 客户端,把自动发现的工具注册进共享的 capability +// registry,使所有角色都能使用。 type Registry struct { reg *registry.Registry mcp *Client @@ -21,11 +21,10 @@ type Registry struct { closed bool } -// NewRegistry builds a Registry that registers cfg's tools into reg. Options -// apply to the underlying Client (logger, injected transport). It is named -// NewRegistry rather than New because this package already exports New for -// Client. A tool-list-changed handler is wired automatically so the registry -// re-syncs when the server announces tools/list_changed. +// NewRegistry 构建一个 Registry,把 cfg 的工具注册进 reg。opts 作用在底层 +// Client 上(日志器、注入的传输)。之所以叫 NewRegistry 而不是 New,是因为 +// 本包已为 Client 导出了 New。这里会自动接上工具清单变更回调, +// 服务器发 tools/list_changed 时 registry 会重新同步。 func NewRegistry(reg *registry.Registry, cfg MCPConfig, opts ...Option) *Registry { r := &Registry{reg: reg} opts = append(opts, WithToolListChangedHandler(r.refresh)) @@ -35,8 +34,7 @@ func NewRegistry(reg *registry.Registry, cfg MCPConfig, opts ...Option) *Registr return r } -// Register connects the MCP server, discovers its tools, and registers each one -// into the underlying registry. +// Register 连接 MCP 服务器、发现其工具,并把每把工具注册进底层 registry。 func (r *Registry) Register(ctx context.Context) error { if r.reg == nil { return fmt.Errorf("mcp registry: nil registry") @@ -64,12 +62,10 @@ func (r *Registry) Register(ctx context.Context) error { return nil } -// refresh re-syncs the registered tool set with the server after a -// notifications/tools/list_changed notification. It re-discovers the current -// tools and applies only the diff: it removes names that are gone and registers -// newly appeared ones, so tools registered by other providers (which collide by -// name) are preserved. It is invoked (off the transport read path) by the -// client's tool-list-changed handler and coalesced by the client. +// refresh 在收到 notifications/tools/list_changed 通知后,把已注册工具集与 +// 服务器重新对齐。它重新发现当前工具并只应用差异:移除已消失的名字、 +// 注册新出现的名字,因此其它提供者注册的同名工具(名字冲突)会被保留。 +// 它由客户端的工具清单变更回调调用(不在传输读路径上),并由客户端合并触发。 func (r *Registry) refresh() { if r.reg == nil { return @@ -91,9 +87,8 @@ func (r *Registry) refresh() { return } - // Drop names the server no longer exposes. Tools registered by other - // providers were skipped at registration time and are not in r.names, so they - // are never removed here. + // 丢弃服务器不再暴露的名字。其它提供者注册的工具在注册时就被跳过、 + // 不在 r.names 里,因此这里永远不会把它们删掉。 kept := r.names[:0] for _, name := range r.names { if !incoming[name] { @@ -106,8 +101,8 @@ func (r *Registry) refresh() { } r.names = kept - // Register newly appeared tools. Skips names already present (own or - // foreign) so a name collision with another provider is not doubled. + // 注册新出现的工具。跳过已存在的名字(无论是自己的还是外来的), + // 避免与其它提供者同名时重复注册。 existing := make(map[string]bool, len(r.names)) for _, name := range r.names { existing[name] = true @@ -127,16 +122,16 @@ func (r *Registry) refresh() { r.log.Info("mcp tools refreshed", "name", r.mcp.cfg.Name, "count", len(r.names)) } -// ToolNames returns a copy of the tool names this registry registered, in -// registration order. It is empty before Register succeeds. +// ToolNames 返回本 registry 注册过的工具名副本(按注册顺序)。 +// Register 成功之前为空。 func (r *Registry) ToolNames() []string { r.mu.Lock() defer r.mu.Unlock() return append([]string(nil), r.names...) } -// Unregister removes every tool this registry previously registered and closes -// the underlying client. It is safe to call multiple times. +// Unregister 移除本 registry 之前注册的全部工具,并关闭底层客户端。 +// 可安全重复调用。 func (r *Registry) Unregister(ctx context.Context) error { r.mu.Lock() names := r.names