package mcp import ( "fmt" "os" "strconv" "strings" "gopkg.in/yaml.v3" ) // Load 从进程环境读取 MCP server 配置,返回所有已配置的服务器; // 由调用方按 Enabled 过滤。 func Load() (*Config, error) { return FromEnv(os.Environ()) } // 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 { k, v, ok := strings.Cut(p, "=") if ok { env[k] = v } } return &Config{Servers: fromEnvMap(env)}, nil } // FromYAML 解析描述 MCP server 的 YAML 文档,例如: // // servers: // - name: calc // command: mcp-calc // args: [--stdio] // enabled: true func FromYAML(data []byte) (*Config, error) { var doc struct { Servers []MCPConfig `yaml:"servers"` } if err := yaml.Unmarshal(data, &doc); err != nil { return nil, fmt.Errorf("mcp config: %w", err) } return &Config{Servers: doc.Servers}, nil } // fromEnvMap 从已解析的环境变量 map 构建服务器列表。 func fromEnvMap(env map[string]string) []MCPConfig { var servers []MCPConfig if cfg, ok := readOne(env, "MCP"); ok { servers = append(servers, cfg) } for i := 0; ; i++ { cfg, ok := readOne(env, "MCP_"+strconv.Itoa(i)) if !ok { break } servers = append(servers, cfg) } return servers } // readOne 用给定的变量前缀(如 "MCP" 或 "MCP_0")从环境读取一台 MCPConfig; // 没有任何标识字段时返回 ok=false。 func readOne(env map[string]string, prefix string) (MCPConfig, bool) { p := prefix if p == "" { p = "MCP" } name := env[p+"_NAME"] command := env[p+"_COMMAND"] url := env[p+"_URL"] transp := env[p+"_TRANSPORT"] if name == "" && command == "" && url == "" { return MCPConfig{}, false } return MCPConfig{ Name: name, Command: command, Args: splitArgs(env[p+"_ARGS"]), URL: url, TransportType: transp, Enabled: parseBool(env[p+"_ENABLED"], false), }, true } // splitArgs 拆分逗号分隔的 args 值,去掉空白与空项。 func splitArgs(raw string) []string { raw = strings.TrimSpace(raw) if raw == "" { return nil } parts := strings.Split(raw, ",") out := make([]string, 0, len(parts)) for _, p := range parts { if t := strings.TrimSpace(p); t != "" { out = append(out, t) } } return out } // parseBool 解析布尔值;输入为空或非法时返回默认值 def。 func parseBool(raw string, def bool) bool { raw = strings.TrimSpace(raw) if raw == "" { return def } b, err := strconv.ParseBool(strings.ToLower(raw)) if err != nil { return def } return b }