Skip to main content
Glama
folexz

remnawave-mcp

by folexz

remnawave-mcp

npm version CI license node

MCP-сервер для API панели Remnawave.

Опубликовано в области @folexz: имя remnawave-mcp без области на npm принадлежит несвязанному проекту, который нацелен на Remnawave 2.7.4 и не работает с 2.8.0+.

npx -y @folexz/remnawave-mcp   # configured via REMNAWAVE_BASE_URL + REMNAWAVE_API_TOKEN_READ/_WRITE

Он покрывает все 205 операций в 28 контроллерах API Remnawave v3.3.2 — пользователи, узлы, хосты, конфигурационные профили, отряды, подписки, плагины узлов, инфраструктурный биллинг, системная статистика — сгенерировано из собственного OpenAPI-документа панели, а не написано вручную. Укажите более новую спецификацию в npm run build-spec — и набор инструментов последует за ней.

Возможности

  • Управляется спецификацией и самообновляется. npm run update-spec загружает новейший OpenAPI-документ из собственной опубликованной копии Remnawave и пересобирает каталог; схема ввода каждого инструмента берётся напрямую из параметров операции и тела запроса. Ничего об API не написано вручную, а при пересборке выводится diff с указанием каждой добавленной, удалённой или переименованной операции, так что обновление версии не может незаметно удалить инструмент.

  • Ограниченная стоимость контекста. 205 типизированных инструментов стоили бы ~39k токенов tools/list на каждый запрос. Профиль по умолчанию предоставляет 5 инструментов (~1.4k токенов) и при этом охватывает все операции — см. Почему не 205 инструментов.

  • Двухтокенная аутентификация с минимальными привилегиями. Токен чтения и опциональный токен записи. GET использует токен чтения; POST/PATCH/PUT/DELETE — токен записи. Без токена записи изменяющие инструменты вообще не регистрируются — сервер физически доступен только для чтения.

  • Защитные механизмы для живой панели. Мутации сериализуются с минимальным интервалом и повторяются с экспоненциальной задержкой, потому что каждая запись конфигурации заставляет панель отправлять конфигурацию на все узлы и перезапускать Xray. Массовые операции и операции удаления дополнительно требуют confirm: true.

  • Встроенные примечания к полям. Приведённые ниже подводные камни прикреплены к затрагиваемым операциям, поэтому они появляются в описании инструмента и в выводе remnawave_describe_operation.

  • Никаких запросов, которые не могут завершиться успехом. 16 конечных точек (auth, passkeys, управление API-токенами) обслуживаются только для вошедшего в систему администраторского JWT и отклоняют API-токены. Они обнаруживаются из спецификации и отклоняются локально с объяснением, а не отправляются.

  • Запасные выходы. remnawave_request_read / remnawave_request_write достигают любого пути, включая недокументированные маршруты и синтаксис запросов, который OpenAPI не может выразить.

Related MCP server: mcp-remnawave

Требования

  • Node.js ≥ 18

  • Панель Remnawave (3.x), доступная по HTTPS

  • API-токен из панели: Настройки → API-токены. Remnawave 3.x поддерживает токены с областями — создайте один с правами на чтение и, если нужны изменения, второй с правами на запись.

Установка

Быстрый путь — npx — см. Регистрация в Claude Code. Для запуска из исходников:

git clone https://github.com/folexz/remnawave-mcp.git
cd remnawave-mcp
npm install
npm run build

Конфигурация

Вся конфигурация задаётся переменными окружения, предоставляемыми вашим MCP-хостом. Файлы не читаются.

Переменная

Обязательно

По умолчанию

Описание

REMNAWAVE_BASE_URL

да

—

Адрес панели, например https://panel.example.com (без суффикса /api).

REMNAWAVE_API_TOKEN_READ

да

—

Токен чтения. Псевдоним: REMNAWAVE_API_TOKEN, чтобы работало собственное имя .env панели.

REMNAWAVE_API_TOKEN_WRITE

нет

—

Токен записи. Опустите для работы только на чтение.

REMNAWAVE_TOOL_PROFILE

нет

minimal

minimal | core | full — сколько типизированных инструментов рекламировать.

