Skip to main content
Glama
folexz

remnawave-mcp

by folexz

remnawave-mcp

npm version CI license node

Un servidor MCP para la API del panel Remnawave.

Publicado bajo el alcance @folexz: el nombre remnawave-mcp sin alcance en npm pertenece a un proyecto no relacionado que apunta a Remnawave 2.7.4 y no funciona con 2.8.0+.

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

Cubre las 205 operaciones en 28 controladores de la API de Remnawave v3.3.2 — usuarios, nodos, hosts, perfiles de configuración, escuadrones, suscripciones, plugins de nodo, facturación de infraestructura, estadísticas del sistema — generado a partir del propio documento OpenAPI del panel en lugar de escribirse a mano. Apunta una especificación más nueva a npm run build-spec y la superficie de herramientas se actualiza.

Características destacadas

  • Impulsado por especificación y autoactualizable. npm run update-spec obtiene el documento OpenAPI más reciente de la copia publicada por Remnawave y reconstruye el catálogo; el esquema de entrada de cada herramienta proviene directamente de los parámetros y el cuerpo de la solicitud de la operación. Nada de la API está escrito a mano, y la reconstrucción imprime un diff que nombra cada operación añadida, eliminada o renombrada, por lo que un cambio de versión no puede eliminar silenciosamente una herramienta.

  • Costo de contexto acotado. 205 herramientas tipadas costarían ~39k tokens de tools/list en cada solicitud. El perfil predeterminado expone 5 herramientas (~1.4k tokens) y aun así llega a todas las operaciones — ver Por qué no 205 herramientas.

  • Autenticación de mínimo privilegio con dos tokens. Un token de lectura y un token de escritura opcional. GET usa el token de lectura; POST/PATCH/PUT/DELETE usan el token de escritura. Sin un token de escritura, las herramientas de mutación no se registran en absoluto — el servidor es físicamente de solo lectura.

  • Protecciones para un panel en vivo. Las mutaciones se serializan con un intervalo mínimo y se reintentan con retroceso, porque cada escritura de configuración hace que el panel envíe la configuración a todos los nodos y reinicie Xray. Las operaciones masivas y de eliminación además requieren confirm: true.

  • Notas de campo integradas. Los problemas que se indican a continuación se adjuntan a las operaciones que afectan, por lo que aparecen en la descripción de la herramienta y en la salida de remnawave_describe_operation.

  • Sin solicitudes que no puedan tener éxito. 16 endpoints (auth, passkeys, gestión de tokens de API) solo se sirven a un JWT de administrador con sesión iniciada y rechazan los tokens de API. Se detectan desde la especificación y se rechazan localmente con una explicación en lugar de enviarse.

  • Vías de escape. remnawave_request_read / remnawave_request_write llegan a cualquier ruta, incluidas rutas no documentadas y sintaxis de consulta que OpenAPI no puede expresar.

Related MCP server: Remnawave Tools MCP

Requisitos

  • Node.js ≥ 18

  • Un panel Remnawave (3.x) accesible a través de HTTPS

  • Un token de API del panel: Configuración → Tokens de API. Remnawave 3.x admite tokens con alcance: crea uno con alcances de lectura y, si quieres mutaciones, un segundo con alcances de escritura.

Instalación

La vía rápida es npx — ver Registrar con Claude Code. Para ejecutar desde el código fuente:

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

Configuración

Toda la configuración son variables de entorno proporcionadas por tu host MCP. No se leen archivos.

Variable

Requerido

Predeterminado

Descripción

REMNAWAVE_BASE_URL

Origen del panel, p. ej. https://panel.example.com (sin sufijo /api).

REMNAWAVE_API_TOKEN_READ

Token de lectura. Alias: REMNAWAVE_API_TOKEN, para que funcione el nombre .env del propio panel.

REMNAWAVE_API_TOKEN_WRITE

no

Token de escritura. Omitir para ejecutar en modo solo lectura.

