Skip to main content
Glama
README.md
# XfeaturesControlMCP

Автономный MCP-сервер для управления игровыми серверами через панель **Calagopus**. ИИ-клиент (Claude Code, Claude Desktop, Cursor, VS Code, Codex CLI) видит ваши серверы, читает логи и файлы, правит конфиги, ищет и ставит плагины и моды с Modrinth и CurseForge. Права ограничены API-ключом пользователя и его правами на сервере: панель сама проверяет каждое действие.

Это не расширение панели: отдельная программа на TypeScript, которая ходит в **Client API** панели по `Authorization: Bearer <ключ>`. Набор инструментов, схемы и тексты совпадают со встроенным MCP-аддоном панели (`addons.calagopus.mcpserver`), поэтому промпты для ИИ работают с обоими.

## Запуск

Нужен Node.js ≥ 20.

```bash
git clone https://github.com/biggikos/XfeaturesControlMCP.git
cd XfeaturesControlMCP
npm ci && npm run build
```

Два режима:

| Режим | Команда | Когда |
|---|---|---|
| **stdio** (по умолчанию) | `node dist/index.js` | локально: клиент сам запускает процесс (Claude Desktop, Cursor, ...). Ключ берётся из `PANEL_API_KEY`. |
| **Streamable HTTP** | `node dist/index.js --http` | общий сервер: один процесс обслуживает многих пользователей, у каждого свой ключ в заголовке `Authorization` каждого запроса. Эндпоинт `/mcp`. |

После публикации в npm станет доступен `npx -y xfeatures-control-mcp`.

## Настройка

Переменные окружения (или JSON-файл, путь в `XFEATURES_CONFIG`; окружение главнее файла):

| Переменная | Значение |
|---|---|
| `PANEL_URL` | адрес панели, например `https://panel.example.com` (обязательно) |
| `PANEL_API_KEY` | API-ключ панели (только stdio; в HTTP ключ приходит с запросом) |
| `CURSEFORGE_API_KEY` | включает поиск и установку с CurseForge (без него только Modrinth) |
| `TOOL_GROUPS_OFF` | выключенные группы через запятую: `inspect`, `files_read`, `files_write`, `power`, `console`, `content_read`, `content_write` |
| `ALLOW_KILL` | `true`, чтобы разрешить `kill` в `power` (по умолчанию выключено) |
| `BACKEND` | `auto` (по умолчанию), `native`, `addon`: см. ниже |
| `CONNECTION_NAME` | `serverInfo.name`, по умолчанию `xfeatures-control` |
| `HTTP_HOST`, `HTTP_PORT` | HTTP-режим, по умолчанию `127.0.0.1:3333` |
| `ALLOWED_ORIGINS` | какие `Origin` разрешены в HTTP-режиме (по умолчанию ни один: MCP-клиенты его не шлют, браузеры шлют всегда) |

Опечатка в имени группы даёт ошибку запуска, а не молча оставляет группу включённой. Выключенная группа пропадает из `tools/list` и отклоняется при вызове.

**Ключ.** Создайте его в панели: Аккаунт → API-ключи. Ключ нигде не логируется и не попадает в ответы инструментов и ошибки.

**HTTP-режим слушает `127.0.0.1`.** Чтобы открыть его наружу, задайте `HTTP_HOST` и ставьте перед ним TLS-прокси: ключ панели идёт в заголовке, по обычному HTTP его нельзя гонять через сеть.

### BACKEND

- `native`: свой код ходит в Client API панели. Предсказуемо, ничего не пробует.
- `addon`: всё пересылается встроенному MCP-аддону панели (`/api/client/extensions/addons.calagopus.mcpserver/mcp`). Если аддон не установлен, будет ошибка.
- `auto`: если аддон есть и включён, пересылка ему (действует политика админа панели), иначе `native`. Наши `TOOL_GROUPS_OFF` и `ALLOW_KILL` работают поверх и могут только сужать.

## Подключение к клиенту

Готовые конфигурации печатает сам сервер (ключ всегда заглушка `<panel-api-key>`):

```bash
PANEL_URL=https://panel.example.com node dist/index.js --snippet claude-code
node dist/index.js --snippet claude-desktop --transport http
node dist/index.js --prompt          # текст, который можно отдать ИИ-агенту: он подключится сам
```

Клиенты: `claude-code`, `claude-desktop`, `cursor`, `vscode`, `codex`, `other`. Флаги: `--transport stdio|http`, `--name`, `--package` (что запускает `npx`).

Например, Claude Code, stdio:

```bash
claude mcp add xfeatures -e PANEL_URL=https://panel.example.com -e PANEL_API_KEY=<panel-api-key> -- npx -y xfeatures-control-mcp
```

Claude Code, HTTP:

```bash
claude mcp add --transport http xfeatures http://127.0.0.1:3333/mcp --header "Authorization: Bearer <panel-api-key>"
```

## Инструменты

`servers`, `server_info`, `logs`, `power`, `command`, `files` (list/read/grep), `file_write` (целиком или find/replace), `content_search`, `content_info`, `content_installed`, `content_install`, `content_updates`, `content_remove`, `describe`.

Каждый помечен `readOnlyHint`/`destructiveHint`. Собственных подтверждений нет: их запрашивает клиент по своему режиму.