REMNAWAVE_CONTROLLERS

нет

—

Разделённые запятыми слаги контроллеров; переопределяет выбор типизированных инструментов профиля.

REMNAWAVE_MAX_SCHEMA_BYTES

нет

2000

Схемы ввода больше этого размера сворачиваются в tools/list.

REMNAWAVE_WRITE_MIN_INTERVAL_MS

нет

1500

Минимальный интервал между двумя мутациями.

REMNAWAVE_MAX_RETRIES

нет

3

Повторные попытки при транспортных сбоях, 429 и 5xx.

REMNAWAVE_TIMEOUT_MS

нет

30000

Тайм-аут на запрос.

REMNAWAVE_SKIP_CONFIRM

нет

0

1 убирает требование confirm: true для разрушительных операций.

REMNAWAVE_ALLOW_ADMIN_JWT_OPS

нет

0

1 разрешает 16 конечных точек, доступных только для администраторского JWT (устанавливайте только если ваш токен — администраторский JWT).

Регистрация в Claude Code

Только чтение (рекомендуемый вариант по умолчанию):

claude mcp add remnawave --scope user \
  --env REMNAWAVE_BASE_URL=https://panel.example.com \
  --env REMNAWAVE_API_TOKEN_READ=your_read_token \
  -- npx -y @folexz/remnawave-mcp@latest

С включёнными мутациями и типизированными инструментами для повседневных контроллеров:

claude mcp add remnawave --scope user \
  --env REMNAWAVE_BASE_URL=https://panel.example.com \
  --env REMNAWAVE_API_TOKEN_READ=your_read_token \
  --env REMNAWAVE_API_TOKEN_WRITE=your_write_token \
  --env REMNAWAVE_TOOL_PROFILE=core \
  -- npx -y @folexz/remnawave-mcp@latest

@latest заставляет npx разрешать самую новую опубликованную версию при каждом запуске. Чтобы запустить локальную сборку, замените команду на node /absolute/path/to/remnawave-mcp/dist/index.js.

Регистрация в Claude Desktop / других MCP-клиентах

{
  "mcpServers": {
    "remnawave": {
      "command": "npx",
      "args": ["-y", "@folexz/remnawave-mcp@latest"],
      "env": {
        "REMNAWAVE_BASE_URL": "https://panel.example.com",
        "REMNAWAVE_API_TOKEN_READ": "your_read_token"
      }
    }
  }
}

Почему не 205 инструментов

tools/list повторно отправляется модели на каждый запрос, поэтому его сериализованный размер — постоянный налог на контекст. Измерено на этой спецификации (npx tsx scripts/tool-stats.ts):

Профиль

Инструменты (чтение+запись)

tools/list

≈ токенов

Инструменты (только чтение)

≈ токенов

minimal

5

5.6 KB

~1.4k

4

~1.2k

core

91

71 KB

~17.8k

38

~5.9k

full

210

156 KB

~39k

92

~13.9k

DTO Remnawave — причина, по которой full так дорог: один разыменованный объект хоста сам по себе занимает ~30 КБ JSON Schema, потому что он включает все варианты входящих и безопасности.

Поэтому сервер не выбирает между «один инструмент на операцию» и «один грубый диспетчер» — он поставляет оба варианта и позволяет профилю решать, сколько рекламировать:

  1. Каталожные инструменты (всегда включены, 3 инструмента). remnawave_list_operations просматривает и ищет в каталоге и возвращает одну компактную строку на операцию; remnawave_describe_operation возвращает полную JSON Schema плюс примечания к полям для одной операции; remnawave_call выполняет любую из 205 по имени. Обычный цикл — список → описание → вызов, и он стоит те же 1.4k токенов независимо от размера API. Это та же идея ленивой загрузки, которую использует агентский каркас, когда откладывает схемы инструментов.

  2. Типизированные инструменты (выбираются профилем). Один сгенерированный инструмент на операцию для контроллеров, с которыми вы реально работаете — core покрывает пользователей, узлы, хосты, конфигурационные профили, внутренние отряды, систему и два контроллера массовых действий; full покрывает всё; minimal — ничего. Схемы, превышающие REMNAWAVE_MAX_SCHEMA_BYTES, сохраняют свои поля верхнего уровня и отбрасывают вложенность, со ссылкой на remnawave_describe_operation для полной версии.

  3. Запасные выходы (2 инструмента). Сырой GET и сырая запись для всего, что пропускает спецификация.

