package tools import ( "context" "omnichannel-mcp/internal/configserver" "github.com/modelcontextprotocol/go-sdk/mcp" ) // release.go — страница «Развёртывание»: файлы схемы, seed/fill, релиз. func registerReleaseTools(s *mcp.Server) { addPatternTool(s, &mcp.Tool{ Name: "save_deployment_files", Description: "Сохранить файлы развёртывания (schema/manifest/prebuild_vars/ip_overrides). Передавай только изменяемые поля.", InputSchema: schema(map[string]any{ "server": serverProp(), "schema": strProps("JSON-схема развёртывания (опционально)", false), "manifest": strProps("JSON-манифест (опционально)", false), "prebuild_vars": strProps("Строка prebuild_vars (опционально)", false), "ip_overrides": strProps("JSON ip_overrides (опционально)", false), }, nil), }, releasePatterns, func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) { args := requestArgs(req) upd := configserver.DeploymentUpdate{ Schema: optionalString(args, "schema"), Manifest: optionalString(args, "manifest"), PrebuildVars: optionalString(args, "prebuild_vars"), IPOverrides: optionalString(args, "ip_overrides"), } if upd.Schema == nil && upd.Manifest == nil && upd.PrebuildVars == nil && upd.IPOverrides == nil { return errorResult("нужно передать хотя бы одно из полей: schema, manifest, prebuild_vars, ip_overrides"), nil } api, res := openAPI(ctx, args, true) if res != nil { return res, nil } defer api.Close() return result(api.SaveDeploymentFiles(ctx, upd)) }) addPatternTool(s, &mcp.Tool{ Name: "seed_hosts", Description: "Создать служебные записи хостов по IP из schema.json. Изменяет БД.", InputSchema: schema(map[string]any{"server": serverProp()}, nil), }, releasePatterns, func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) { args := requestArgs(req) api, res := openAPI(ctx, args, true) if res != nil { return res, nil } defer api.Close() return result(api.SeedHosts(ctx)) }) addPatternTool(s, &mcp.Tool{ Name: "fill_vars", Description: "Заполнить prebuild_vars из schema.json. Изменяет файл конфигурации развёртывания.", InputSchema: schema(map[string]any{"server": serverProp()}, nil), }, releasePatterns, func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) { args := requestArgs(req) api, res := openAPI(ctx, args, true) if res != nil { return res, nil } defer api.Close() v, err := api.FillVars(ctx) return result(v, err) }) addPatternTool(s, &mcp.Tool{ Name: "download_release", Description: "Загрузить релиз. load_images=false — синхронно (пакеты + sync-задачи); true — фоновая загрузка образов (прогресс через release_job). Разрушительно/тяжело: требует confirm=\"true\".", InputSchema: schema(map[string]any{ "server": serverProp(), "load_images": boolProps("Загружать docker-образы в фоне (по умолчанию false)", false), "gitlab_token": strProps("GitLab-токен (опционально; иначе из конфига/env сервера)", false), "confirm": boolProps("Подтверждение операции (обязательно true)", true), }, []string{"confirm"}), }, releasePatterns, func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) { args := requestArgs(req) if res := confirmGate(args, "download_release"); res != nil { return res, nil } api, res := openAPI(ctx, args, true) if res != nil { return res, nil } defer api.Close() ack, err := api.DownloadRelease(ctx, getString(args, "gitlab_token", ""), getBool(args, "load_images", false)) return result(ack, err) }) addPatternTool(s, &mcp.Tool{ Name: "start_services", Description: "Создать задачи запуска сервисов для хостов из schema.json. Изменяет состояние стенда.", InputSchema: schema(map[string]any{"server": serverProp()}, nil), }, releasePatterns, func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) { args := requestArgs(req) api, res := openAPI(ctx, args, true) if res != nil { return res, nil } defer api.Close() return result(api.StartServices(ctx)) }) } // optionalString возвращает указатель на строковый аргумент, если он задан // (в том числе пустой строкой), иначе nil. func optionalString(args map[string]any, key string) *string { if _, ok := args[key]; !ok { return nil } v := getString(args, key, "") return &v }