Back to Browse

Wg Easy MCP Server

by Ni C
Developer ToolsLow Risk10.0MCP RegistryLocal
Free

Server data from the Official MCP Registry

Administer wg-easy (WireGuard Easy) v15: manage VPN clients, configs, QR codes and server status

About

Administer wg-easy (WireGuard Easy) v15: manage VPN clients, configs, QR codes and server status

Security Report

10.0
Low Risk10.0Low Risk

Valid MCP server (2 strong, 1 medium validity signals). No known CVEs in dependencies. Package registry verified. Imported from the Official MCP Registry. Trust signals: trusted author (16/16 approved).

6 files analyzed · 1 issue found

Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.

Permissions Required

This plugin requests these system permissions. Most are normal for its category.

file_system

Check that this permission is expected for this type of plugin.

What You'll Need

Set these up before or after installing:

Base URL of the wg-easy web UI, e.g. https://vpn.example.com:51821Optional

Environment variable: WG_EASY_URL

Username of a wg-easy admin account (2FA must be disabled)Optional

Environment variable: WG_EASY_USERNAME

Password of the wg-easy admin accountRequired

Environment variable: WG_EASY_PASSWORD

Set to true to accept self-signed TLS certificates (scoped to the wg-easy connection)Optional

Environment variable: WG_EASY_INSECURE_TLS

Set to true to register only the read tools (default: false)Optional

Environment variable: WG_EASY_READ_ONLY

Comma-separated tool names or list_* prefixes to register; 'essential' selects a curated preset (default: all tools)Optional

Environment variable: WG_EASY_ALLOW_TOOLS

Comma-separated tool names or list_* prefixes to remove from whatever WG_EASY_ALLOW_TOOLS leftOptional

Environment variable: WG_EASY_DENY_TOOLS

How to Install

Add this to your MCP configuration file:

{
  "mcpServers": {
    "io-github-ni-c-wg-easy-mcp": {
      "env": {
        "WG_EASY_URL": "your-wg-easy-url-here",
        "WG_EASY_PASSWORD": "your-wg-easy-password-here",
        "WG_EASY_USERNAME": "your-wg-easy-username-here",
        "WG_EASY_READ_ONLY": "your-wg-easy-read-only-here",
        "WG_EASY_DENY_TOOLS": "your-wg-easy-deny-tools-here",
        "WG_EASY_ALLOW_TOOLS": "your-wg-easy-allow-tools-here",
        "WG_EASY_INSECURE_TLS": "your-wg-easy-insecure-tls-here"
      },
      "args": [
        "-y",
        "wg-easy-mcp"
      ],
      "command": "npx"
    }
  }
}

Documentation

View on GitHub

From the project's GitHub README.

wg-easy-mcp

CI npm version npm downloads node license container docs sponsor

A Model Context Protocol (MCP) server for administering wg-easy (WireGuard Easy) instances.

Lets MCP clients like Claude Code, Claude Desktop or Codex manage your WireGuard VPN: list, create, update, enable/disable and delete clients, fetch configuration files and QR codes, and inspect the server status — all through the wg-easy v15 REST API.

Eleven tools is the ceiling, not the floor: WG_EASY_ALLOW_TOOLS=essential registers a curated eight instead, and a model picks the right tool far more reliably from eight than from eleven — see choosing which tools load.

Requirements

  • Node.js ≥ 22
  • A running wg-easy v15+ instance
  • 2FA (TOTP) must be disabled for the account used by this server — the wg-easy API only supports Basic Authentication and does not work with 2FA enabled

Note: The wg-easy REST API is not yet declared stable and may change between releases. This server targets wg-easy v15.

Configuration

Configuration is provided via environment variables:

VariableRequiredDescription
WG_EASY_URLyesBase URL of the wg-easy web UI, e.g. https://vpn.example.com:51821
WG_EASY_USERNAMEyesUsername of a wg-easy admin account
WG_EASY_PASSWORDyesPassword of that account
WG_EASY_INSECURE_TLSnoSet to true to accept self-signed TLS certificates (scoped to the wg-easy connection)
WG_EASY_ALLOW_TOOLSnoComma-separated tool names, list_* prefixes, or essential for a curated preset
WG_EASY_DENY_TOOLSnoSame syntax; removed from whatever WG_EASY_ALLOW_TOOLS left

Use https://. With a plain-http URL the Basic Auth credentials and all WireGuard private keys travel unencrypted; the server prints a warning unless the host is local. For self-signed certificates prefer a proper internal CA over WG_EASY_INSECURE_TLS.

Without credentials the server still starts and lists its tools (so registries and inspectors can introspect it), but every tool call fails with setup instructions instead of reaching the wg-easy API.

Choosing which tools load

WG_EASY_ALLOW_TOOLS and WG_EASY_DENY_TOOLS take comma-separated tool names; a trailing * matches a whole family. essential is a curated preset of eight: get_server_info, list_clients, get_client, create_client, get_client_config, get_client_qrcode, enable_client, disable_client.

WG_EASY_ALLOW_TOOLS=essential
WG_EASY_ALLOW_TOOLS=list_clients,get_client_config
WG_EASY_DENY_TOOLS=delete_client,create_client

An entry that matches no tool aborts startup and names it, so a typo cannot silently hide a tool — an absent tool is not something anyone traces back to an environment variable. A filtered tool is never registered, so it is absent from tools/list and unknown to tools/call alike, exactly like a write tool under WG_EASY_READ_ONLY.

If you run several of these servers at once, mcp-hub is the other answer — its /hub endpoint replaces every server's tools with six meta-tools.