Каждый маршрут проходит через один и тот же исполнитель, поэтому шлюз записи, шлюз подтверждения разрушительных операций, шаблонизация путей и обработка запросов ведут себя одинаково, какой бы интерфейс вы ни использовали.

Выбирайте профиль по вкусу: minimal, если у вас подключено много MCP-серверов, core, если хотите иметь повседневные операции в одном вызове, full, если контекст не проблема.

Примечания к полям — поведение, не документированное в спецификации

Все они были проверены на живой панели 3.3.2 и прикреплены к затрагиваемым операциям в описаниях инструментов.

  • PATCH /api/config-profiles — это замена, а не частичное обновление. Тело — {uuid, config}, и config должен быть полным, корректным конфигом Xray. Фрагмент завершается ошибкой A061: Config doesn't have inbounds. Правильная последовательность: GET /api/config-profiles/{uuid} → отредактируйте возвращённый объект config на месте → PATCH всего целиком.

  • Панель не отвечает на 127.0.0.1:3000, даже с самого хоста панели и даже несмотря на то, что docker-proxy слушает там (curl возвращает код выхода 52, пустой ответ). Всегда используйте публичный HTTPS-адрес с Bearer-токеном.

  • Каждый ответ обёрнут в {"response": ...}. Этот сервер разворачивает его, поэтому вывод инструмента — это сам полезный груз.

  • Хост привязывается к профилю через вложенный inbound.configProfileUuid (плюс inbound.configProfileInboundUuid), а не через верхнеуровневый configProfileUuid. Проверено на живых хостах: вложенный присутствует, верхнеуровневый отсутствует.

  • Серия PATCH-запросов выведет панель из строя. Каждая запись конфигурации отправляется на каждый узел и перезапускает там Xray; несколько подряд — и собственный TLS-слушатель панели перестаёт отвечать. Клиент сериализует мутации (REMNAWAVE_WRITE_MIN_INTERVAL_MS, по умолчанию 1500 мс) и повторяет транспортные сбои с экспоненциальной задержкой и джиттером. Не обходите это, запуская массовые обновления параллельно.

  • POST /api/subscription-templates создаёт только пустой шаблон. Содержимое загружается отдельным PATCH /api/subscription-templates. JSON и YAML тела нельзя обновить в одном вызове.

  • serverDescription на хосте ограничено 30 символами (подтверждено maxLength в спецификации). Это также то, что заставляет хост Hysteria2 правильно отображаться в Happ вместо сырого JSON.

  • Шестнадцать конечных точек доступны только для администраторского JWT — все контроллеры auth и passkeys, а также управление API-токенами (GET/POST /api/tokens, DELETE /api/tokens/{uuid}, GET /api/tokens/scopes). Панель отвечает на API-токен там 401/403. Этот сервер обнаруживает их из спецификации и отказывает локально; REMNAWAVE_ALLOW_ADMIN_JWT_OPS=1 снимает ограничение, если настроенный вами токен действительно является администраторским JWT.

  • GET /api/users/stream отвечает JSON, разделённым переводами строк, а не одним документом. Он разбирается в массив записей пользователей, а не возвращается как кусок текста.

  • PATCH /api/hosts действительно является настоящим частичным обновлением — одного {uuid, serverDescription} достаточно. Только конфигурационные профили имеют семантику полной замены. Проверено вживую.

  • Ошибки возвращаются как {message, errorCode}; errorCode (например, A061) включается в текст ошибки этого сервера.

Покрытие инструментов

Каждый контроллер доступен через remnawave_call и запасные выходы. Столбец typed показывает, какие получают отдельные инструменты при REMNAWAVE_TOOL_PROFILE=core.

Controller slug

Операции

Типизированы в core

users

17

да

node-plugins

18

—

nodes

15

да

infra-billing

12

—

internal-squads

12

да

system

12

да

users-bulk-actions

10

да

config-profiles

