// Package tools — доменный слой сервера: конфиг, Manager и инструменты. // Замените содержимое на свою задачу; каркасные хелперы берите из toolkit. package tools import ( "context" "encoding/json" "os" "strings" "git.totmin.ru/en2zmax/forge-toolkit" "github.com/modelcontextprotocol/go-sdk/mcp" ) // Config — доменный конфиг сервера (пример). Замените поля на свои. type Config struct { Greeting string `json:"greeting"` } // LoadConfig читает config.json и разворачивает ${VAR}. Пустые обязательные // поля лучше отвергать здесь (fail-closed), а не в обработчике. func LoadConfig(path string) (*Config, error) { raw, err := os.ReadFile(path) if err != nil { return nil, err } var cfg Config if err := json.Unmarshal(toolkit.Expand(raw), &cfg); err != nil { return nil, err } if strings.TrimSpace(cfg.Greeting) == "" { cfg.Greeting = "hello" } return &cfg, nil } // Manager — доменное состояние сервера. Инструменты вызываются конкурентно, // поэтому изменяемое состояние держите под sync.RWMutex. type Manager struct { cfg *Config } // NewManager создаёт Manager. func NewManager(cfg *Config) *Manager { return &Manager{cfg: cfg} } // Close освобождает ресурсы (соединения, файлы). В каркасе — no-op. func (m *Manager) Close() {} // RegisterAll регистрирует инструменты сервера. func RegisterAll(s *mcp.Server, mgr *Manager) { mcp.AddTool(s, &mcp.Tool{ Name: "greet", Description: "Приветствие по имени. Без побочных эффектов.", InputSchema: toolkit.Schema(map[string]any{ "name": toolkit.StrProps("имя", false), }, nil), }, func(_ context.Context, req *mcp.CallToolRequest, _ struct{}) (*mcp.CallToolResult, any, error) { name := toolkit.GetString(toolkit.RequestArgs(req), "name", "world") return toolkit.Text(mgr.cfg.Greeting + ", " + name + "!"), nil, nil }) }