REMNAWAVE_TOOL_PROFILE

no

minimal

minimal | core | full — cuántas herramientas tipadas anunciar.

REMNAWAVE_CONTROLLERS

no

Slugs de controladores separados por comas; anula la selección de herramientas tipadas del perfil.

REMNAWAVE_MAX_SCHEMA_BYTES

no

2000

Los esquemas de entrada más grandes que esto se colapsan en tools/list.

REMNAWAVE_WRITE_MIN_INTERVAL_MS

no

1500

Intervalo mínimo entre dos mutaciones.

REMNAWAVE_MAX_RETRIES

no

3

Reintentos en fallos de transporte, 429 y 5xx.

REMNAWAVE_TIMEOUT_MS

no

30000

Tiempo de espera por solicitud.

REMNAWAVE_SKIP_CONFIRM

no

0

1 elimina el requisito de confirm: true en operaciones destructivas.

REMNAWAVE_ALLOW_ADMIN_JWT_OPS

no

0

1 permite los 16 endpoints solo de JWT de administrador (establecer solo si tu token es un JWT de administrador).

Registrar con Claude Code

Solo lectura (predeterminado recomendado):

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

Con mutaciones habilitadas y herramientas tipadas para los controladores cotidianos:

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 hace que npx resuelva la versión publicada más reciente en cada lanzamiento. Para ejecutar una compilación local, reemplaza el comando con node /absolute/path/to/remnawave-mcp/dist/index.js.

Registrar con Claude Desktop / otros clientes 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"
      }
    }
  }
}

Por qué no 205 herramientas

tools/list se reenvía al modelo en cada solicitud, por lo que su tamaño serializado es un impuesto de contexto permanente. Medido en esta especificación (npx tsx scripts/tool-stats.ts):

Perfil

Herramientas (lectura+escritura)

tools/list

≈ tokens

Herramientas (solo lectura)

≈ tokens

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

Los DTO de Remnawave son la razón por la que full es tan costoso: un objeto host desreferenciado es ~30 KB de JSON Schema por sí solo, porque incrusta cada variante de entrada y seguridad.

Entonces el servidor no elige entre "una herramienta por operación" y "un despachador contundente" — incluye ambos, y deja que el perfil decida cuánto se anuncia:

  1. Herramientas de catálogo (siempre activas, 3 herramientas). remnawave_list_operations navega y busca en el catálogo y devuelve una línea compacta por operación; remnawave_describe_operation devuelve el JSON Schema completo más notas de campo para una operación; remnawave_call ejecuta cualquiera de las 205 por nombre. El bucle habitual es listar → describir → llamar, y cuesta los mismos 1.4k tokens sin importar cuán grande sea la API. Esta es la misma idea de carga diferida que usa un harness de agente cuando difiere los esquemas de herramientas.

  2. Herramientas tipadas (seleccionadas por perfil). Una herramienta generada por operación para los controladores con los que realmente trabajas — core cubre usuarios, nodos, hosts, perfiles de configuración, escuadrones internos, sistema y los dos controladores de acciones masivas; full cubre todo; minimal ninguna. Los esquemas que superan REMNAWAVE_MAX_SCHEMA_BYTES conservan sus campos de nivel superior y eliminan el anidamiento, con un puntero a remnawave_describe_operation para la versión completa.

  3. Vías de escape (2 herramientas). GET crudo y escritura cruda para cualquier cosa que la especificación omita.

Cada ruta pasa por el mismo ejecutor, por lo que la puerta de escritura, la puerta de confirmación destructiva, el templating de rutas y el manejo de consultas se comportan de manera idéntica sin importar qué superficie uses.

Elige un perfil según tu gusto: minimal si tienes muchos servidores MCP conectados, core si quieres las operaciones cotidianas a una llamada de distancia, full si el contexto no es una preocupación.

Notas de campo — comportamiento que la especificación no documenta