9

да

external-squads

8

—

auth

7

—

bandwidth-stats

7

—

connections

7

—

hosts

7

да

hwid-user-devices

7

—

subscription-page-configs

7

—

subscriptions

7

—

subscription-template

6

—

node-integrations

5

—

passkeys

5

—

snippets

5

—

api-tokens

4

—

hosts-bulk-actions

4

да

metadata

4

—

public-subscription

3

—

remnawave-settings

2

—

subscription-request-history

2

—

subscription-settings

2

—

keygen

1

—

Итого

205

Запустите remnawave_list_operations на живом сервере, чтобы получить точный актуальный набор.

Примеры

Просмотр и вызов без типизированных инструментов:

// 1. What is there?
{ "tool": "remnawave_list_operations", "arguments": { "controller": "nodes" } }

// 2. What does it take?
{ "tool": "remnawave_describe_operation",
  "arguments": { "operation": "remnawave_post_nodes_uuid_actions_restart" } }

// 3. Do it.
{ "tool": "remnawave_call",
  "arguments": { "operation": "remnawave_post_nodes_uuid_actions_restart",
                 "params": { "uuid": "…" } } }

params, body и query могут также приходить в виде JSON-текста — "params": "{\"uuid\":\"…\"}" — потому что некоторые MCP-клиенты передают аргументы нетипизированных инструментов дословно, не разбирая их. Строка разбирается за вас; строка, не являющаяся JSON, отклоняется с соответствующим сообщением.

Безопасное редактирование профиля конфигурации (ловушка A061):

// Read the whole profile first — PATCH replaces the config wholesale.
{ "tool": "remnawave_call",
  "arguments": { "operation": "remnawave_get_config_profiles_uuid", "params": { "uuid": "…" } } }

// Send the full, edited config back.
{ "tool": "remnawave_call",
  "arguments": { "operation": "remnawave_patch_config_profiles",
                 "params": { "body": { "uuid": "…", "config": { /* complete Xray config */ } } } } }

Синтаксис запросов, который спецификация не может выразить:

{ "tool": "remnawave_request_read",
  "arguments": { "path": "/api/users",
                 "query": { "size": 25, "start": 0,
                            "filters[0][id]": "status", "filters[0][value]": "ACTIVE" } } }

Тестирование

npm run build
npm test            # 50 unit tests + the offline smoke suite
npm run test:unit   # unit tests alone

Модульные тесты покрывают части, которые отказывают тихо: разворачивание $ref через рекурсивные DTO Remnawave, вывод имён инструментов (бюджет длины, детерминизм, обнаружение коллизий), diff каталога, оба шлюза записи, шлюз admin-JWT, схлопывание схем и разбор NDJSON.

Проверки только на чтение против реальной панели

Когда панель доступна, а в окружении есть read-токен, smoke-скрипт также выполняет живые вызовы только на чтение (никогда не мутации):

REMNAWAVE_BASE_URL=https://panel.example.com \
REMNAWAVE_API_TOKEN_READ="$REMNAWAVE_API_TOKEN" \
npm run smoke

Запускайте его там, где токен уже живёт (например, на хосте панели), чтобы секрет никуда не путешествовал. Скрипт печатает формы — типы, имена ключей, длины массивов — и никогда значения полезной нагрузки, так что его вывод можно безопасно вставлять в issue.

Проверки защитных ограждений намеренно указывают на http://127.0.0.1:9, чтобы шлюз, который когда-либо откажет в открытом виде, не смог дотянуться до реальной панели.

Проверка пути записи

Чтения не могут доказать, что маршрутизация токенов, троттлинг, шлюз подтверждения и семантика частичного PATCH действительно работают. scripts/write-check.mjs доказывает это на объектах, к которым никто не привязан, и возвращает на место единственный предсуществующий объект, которого касается:

REMNAWAVE_BASE_URL=https://panel.example.com \
REMNAWAVE_API_TOKEN_READ="$T" REMNAWAVE_API_TOKEN_WRITE="$T" \
node scripts/write-check.mjs --i-understand-this-mutates [--host-uuid <uuid>]

