first commit
This commit is contained in:
@@ -0,0 +1,36 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"git.totmin.ru/en2zmax/forge-toolkit"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
// Адаптеры к forge-toolkit. Локальные имена держим короткими, чтобы объявления
|
||||
// инструментов читались как схема, а не как вызов библиотеки. Если тулкит
|
||||
// сменит сигнатуры — правится только этот файл.
|
||||
|
||||
func schema(props map[string]any, required []string) map[string]any {
|
||||
return toolkit.Schema(props, required)
|
||||
}
|
||||
|
||||
func strProps(desc string, required bool, enum ...string) map[string]any {
|
||||
return toolkit.StrProps(desc, required, enum...)
|
||||
}
|
||||
|
||||
func intProps(desc string, required bool) map[string]any {
|
||||
return toolkit.IntProps(desc, required)
|
||||
}
|
||||
|
||||
func requestArgs(req *mcp.CallToolRequest) map[string]any { return toolkit.RequestArgs(req) }
|
||||
|
||||
func getString(m map[string]any, key, def string) string { return toolkit.GetString(m, key, def) }
|
||||
|
||||
func requireString(m map[string]any, key string) (string, error) {
|
||||
return toolkit.RequireString(m, key)
|
||||
}
|
||||
|
||||
func getInt(m map[string]any, key string, def int) int { return toolkit.GetInt(m, key, def) }
|
||||
|
||||
func textResult(s string) *mcp.CallToolResult { return toolkit.Text(s) }
|
||||
|
||||
func errorResult(msg string) *mcp.CallToolResult { return toolkit.Error(msg) }
|
||||
@@ -0,0 +1,201 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"forge-tools-lexicomai/internal/lexicomai"
|
||||
|
||||
"git.totmin.ru/en2zmax/forge-toolkit"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
// registerInstall — мутации (M3–M5): установка, обновление, удаление, база,
|
||||
// конфигурация, лицензия, управление службой. Все через addAction (forge-probe)
|
||||
// → хост применяет политику approval; домен дополнительно проверяет
|
||||
// read_only/allow_mutate.
|
||||
func registerInstall(r *registrar) {
|
||||
r.addAction("service_install",
|
||||
"Установка продукта на машину (асинхронно, возвращает id). Плюс последняя версия в ветке.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
"version": strProps("Версия (например 7.012); пусто = последняя", false),
|
||||
"branch": strProps("release или beta (default release)", false, "release", "beta"),
|
||||
}, []string{"product"}),
|
||||
patternsFor("install"),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
id, err := r.m.Install(ctx, getString(args, "alias", ""), p,
|
||||
getString(args, "version", ""), getString(args, "branch", "release"))
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult("install started, id=" + id), nil
|
||||
})
|
||||
|
||||
r.add("service_install_status",
|
||||
"Прогресс установки по id (service_install). Read-only.",
|
||||
schema(map[string]any{
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
"id": strProps("id установки", true),
|
||||
}, []string{"id"}),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
id, err := requireString(args, "id")
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
sess, ok := r.m.Session(id)
|
||||
if !ok {
|
||||
return errorResult("install session " + id + " not found (id is per-process)"), nil
|
||||
}
|
||||
t, err := targetArg(r.m, args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
out, err := r.m.InstallStatus(ctx, t, sess)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult(out), nil
|
||||
})
|
||||
|
||||
r.addAction("service_uninstall",
|
||||
"Удаление продукта с машины (инсталлятор --uninstall).",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
}, []string{"product"}),
|
||||
patternsFor("uninstall"),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
out, err := r.m.Uninstall(ctx, getString(args, "alias", ""), p)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult(out), nil
|
||||
})
|
||||
|
||||
r.addAction("service_update",
|
||||
"Обновление продукта до последней версии в ветке (backup инсталлятором).",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
"branch": strProps("release или beta (default release)", false, "release", "beta"),
|
||||
}, []string{"product"}),
|
||||
patternsFor("update"),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
id, err := r.m.Install(ctx, getString(args, "alias", ""), p, "", getString(args, "branch", "release"))
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult("update started, id=" + id), nil
|
||||
})
|
||||
|
||||
r.addAction("base_ensure",
|
||||
"Создание минимальной базы /opt/pve на машине (идемпотентно).",
|
||||
schema(map[string]any{
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
}, nil),
|
||||
func(map[string]any) ([]string, []string) { return []string{"lexicomai base"}, nil },
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
out, err := r.m.BaseEnsure(ctx, getString(args, "alias", ""))
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult(out), nil
|
||||
})
|
||||
|
||||
r.addAction("service_config_set",
|
||||
"Изменение ключей config.json (точечный путь, например logs.level) + рестарт.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
"key": strProps("Ключ (точечный путь, например logs.level)", true),
|
||||
"value": strProps("Новое значение (строка)", true),
|
||||
}, []string{"product", "key", "value"}),
|
||||
patternsFor("config"),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
key, err := requireString(args, "key")
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
out, err := r.m.ConfigSet(ctx, getString(args, "alias", ""), p, map[string]any{key: getString(args, "value", "")})
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult(out), nil
|
||||
})
|
||||
|
||||
r.addAction("license_apply",
|
||||
"Запись license.json и проверка через /license/check.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
"license": strProps("JSON лицензии (service/expire/licenses/key)", true),
|
||||
}, []string{"product", "license"}),
|
||||
patternsFor("license"),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
lic, err := requireString(args, "license")
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
out, err := r.m.LicenseApply(ctx, getString(args, "alias", ""), p, lic)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult(out), nil
|
||||
})
|
||||
|
||||
r.addAction("service_restart",
|
||||
"Перезапуск службы продукта (systemctl restart).",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
}, []string{"product"}),
|
||||
patternsFor("restart"),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
out, err := r.m.ServiceControl(ctx, getString(args, "alias", ""), p, "restart")
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult(out), nil
|
||||
})
|
||||
}
|
||||
|
||||
// patternsFor строит permission-паттерн «lexicomai <action> <product>».
|
||||
func patternsFor(action string) toolkit.PatternsFn {
|
||||
return func(args map[string]any) ([]string, []string) {
|
||||
p := getString(args, "product", "")
|
||||
return []string{"lexicomai " + action + " " + p}, nil
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,255 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"forge-tools-lexicomai/internal/lexicomai"
|
||||
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
// Общие помощники обработчиков: нормализация аргументов product/alias и
|
||||
// превращение доменного значения в результат инструмента.
|
||||
|
||||
// productArg читает обязательный аргумент product и нормализует его
|
||||
// (нижний регистр + проверка, что продукт поддерживается).
|
||||
func productArg(args map[string]any) (string, error) {
|
||||
p, err := requireString(args, "product")
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return lexicomai.NormalizeProduct(p)
|
||||
}
|
||||
|
||||
// targetArg резолвит машину по alias (пустой alias — «по умолчанию»).
|
||||
func targetArg(m *lexicomai.Manager, args map[string]any) (*lexicomai.Target, error) {
|
||||
alias := getString(args, "alias", "")
|
||||
return m.Target(alias)
|
||||
}
|
||||
|
||||
func (r *registrar) run(ctx context.Context, req *mcp.CallToolRequest, fn func(*lexicomai.Target) (string, error)) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
t, err := targetArg(r.m, args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
out, err := fn(t)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil // доменная ошибка → модели (recoverable)
|
||||
}
|
||||
return textResult(out), nil
|
||||
}
|
||||
|
||||
// registerInventory — инвентарь и статус (products_list, service_status,
|
||||
// repo_catalog, base_status).
|
||||
func registerInventory(r *registrar) {
|
||||
r.add("products_list",
|
||||
"Инвентарь продуктов по всем машинам конфига: продукт → машина, состояние службы, порт, движок, лицензия, версия. Read-only.",
|
||||
schema(map[string]any{}, nil),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
out, err := r.m.Inventory(ctx)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult(out), nil
|
||||
})
|
||||
|
||||
r.add("service_status",
|
||||
"Краткий статус продукта на машине: unit, порт, движок, venv, состояние, лицензия, версия. Read-only.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании (например ups, spr, cls)", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
}, []string{"product"}),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return r.run(ctx, req, func(t *lexicomai.Target) (string, error) {
|
||||
return r.m.Status(ctx, t, p)
|
||||
})
|
||||
})
|
||||
|
||||
r.add("repo_catalog",
|
||||
"Список версий продукта в репозитории (ветки release/beta). Read-only.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
}, []string{"product"}),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
out, err := r.m.RepoCatalog(ctx, p)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return textResult(out), nil
|
||||
})
|
||||
|
||||
r.add("base_status",
|
||||
"Полнота минимальной базы /opt/pve на машине (.version, bin). Read-only.",
|
||||
schema(map[string]any{
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
}, nil),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
return r.run(ctx, req, func(t *lexicomai.Target) (string, error) {
|
||||
return r.m.BaseStatus(ctx, t)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// registerConfig — конфигурация сервиса (service_config_get).
|
||||
func registerConfig(r *registrar) {
|
||||
r.add("service_config_get",
|
||||
"Читает config.json продукта и сообщает top-level ключи (+ наличие .example). Read-only.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
}, []string{"product"}),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return r.run(ctx, req, func(t *lexicomai.Target) (string, error) {
|
||||
return r.m.ConfigGet(ctx, t, p)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// registerLicense — лицензии (license_get, license_verify).
|
||||
func registerLicense(r *registrar) {
|
||||
r.add("license_get",
|
||||
"Содержимое license.json продукта (service, expire, licenses, key). Read-only.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
}, []string{"product"}),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return r.run(ctx, req, func(t *lexicomai.Target) (string, error) {
|
||||
l, err := r.m.LicenseGet(ctx, t, p)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return licenseText(l), nil
|
||||
})
|
||||
})
|
||||
|
||||
r.add("license_verify",
|
||||
"Проверка лицензии: поля (service/expire/занятость) + GET /license/check для FastAPI-продуктов. Read-only.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
}, []string{"product"}),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return r.run(ctx, req, func(t *lexicomai.Target) (string, error) {
|
||||
return r.m.LicenseVerify(ctx, t, p)
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
// licenseText форматирует лицензию в читаемый вид (ключ — с маской).
|
||||
func licenseText(l *lexicomai.License) string {
|
||||
return "license: service=" + l.Service + " expire=" + l.Expire +
|
||||
" seats=" + itoa(l.Licenses) + " key=" + l.KeyMasked()
|
||||
}
|
||||
|
||||
func itoa(n int) string {
|
||||
return fmt.Sprintf("%d", n)
|
||||
}
|
||||
|
||||
// registerHealth — логи, health, диагностика, поиск ошибок.
|
||||
func registerHealth(r *registrar) {
|
||||
r.add("service_logs",
|
||||
"Хвост журнала systemd-юнита продукта (опц. фильтр grep). Read-only.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
"tail": intProps("Число строк (default 100)", false),
|
||||
"grep": strProps("Подстрока-фильтр (по умолчанию нет)", false),
|
||||
}, []string{"product"}),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
tail := getInt(args, "tail", 100)
|
||||
grep := getString(args, "grep", "")
|
||||
return r.run(ctx, req, func(t *lexicomai.Target) (string, error) {
|
||||
return r.m.Logs(ctx, t, p, tail, grep)
|
||||
})
|
||||
})
|
||||
|
||||
r.add("service_health",
|
||||
"Живой статус + /openapi.json (жив/версия) + /license/check. Read-only.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
}, []string{"product"}),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return r.run(ctx, req, func(t *lexicomai.Target) (string, error) {
|
||||
return r.m.Health(ctx, t, p)
|
||||
})
|
||||
})
|
||||
|
||||
r.add("service_diagnose",
|
||||
"Чек-лист: юнит, процесс, порт, лицензия, база /opt/pve. Read-only.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
}, []string{"product"}),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
return r.run(ctx, req, func(t *lexicomai.Target) (string, error) {
|
||||
return r.m.Diagnose(ctx, t, p)
|
||||
})
|
||||
})
|
||||
|
||||
r.add("errors_search",
|
||||
"Поиск ошибок в журнале продукта за окно (по умолчанию -p err, окно 1h). Read-only.",
|
||||
schema(map[string]any{
|
||||
"product": strProps("Продукт компании", true, lexicomai.DefaultProducts()...),
|
||||
"alias": strProps("Машина (target alias); пусто = по умолчанию", false),
|
||||
"window": strProps("Окно --since, например 1h/24h (default 1h)", false),
|
||||
"level": strProps("Приоритет -p (default err)", false),
|
||||
"pattern": strProps("Regex-фильтр ошибок (default: error|traceback|exception|failed)", false),
|
||||
}, []string{"product"}),
|
||||
func(ctx context.Context, req *mcp.CallToolRequest) (*mcp.CallToolResult, error) {
|
||||
args := requestArgs(req)
|
||||
p, err := productArg(args)
|
||||
if err != nil {
|
||||
return errorResult(err.Error()), nil
|
||||
}
|
||||
window := getString(args, "window", "1h")
|
||||
level := getString(args, "level", "err")
|
||||
pattern := getString(args, "pattern", "")
|
||||
return r.run(ctx, req, func(t *lexicomai.Target) (string, error) {
|
||||
return r.m.Errors(ctx, t, p, window, level, pattern)
|
||||
})
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package tools
|
||||
|
||||
import (
|
||||
"forge-tools-lexicomai/internal/lexicomai"
|
||||
|
||||
"git.totmin.ru/en2zmax/forge-toolkit"
|
||||
"github.com/modelcontextprotocol/go-sdk/mcp"
|
||||
)
|
||||
|
||||
// registrar — тонкая обёртка регистрации: держит сервер и Manager и даёт
|
||||
// доменам лаконичный API. Все схемы — ручные (объявлены явно).
|
||||
type registrar struct {
|
||||
s *mcp.Server
|
||||
m *lexicomai.Manager
|
||||
}
|
||||
|
||||
// add регистрирует read-only/безопасный инструмент (probe не требуется).
|
||||
// inputSchema — уже собранная схема (см. schema(...) с required).
|
||||
func (r *registrar) add(name, desc string, inputSchema map[string]any, h mcp.ToolHandler) {
|
||||
r.s.AddTool(&mcp.Tool{
|
||||
Name: name,
|
||||
Description: desc,
|
||||
InputSchema: inputSchema,
|
||||
}, h)
|
||||
}
|
||||
|
||||
// addAction регистрирует side-effecting инструмент через permission-паттерны:
|
||||
// хост узнаёт паттерн ДО выполнения и применяет политику одобрения. Пока не
|
||||
// используется (M1 — только чтение), но готово для установки/конфига/лицензии
|
||||
// в следующих итерациях.
|
||||
func (r *registrar) addAction(name, desc string, inputSchema map[string]any,
|
||||
patterns toolkit.PatternsFn, h mcp.ToolHandler) {
|
||||
toolkit.RegisterPatternTool(r.s, &mcp.Tool{
|
||||
Name: name,
|
||||
Description: desc,
|
||||
InputSchema: inputSchema,
|
||||
}, patterns, h)
|
||||
}
|
||||
|
||||
// RegisterAll — единая точка регистрации инструментов модуля.
|
||||
//
|
||||
// Каждый следующий функциональный блок добавляется сюда одной строкой,
|
||||
// поэтому каркас разрастается предсказуемо.
|
||||
func RegisterAll(s *mcp.Server, m *lexicomai.Manager) {
|
||||
r := ®istrar{s: s, m: m}
|
||||
|
||||
registerInventory(r)
|
||||
registerConfig(r)
|
||||
registerLicense(r)
|
||||
registerHealth(r)
|
||||
registerInstall(r)
|
||||
}
|
||||
Reference in New Issue
Block a user