Todas estas se probaron contra un panel 3.3.2 en vivo y se adjuntan a las operaciones afectadas en las descripciones de las herramientas.

  • PATCH /api/config-profiles es un reemplazo, no un parche. El cuerpo es {uuid, config} y config debe ser la configuración Xray completa y válida. Un fragmento falla con A061: Config doesn't have inbounds. Secuencia correcta: GET /api/config-profiles/{uuid} → edita el objeto config devuelto en su lugar → PATCH de todo el objeto de vuelta.

  • El panel no responde en 127.0.0.1:3000, incluso desde el propio host del panel y aunque docker-proxy esté escuchando allí (curl devuelve el código de salida 52, respuesta vacía). Usa siempre el origen HTTPS público con un token Bearer.

  • Cada respuesta está envuelta en {"response": ...}. Este servidor la desenvuelve, por lo que la salida de la herramienta es el payload en sí.

  • Un host se vincula a un perfil a través del inbound.configProfileUuid anidado (más inbound.configProfileInboundUuid), no un configProfileUuid de nivel superior. Verificado contra hosts en vivo: anidado presente, nivel superior ausente.

  • Una serie de PATCHes tumbarán el panel. Cada escritura de configuración empuja a cada nodo y reinicia Xray allí; varias seguidas y el propio listener TLS del panel deja de responder. El cliente serializa las mutaciones (REMNAWAVE_WRITE_MIN_INTERVAL_MS, predeterminado 1500 ms) y reintenta los fallos de transporte con retroceso exponencial y jitter. No lo anules lanzando actualizaciones masivas en paralelo.

  • POST /api/subscription-templates solo crea una plantilla vacía. El contenido se sube mediante un PATCH /api/subscription-templates separado. Los cuerpos JSON y YAML no se pueden actualizar en la misma llamada.

  • serverDescription en un host está limitado a 30 caracteres (confirmado por maxLength en la especificación). También es lo que hace que un host Hysteria2 se renderice correctamente en Happ en lugar de JSON crudo.

  • Dieciséis endpoints son solo de JWT de administrador — los controladores completos auth y passkeys más la gestión de tokens de API (GET/POST /api/tokens, DELETE /api/tokens/{uuid}, GET /api/tokens/scopes). El panel responde a un token de API con 401/403 allí. Este servidor los detecta desde la especificación y los rechaza localmente; REMNAWAVE_ALLOW_ADMIN_JWT_OPS=1 levanta la puerta si el token que configuraste realmente es un JWT de administrador.

  • GET /api/users/stream responde con JSON delimitado por saltos de línea, no un solo documento. Se analiza en un array de registros de usuario en lugar de devolverse como un blob de texto.

  • PATCH /api/hosts es un parche parcial real{uuid, serverDescription} solo funciona. Solo los perfiles de configuración tienen la semántica de reemplazo completo. Verificado en vivo.

  • Los errores vienen como {message, errorCode}; el errorCode (p. ej. A061) se incluye en el texto de error de este servidor.

Cobertura de herramientas

Cada controlador es accesible a través de remnawave_call y las vías de escape. La columna tipadas muestra cuáles obtienen herramientas individuales bajo REMNAWAVE_TOOL_PROFILE=core.

Slug del controlador

Operaciones

Tipado en 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

Total

205

Ejecuta remnawave_list_operations contra un servidor en vivo para obtener el conjunto exacto y actual.

Ejemplos

Explora y llama sin herramientas tipadas:

// 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 y query también pueden llegar como texto JSON — "params": "{\"uuid\":\"…\"}" — porque algunos clientes MCP reenvían los argumentos de herramientas no tipadas tal cual en lugar de analizarlos. La cadena se analiza por ti; una que no sea JSON se rechaza con un mensaje que lo indica.

Editar un perfil de configuración de forma segura (la trampa 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 */ } } } } }

Sintaxis de consulta que la especificación no puede expresar:

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