Он создаёт внутренний отряд без входящих подключений и без участников и снова удаляет его, затем перезаписывает serverDescription на одном хосте и восстанавливает исходное значение. Он отказывается запускаться без флага подтверждения и сообщает о ненулевом коде выхода, если что-то осталось.

Против живой панели 3.3.2 он подтвердил: шлюз подтверждения срабатывает на реальном DELETE; частичный PATCH /api/hosts работает; панель отклоняет serverDescription из 31 символа; исходное значение (включая null) проходит туда и обратно; а последовательные мутации были разнесены на 1525 и 1524 мс при настроенном минимуме в 1500 мс.

Локальный просмотр

REMNAWAVE_BASE_URL=https://panel.example.com REMNAWAVE_API_TOKEN_READ=xxx npm run inspect

Обновление спецификации API

Всё об API берётся из одного файла, так что отслеживание нового релиза Remnawave — это одна команда:

npm run update-spec            # fetch the newest spec + rebuild the catalogue
npm run update-spec -- --strict  # additionally fail if any operation disappeared or was renamed
npm run build && npm test      # compile and verify

Откуда берётся спецификация

https://cdn.remna.st/docs/openapi.json — публикуется собственным workflow Build&Push OpenAPI Specs Remnawave на каждом теге апстрима, так что всегда описывает новейший релиз. Переопределите с помощью --url <u> или REMNAWAVE_SPEC_URL, чтобы закрепить другой источник.

Экземпляр панели не является пригодным источником: документация отключена, если развёртывание не включает её, и даже тогда Swagger смонтирован на /backend-tools/swagger, который обычный обратный прокси не маршрутизирует. Проверка живой панели 3.3.2 вернула 404 на каждом обычном пути спецификации.

Загрузка записывается на диск только после того, как она разбирается как документ OpenAPI с непустым paths, так что страница ошибки или captive-портал не могут затереть рабочую спецификацию.

Что проверить после

build-spec сравнивает новый каталог с предыдущим и печатает каждое изменение:

build-spec: Remnawave API v3.4.0 -> 211 operations, 28 controllers, 315 KB
  methods: DELETE=22 GET=90 PATCH=19 POST=78 PUT=2  admin-JWT-only: 16
  diff: API version 3.3.2 -> 3.4.0
  REMOVED — tools that will disappear (1):
    remnawave_get_old_thing  (GET /api/old-thing)
  added (7):
    ...
  • REMOVED / RENAMED — ломающие изменения для тех, чьи промпты или скрипты называют эти инструменты. --strict превращает их в ненулевой код выхода — это флаг, который должна использовать автоматизация.

  • added — безопасно; новые операции сразу доступны через remnawave_call и получают типизированные инструменты, если их контроллер в активном профиле.

  • schema changed — стоит взглянуть на операции, которые вы реально используете.

Затем npm test повторно проверяет, что каталог на диске совпадает со свежей сборкой, что все имена инструментов уникальны и укладываются в бюджет 64 символов, и что защитные ограждения по-прежнему держатся.

Автоматизация

npm run update-spec -- --strict   # exits non-zero on a breaking catalogue change
npm test
npm version minor --no-git-tag-version
git commit -am "chore: Remnawave API 3.4.0" && git push
git tag "v$(node -p "require('./package.json').version")" && git push --tags

Отправленный тег запускает workflow релиза, который перепубликует пакет в npm. Клиенты, зарегистрированные с @folexz/remnawave-mcp@latest, подхватят новую версию при следующем запуске.

Релиз (для мейнтейнеров)

Первая публикация — обязательно вручную