Installation

Claude Code

claude mcp add wg-easy -s user \
  -e WG_EASY_URL=https://vpn.example.com:51821 \
  -e WG_EASY_USERNAME=admin \
  -e WG_EASY_PASSWORD=your-password \
  -- npx -y wg-easy-mcp

Claude Desktop

Add to your claude_desktop_config.json:

{
  "mcpServers": {
    "wg-easy": {
      "command": "npx",
      "args": ["-y", "wg-easy-mcp"],
      "env": {
        "WG_EASY_URL": "https://vpn.example.com:51821",
        "WG_EASY_USERNAME": "admin",
        "WG_EASY_PASSWORD": "your-password"
      }
    }
  }
}

Codex

Add to your ~/.codex/config.toml:

[mcp_servers.wg-easy]
command = "npx"
args = ["-y", "wg-easy-mcp"]
env = { WG_EASY_URL = "https://vpn.example.com:51821", WG_EASY_USERNAME = "admin", WG_EASY_PASSWORD = "your-password" }

From source

git clone https://github.com/ni-c/wg-easy-mcp.git
cd wg-easy-mcp
npm install
npm run build
# then use `node /path/to/wg-easy-mcp/dist/index.js` as the command

Docker

A multi-arch image (linux/amd64, linux/arm64) with an SBOM and build provenance is published to GitHub Container Registry:

docker run -i --rm \
  -e WG_EASY_URL=https://vpn.example.com:51821 \
  -e WG_EASY_USERNAME=admin \
  -e WG_EASY_PASSWORD=your-password \
  ghcr.io/ni-c/wg-easy-mcp:latest

The image talks MCP over stdio, so clients need docker run -i (no port is exposed):

{
  "mcpServers": {
    "wg-easy": {
      "command": "docker",
      "args": [
        "run",
        "-i",
        "--rm",
        "-e",
        "WG_EASY_URL",
        "-e",
        "WG_EASY_USERNAME",
        "-e",
        "WG_EASY_PASSWORD",
        "ghcr.io/ni-c/wg-easy-mcp:latest"
      ],
      "env": {
        "WG_EASY_URL": "https://vpn.example.com:51821",
        "WG_EASY_USERNAME": "admin",
        "WG_EASY_PASSWORD": "your-password"
      }
    }
  }
}

Tools

ToolDescription
list_clientsList all WireGuard clients with status and traffic statistics
get_clientGet the full details of a single client
create_clientCreate a new client (name, optional expiresAt)
update_clientUpdate a client; only the provided fields are changed
enable_client / disable_clientEnable or disable a client
delete_clientPermanently delete a client — two-step, guarded by a confirmation token
get_client_configGet the client's WireGuard .conf file
get_client_qrcodeGet the client configuration as a QR code (SVG)
generate_one_time_linkGenerate a one-time config download link (requires one-time links to be enabled in wg-easy)
get_server_infoRelease/update status, general settings and interface configuration (secrets redacted)

Safety

  • delete_client is a two-step operation: the first call returns a random confirmation token (valid for 5 minutes, bound to the client ID) and only a second call with that exact token deletes the client. Unlike a plain confirm=true parameter, the token cannot be guessed or pre-supplied by the model or by injected text.
  • get_server_info redacts secret fields (privateKey, preSharedKey, password, session/TOTP secrets) from the admin API responses.
  • Everything the wg-easy API returns carries an explicit untrusted-data marker and a 60 000-character budget. Client names, DNS entries and endpoints are free-form strings, so they are marked as data to report rather than instructions to follow, and a single oversized field cannot flood the model's context.
  • A WG_EASY_URL containing embedded credentials (user:password@host) is rejected at startup — they would otherwise be echoed in the startup log and prefixed onto every request.
  • Upstream error bodies are truncated and HTML error pages (reverse proxies) are dropped before being returned to the MCP client.
  • WG_EASY_INSECURE_TLS only relaxes certificate validation for the wg-easy connection — it does not disable TLS verification process-wide.
  • Tools carry MCP annotations (readOnlyHint, destructiveHint, idempotentHint) so hosts can apply appropriate permission policies.
  • Keep in mind that get_client_config and get_client_qrcode return the client's private key, and a generate_one_time_link URL allows an unauthenticated config download — treat tool output as sensitive.

The full trust model is in SECURITY.md and, in prose, at wg-easy-mcp.ni-c.de/guide/security.

Development

npm install
npm run build     # compile TypeScript to dist/
npm test          # run the vitest test suite
npm run lint      # eslint + prettier check
npm run test:coverage

CI runs the suite on Node 22 and 24 and adds npm audit, CodeQL and a Trivy scan of the container image on both architectures. See CONTRIBUTING.md.

The documentation site lives in docs/ with its own manifest:

cd docs && npm install && npm run dev

Releasing

  1. Bump the version in package.json and add a CHANGELOG.md entry.
  2. Commit, then tag and push: git tag -a vX.Y.Z -m "vX.Y.Z" && git push origin main vX.Y.Z

The release workflow runs the test suite, publishes to npm (via trusted publishing, no token, with provenance), creates a GitHub release from the changelog entry and updates the entry in the official MCP Registry (io.github.ni-c/wg-easy-mcp, via GitHub OIDC). The container image is published to GHCR by the CI workflow on the same tag.

server.json lists both an npm and an OCI package; the registry job syncs the version into both before publishing. If it ever fails, fix main and re-run mcp-registry.yml via workflow_dispatch — re-running the tag job checks out the old tree.

License

MIT

Reviews

No reviews yet

Be the first to review this server!