Pruebas

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

Las pruebas unitarias cubren las partes que fallan silenciosamente: la expansión de $ref a través de los DTO recursivos de Remnawave, la derivación de nombres de herramientas (presupuesto de longitud, determinismo, detección de colisiones), el diff del catálogo, ambas compuertas de escritura, la compuerta admin-JWT, el colapso de esquemas y el análisis NDJSON.

Comprobaciones de solo lectura contra un panel real

Con un panel accesible y un token de lectura en el entorno, el script de humo también ejecuta llamadas en vivo de solo lectura (nunca una mutación):

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

Ejecútalo donde ya vive el token (p. ej. en el host del panel) para que el secreto nunca viaje. El script imprime formas — tipos, nombres de claves, longitudes de arrays — y nunca valores de payload, por lo que su salida es segura para pegar en un issue.

Las comprobaciones de guardarraíl apuntan deliberadamente a http://127.0.0.1:9, de modo que una compuerta que alguna vez fallara abierta no pudiera alcanzar un panel real.

Verificación de la ruta de escritura

Las lecturas no pueden demostrar que el enrutamiento de tokens, el limitador, la compuerta de confirmación y la semántica de parche parcial funcionan realmente. scripts/write-check.mjs los demuestra en objetos a los que nadie está conectado, y restaura el único objeto preexistente que toca:

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>]

Crea un squad interno sin inbounds y sin miembros y lo elimina de nuevo, luego reescribe serverDescription en un host y restaura el valor original. Se niega a iniciar sin el flag de reconocimiento, y reporta una salida distinta de cero si queda algo atrás.

Contra un panel 3.3.2 en vivo confirmó: la compuerta de confirmación se mantiene en un DELETE real; un PATCH /api/hosts parcial funciona; el panel rechaza un serverDescription de 31 caracteres; el valor original (incluido null) hace el viaje de ida y vuelta; y las mutaciones consecutivas se espaciaron 1525 y 1524 ms entre sí contra un mínimo configurado de 1500 ms.

Inspección local

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

Actualización de la especificación de la API

Todo sobre la API proviene de un solo archivo, por lo que seguir una nueva versión de Remnawave es un comando:

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

De dónde proviene la especificación

https://cdn.remna.st/docs/openapi.json — publicado por el propio flujo de trabajo Build&Push OpenAPI Specs de Remnawave en cada tag upstream, por lo que siempre describe la versión más reciente. Anula con --url <u> o REMNAWAVE_SPEC_URL para fijar una fuente diferente.

Una instancia de panel no es una fuente utilizable: los docs están deshabilitados a menos que el despliegue los active, e incluso entonces Swagger está montado en /backend-tools/swagger, que el proxy inverso habitual no enruta. Sondear un panel 3.3.2 en vivo devolvió 404 en cada ruta de especificación convencional.

La descarga solo se escribe en disco después de que se analice como un documento OpenAPI con un paths no vacío, por lo que una página de error o un portal cautivo no pueden sobrescribir una especificación funcional.

Qué comprobar después

build-spec compara el nuevo catálogo con el anterior e imprime cada cambio:

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 son cambios disruptivos para cualquiera cuyos prompts o scripts nombren esas herramientas. --strict los convierte en una salida distinta de cero, que es el flag que la automatización debería usar.

  • added es seguro; las nuevas operaciones son accesibles a través de remnawave_call inmediatamente y obtienen herramientas tipadas si su controlador está en el perfil activo.

  • schema changed merece un vistazo para las operaciones que realmente usas.

npm test luego vuelve a comprobar que el catálogo en disco coincide con una compilación nueva, que todos los nombres de herramientas son únicos y están dentro del presupuesto de 64 caracteres, y que los guardarraíles siguen en pie.

Automatización

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

El tag empujado activa el flujo de trabajo de release, que republica en npm. Los clientes registrados con @folexz/remnawave-mcp@latest recogen la nueva versión en su próximo lanzamiento.

