mcp-remnawave
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.
README
<div align="center">
mcp-remnawave
MCP server for the Remnawave VPN panel — updated for Remnawave 3.x
English · Русский
</div>
Lets an MCP client — Claude Code, Claude Desktop, Cursor or any other — read and manage users, nodes, hosts, config profiles, squads, subscription templates, billing and HWID devices through the panel's REST API.
Maintained fork of TrackLine/mcp-remnawave v1.2.0, brought in line with Remnawave 3.x (verified against a live 3.3.x panel) and reworked so that tool schemas can no longer drift away from the panel API.
✨ Highlights
| 🔢 Numeric user ids | Remnawave 3.0 dropped the user uuid; every users_* tool uses the numeric id and the removed by-* routes are replaced by users_list filters |
| 📜 Schemas from the contract | Write tools take their input schema straight from @remnawave/backend-contract — the full API surface, not a hand-picked subset |
| 🧾 Real error messages | Validation errors come back with field-level details instead of a bare Validation failed |
| 🗂 One install, many panels | Panel config is looked up in the current project first — the active panel is whichever project you are working in |
| 🔒 Readonly by default | With REMNAWAVE_READONLY=true write tools are not registered at all |
🚀 Quick start
git clone https://github.com/Maaagiic/mcp-remnawave.git
cd mcp-remnawave
npm install && npm run build
cp .env.example .env # set REMNAWAVE_BASE_URL and REMNAWAVE_API_TOKEN
# Claude Code — available in every project:
claude mcp add --scope user remnawave -- node "$PWD/dist/index.js"
That's it. Ask your client to system_metadata — it should answer with the panel version.
<details> <summary><b>Per-project registration instead (<code>.mcp.json</code>)</b></summary>
{
"mcpServers": {
"remnawave": {
"command": "node",
"args": ["/absolute/path/to/mcp-remnawave/dist/index.js"]
}
}
}
</details>
<details> <summary><b>Other MCP clients</b></summary>
Any stdio MCP client works — point it at node dist/index.js and pass the environment
variables from the table below (or rely on the config file lookup).
</details>
⚙️ Configuration
| Variable | Required | Description |
|---|---|---|
REMNAWAVE_BASE_URL |
✅ | Panel URL, e.g. https://panel.example.com |
REMNAWAVE_API_TOKEN |
✅ | API token (Bearer) — Panel → API tokens |
REMNAWAVE_READONLY |
— | true = only read tools are registered (recommended default) |
REMNAWAVE_API_KEY |
— | X-Api-Key for a Caddy custom-path setup |
REMNAWAVE_ENV_FILE |
— | Explicit path to a config file |
Where the config comes from
The server stops at the first file that provides REMNAWAVE_BASE_URL and REMNAWAVE_API_TOKEN:
1. $REMNAWAVE_ENV_FILE explicit path
2. <cwd>/.remnawave.env per-project — add it to .gitignore
3. <cwd>/.env
4. <package>/.env fallback
MCP clients launch stdio servers with cwd set to the project root, so with a single
global install the active panel is whichever project you are working in. To add a
panel, drop a .remnawave.env into its project — nothing to change on the server side.
Variables already present in the environment are never overridden, so env passed by the
client registration always wins.
Readonly mode
Start with REMNAWAVE_READONLY=true. Write tools (create / update / delete / enable /
disable / bulk) are not registered at all in this mode, so the client cannot even
attempt them. Set it to false and restart the server when you actually need to write.
🧰 Tools
About 150 tools, grouped like the panel API. Read tools are always available; write tools only when readonly is off.
<details open> <summary><b>Users</b></summary>
| Read | Write |
|---|---|
users_list (filters · sorting), users_get, users_get_by_username, users_get_by_short_uuid, users_resolve, users_accessible_nodes, users_tags_list |
users_create, users_update, users_delete, users_enable / users_disable, users_revoke_subscription, users_reset_traffic, users_extend_expiration, users_bulk_*, users_bulk_all_* |
- Search by telegramId / email / tag / status:
users_listwithfilters: [{"id": "telegramId", "value": 123456789}](+ optionalfilterModes,sorting). This replaces theby-*routes removed in 3.x. users_resolvetakes exactly one ofid,shortUuid,username.- Bulk tools take
userIds: number[](1–500);users_bulk_updatenests changed fields underfields. users_createaccepts explicitvlessUuid/ssPassword/trojanPassword/shortUuid— handy for service accounts. </details>
<details> <summary><b>Nodes · Hosts · Config profiles</b></summary>
| Group | Read | Write |
|---|---|---|
| Nodes | nodes_list, nodes_get, nodes_tags_list |
nodes_create / update / delete, nodes_enable / disable, nodes_restart, nodes_restart_all, nodes_reorder, nodes_reset_traffic, nodes_bulk_* |
| Hosts | hosts_list, hosts_get, hosts_tags_list |
hosts_create / update / delete, hosts_bulk_* |
| Config profiles | config_profiles_list / get, config_profiles_get_inbounds, config_profiles_get_computed_config, inbounds_list |
config_profiles_create / update / delete / reorder |
config_profiles_updatewithconfigreplaces the whole xray config of the profile — read, patch, write back.hosts_createrequiresinbound: { configProfileUuid, configProfileInboundUuid }. </details>
<details> <summary><b>Squads · Subscriptions · Templates</b></summary>
| Group | Read | Write |
|---|---|---|
| Squads | squads_list, squads_accessible_nodes, external_squads_list / get |
squads_create / update / delete, squads_add_users, squads_remove_users, external_squads_* |
| Subscriptions | subscriptions_list, subscriptions_get_by_username, subscriptions_get_by_short_uuid, subscriptions_get_by_user_id, subscriptions_get_raw_by_short_uuid, subscriptions_get_connection_keys, subscription_info |
— |
| Templates & pages | subscription_templates_list / get, sub_page_configs_list / get |
subscription_templates_update, sub_page_configs_* |
| </details> |
<details> <summary><b>HWID · System · Billing · Plugins · Misc</b></summary>
| Group | Read | Write |
|---|---|---|
| HWID | hwid_devices_list, hwid_devices_list_all, hwid_stats, hwid_top_users |
hwid_device_create / delete, hwid_devices_delete_all |
| System | system_health, system_metadata, system_stats, system_stats_recap, system_bandwidth_stats, system_nodes_metrics, system_nodes_statistics, system_generate_x25519, keygen_get, system_srr_matcher |
settings_update |
| Billing | billing_providers_list / get, billing_nodes_list, billing_history_list |
billing_provider_*, billing_node_*, billing_history_* |
| Node plugins | node_plugins_list / get, node_plugins_torrent_* |
node_plugins_* |
| Misc | api_tokens_list, snippets_list, metadata_*_get, ip_control_* |
api_tokens_*, snippets_*, metadata_*_upsert |
api_tokens_list and settings_* need an API token with the matching rights — otherwise the panel answers Forbidden.
</details>
🔧 What changed vs. upstream
<details> <summary>Full list</summary>
- Numeric user ids everywhere;
users_get_by_telegram_id/_by_email/_by_tag/_by_subscription_uuidandsubscriptions_get_by_uuidremoved (the routes no longer exist). contractTool()— write tools register withRequestSchema.shapefrom the contract. Before: 20 of 23 write tools exposed a subset of fields and the MCP SDK dropped the rest silently.users_*remain hand-written: the installed contract still declaresuuidfor users.- New:
users_extend_expiration,users_accessible_nodes,subscriptions_get_by_user_id,subscription_templates_list/get/update;config_profiles_updatetakesconfig. - Client: full API error bodies, empty
2xxbodies on bulk operations handled, trailing-slash-safe hand-built paths for 3.x-only routes. - Enums from the contract (
RESET_PERIODSincl.MONTH_ROLLING,USERS_STATUS). - Multi-panel config lookup; readonly recommended by default; version bumped to 2.0.0. </details>
🛠 Development
npm run dev # tsup --watch
npm run build # tsup → dist/index.js
npx tsc --noEmit # typecheck
🐳 Docker
docker compose up -d
See docker-compose.yml and pass the same environment variables.
📄 License
MIT. Upstream authorship: TrackLine/mcp-remnawave.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.