npm не может настроить доверенного издателя для пакета, которого ещё не существует: настройка живёт на странице настроек самого пакета. Это известное, всё ещё открытое ограничение (npm/cli#8544), и оно применимо и к scoped-пакетам. Поэтому версию 0.1.0 нужно публиковать с машины, где выполнен вход:

npm whoami            # must print the account that owns the @folexz scope
npm publish --access public

--access public обязателен: scoped-пакеты по умолчанию ограничены.

Затем переключитесь на релизы без токенов

Как только пакет существует, на npmjs.com → @folexz/remnawave-mcp → Settings → Trusted Publisher добавьте издателя GitHub Actions с репозиторием folexz/remnawave-mcp и workflow release.yml. repository.url в package.json должен точно совпадать с репозиторием GitHub — так и есть.

После этого .github/workflows/release.yml публикует по любому отправленному тегу vX.Y.Z через OIDC — без токена, без секрета, с автоматически прикреплённой provenance:

npm version patch --no-git-tag-version
git commit -am "chore: v0.1.1"
git push
git tag v0.1.1 && git push origin v0.1.1

Workflow переустанавливает зависимости из lockfile, пересобирает, запускает модульные тесты и офлайн smoke-набор и быстро падает, если тег не совпадает с package.json.

Клиенты, зарегистрированные с @folexz/remnawave-mcp@latest, подхватят новую версию при следующем запуске.

Заметки по безопасности

  • Токены читаются только из окружения и никогда не логируются. Логи идут в stderr; stdout — это канал MCP JSON-RPC.

  • Предпочитайте настраивать только REMNAWAVE_API_TOKEN_READ. Мутирующих инструментов не существует без write-токена, так что скомпрометированный или запутавшийся клиент не сможет изменить панель.

  • Эндпоинты подписок возвращают рабочие конфигурации клиентов. Относитесь к их выводу как к секрету.

  • Никогда не коммитьте реальные токены. .env в gitignore; .env.example показывает форму.

Известные ограничения

  • Валидация тела делегирована панели. Этот сервер проверяет только наличие обязательных аргументов и обязательного body; он не проверяет внутреннюю форму тела на соответствие схеме. Это намеренно — панель уже валидирует каждое поле и отвечает точным message + errorCode (например, A061), а дублирование этого локально означало бы поставку валидатора JSON Schema плюс вторую, неизбежно расходящуюся, копию правил. Цена в том, что о некорректном теле вы узнаёте ценой одного round trip.

  • Запасные люки обходят шлюзы отдельных операций. remnawave_request_write сырой по замыслу: он по-прежнему требует write-токен и по-прежнему проходит через троттлинг и логику повторов, но не применяет разрушительный шлюз confirm или проверку admin-JWT, потому что у него нет операции, по которой их можно найти. Предпочитайте remnawave_call, если вам не нужен маршрут, который спецификация не описывает.

  • Инструменты настолько актуальны, насколько актуальна поставляемая спецификация (v3.3.2). Панель на другой минорной версии может открывать маршруты, которые она не описывает; для этого и нужны запасные люки. См. Обновление спецификации API.

  • Эндпоинты admin-JWT закрыты шлюзом, а не реализованы. Этот сервер носит API-токены; он не выполняет вход администратора, не держит сессию и не обновляет JWT. Если вы предоставите admin JWT в качестве токена и установите REMNAWAVE_ALLOW_ADMIN_JWT_OPS=1, эти 16 эндпоинтов станут вызываемыми, но истечение и продление — ваша проблема.

  • Эндпоинт метрик Prometheus с basic-auth не является частью этой спецификации и не открыт.

  • write-check.mjs мутирует. Это инструмент мейнтейнера, исключённый из npm test, и отказывается запускаться без явного флага подтверждения.

Лицензия

MIT — см. LICENSE.

Related MCP Connectors

Related MCP Servers

  • A
    license
    C
    quality
    A
    maintenance
    Enables MCP clients like Claude Code, Claude Desktop, or Cursor to read and manage Remnawave 3.x VPN panel resources — users, nodes, hosts, config profiles, squads, subscription templates, billing, and HWID devices — through the panel's REST API, with contract-driven tool schemas, numeric user IDs, multi-panel config lookup, and an optional readonly mode.
    204
    5 npm
    MIT
  • A
    license
    Not graded
    quality
    A
    maintenance
    Enables managing and observing Technitium DNS Server through MCP, including read-only or read-write tool surfaces, scoped bearer authentication, audit logging, and confirmation gates for destructive operations.
    MIT
  • A
    license
    C
    quality
    B
    maintenance
    Enables managing a Remnawave VPN panel from MCP clients, providing tools for users, nodes, subscriptions, statistics, billing, and system operations, plus resources and prompts for common admin tasks.
    190
    5 npm
    MIT