Publicación (mantenedores)

Primera publicación — necesariamente manual

npm no puede configurar un editor de confianza para un paquete que aún no existe: la configuración vive en la propia página de configuración del paquete. Esa es una limitación conocida y aún abierta (npm/cli#8544), y también se aplica a los paquetes con scope. Así que la versión 0.1.0 tiene que subir desde una máquina con sesión iniciada:

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

--access public es obligatorio: los paquetes con scope tienen por defecto restringido.

Luego cambia a releases sin token

Una vez que el paquete existe, en npmjs.com → @folexz/remnawave-mcp → Settings → Trusted Publisher, añade un editor de GitHub Actions con el repositorio folexz/remnawave-mcp y el flujo de trabajo release.yml. repository.url en package.json debe coincidir exactamente con el repositorio de GitHub — lo hace.

Después de eso, .github/workflows/release.yml publica en cualquier tag vX.Y.Z empujado vía OIDC — sin token, sin secreto, con procedencia adjunta automáticamente:

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

El flujo de trabajo reinstala desde el lockfile, recompila, ejecuta las pruebas unitarias y la suite de humo sin conexión, y falla rápido si el tag no coincide con package.json.

Los clientes registrados con @folexz/remnawave-mcp@latest recogen la nueva versión en su próximo lanzamiento.

Notas de seguridad

  • Los tokens se leen solo del entorno y nunca se registran. Los logs van a stderr; stdout es el canal MCP JSON-RPC.

  • Prefiere configurar solo REMNAWAVE_API_TOKEN_READ. Las herramientas de mutación no existen sin un token de escritura, por lo que un cliente comprometido o confundido no puede cambiar el panel.

  • Los endpoints de suscripción devuelven configuraciones de cliente funcionales. Trata su salida como secreta.

  • Nunca hagas commit de tokens reales. .env está en gitignore; .env.example muestra la forma.

Limitaciones conocidas

  • La validación del body se delega al panel. Este servidor solo comprueba que los argumentos requeridos y un body requerido estén presentes; no valida la forma interna del body contra el esquema. Eso es deliberado — el panel ya valida cada campo y responde con un message + errorCode preciso (p. ej. A061), y duplicar eso localmente significaría enviar un validador de JSON Schema más una segunda copia de las reglas, inevitablemente divergente. El coste es que un body malformado cuesta un viaje de ida y vuelta para descubrirlo.

  • Las escotillas de escape omiten las compuertas por operación. remnawave_request_write es crudo por diseño: todavía requiere un token de escritura y todavía pasa por el limitador y la lógica de reintento, pero no aplica la compuerta destructiva confirm ni la comprobación admin-JWT, porque no tiene una operación de la que obtenerlas. Prefiere remnawave_call a menos que necesites una ruta que la especificación no describe.

  • Las herramientas están tan actualizadas como la especificación incluida (v3.3.2). Un panel en una versión menor diferente puede exponer rutas que no describe; para eso están las escotillas de escape. Consulta Actualización de la especificación de la API.

  • Los endpoints admin-JWT están compuertados, no implementados. Este servidor lleva tokens de API; no realiza un inicio de sesión de administrador, mantiene una sesión ni refresca un JWT. Si suministras un JWT de administrador como token y estableces REMNAWAVE_ALLOW_ADMIN_JWT_OPS=1, esos 16 endpoints se vuelven invocables, pero la expiración y la renovación son tu problema.

  • El endpoint de métricas Prometheus con autenticación básica no forma parte de esta especificación y no está expuesto.

  • write-check.mjs muta. Es una herramienta de mantenedores, excluida de npm test, y se niega a ejecutarse sin un flag de reconocimiento explícito.

Licencia

MIT — consulta LICENSE.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    B
    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.
    7
    MIT
  • A
    license
    Not graded
    quality
    B
    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