Экономия токенов заложена в дизайн: 14 инструментов с короткими описаниями (подробности через `describe`), ответы компактным текстом (TSV) с потолком 24 КБ, сервер указывается по имени, загрузчик и версия Minecraft определяются сами, логи и файлы читаются окнами и через `grep`, поиск возвращает одну строку на результат с объединением Modrinth и CurseForge, `content_install` разрешает всё дерево зависимостей за один вызов, `dry_run` показывает план.

**Зависимости и версии.** Выбирается новейший релиз, совместимый с загрузчиком и версией (Paper берёт paper/spigot/bukkit, Purpur ещё и purpur, Quilt берёт fabric). Обязательные зависимости ставятся сами, несовместимые с установленным блокируют установку. `content_updates{target_mc}` показывает, что сломается при смене версии Minecraft. `content_remove` не удаляет jar, который требует другой установленный.

## Безопасность

- Запретные пути (`.env`, `.ssh`, ключи, `/proc`, `/sys`, `/dev`, сокеты) отсекаются до запроса к панели.
- Файлы скачивает сама нода через `files/pull`; разрешены только `https` на CDN Modrinth и CurseForge (по разобранному имени хоста, без логина в URL).
- Лимиты: запись целиком до 512 КиБ, правка `find`/`replace` до 2 МиБ (файл не UTF-8 или обрезанный не правится), ответ до 24 КБ.
- Регулярки из `grep` проверяются на типовые шаблоны катастрофического отката (см. ограничения).
- Ошибки инструментов возвращаются как результат `isError`, а не как ошибка протокола: модель читает сообщение и может исправиться.

## Отличия от аддона панели

Совпадают: 14 инструментов, их схемы, аннотации, `INSTRUCTIONS`, тексты `describe`, группы, правила совместимости загрузчиков. Это проверяет тест `test/parity.test.ts`, который разбирает исходники аддона (запуск ниже).

| Что | Аддон | Здесь | Почему |
|---|---|---|---|
| Максимум строк в `logs` | 2000 | 1000 | потолок Client API |
| Размер страницы `files list` | до 500 | до 100 | потолок панели |
| Фильтр `errors` | `\bException\b` | `Exception\b` | аддон пропускает `InvalidPluginException` |
| Регулярки | линейный движок Rust | JS `RegExp` с защитой | у JS нет безопасного движка |
| Файл больше 2 МБ | обрезает молча | пишет пометку | модель должна знать |
| Лимит сервера 0 | «of 0 MiB» | «unlimited» | понятнее |
| Состояние в `servers` | из ресурсов ноды | плюс `suspended` и статус установки | видно без запроса к ноде |
| Ключ CurseForge | из БД панели | `CURSEFORGE_API_KEY` | автономному серверу к БД доступа нет |
| Проверка хоста загрузки | префикс строки | разбор URL; в плане как `!` | префикс пропускает `cdn.modrinth.com@evil.example` |
| Идентификатор `mr:x =cf:1` | ищет «x =cf:1» | берётся первое слово | модель может вернуть строку поиска целиком |
| `content_remove` с `../` в имени | чистит путь и удаляет | отказывает | иначе удалится другой файл |
| `file_write` find/replace | Wings читает с лимитом | отказ для обрезанного и не UTF-8 файла | иначе запись затрёт хвост или бинарные данные |
| SHA-1 jar | один пакетный запрос к ноде | один запрос на jar (по 8 параллельно) | пакетного эндпоинта у Client API нет |
| Имя по умолчанию | `calagopus` | `xfeatures-control` | |

Не перенесено: Hytale (в образце вне ядра MCP), административные страницы и настройки панели (`public_url`, `enabled`, эндпоинты `/config` и `/access`), собственные проверки прав (панель сама проверяет каждый вызов).

## Ограничения

- **Скачивание асинхронное.** «installed N/M» значит, что нода приняла задачи `files/pull`, а не что файлы уже скачаны. Результат видно через `content_installed` через несколько секунд.
- **Замена не откатывается.** Старый jar удаляется до скачивания нового; сбой сети после удаления оставит сервер без плагина.
- **Опознаются только jar, известные Modrinth.** Для остальных обновления недоступны; установленное с CurseForge определяется только по имени файла.
- **Защита от тяжёлых регулярок эвристическая.** Она отсекает типовые шаблоны (`(a+)+`), но не гарантирует защиту от любых; худший случай: зависание одного запроса.
- **Логи ограничены 1000 строк** окном `lines` панели, поэтому `errors` и `grep` ищут в последних 1000 строках.

## Разработка

```bash
npm ci
npm run typecheck
npm test                 # юнит-тесты; сети нет: фикстуры Modrinth/CurseForge и поддельная панель
```

Сверка с исходниками аддона (нужен клонированный `calagopus-addons`):

```bash
ADDON_SRC=/path/to/calagopus-addons/mcp/backend-extensions/addons_calagopus_mcpserver/src npm test
```

Структура: `src/tools/` (каталог и обработчики), `src/content/` (поиск, резолвер зависимостей, установка, обновления), `src/panel/` (клиент Client API и прокси к аддону), `src/transport/http.ts`, `src/snippets.ts`.

## Лицензия

MIT