Skip to main content
Glama

wg-easy-mcp

CI OpenSSF Scorecard Glama score npm version container image HTTP via mcp-hub 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 six instead, and a model picks the right tool far more reliably from six than from eleven — see choosing which tools load.

Listing the tools, narrowing them to the essential preset, and the startup abort a mistyped tool name produces

What makes it different

The full client lifecycle over the wg-easy v15 REST API, including .conf files, QR codes and one-time download links.

Partial updates merge. An update reads the current client state and changes only the fields you named, instead of overwriting the rest with defaults.

disable_client stays ungated on purpose. Every other write asks a person first through MCP elicitation; that one only ever withdraws access, and making it harder would be making the safe move the slow one.

Related MCP server: amp-mcp-server

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:

Variable

Required

Description

WG_EASY_URL

yes

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

WG_EASY_USERNAME

yes

Username of a wg-easy admin account

WG_EASY_PASSWORD

yes

Password of that account

WG_EASY_INSECURE_TLS

no

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

WG_EASY_ALLOW_TOOLS

no

Comma-separated tool names, list_* prefixes, or essential for a curated preset

WG_EASY_DENY_TOOLS

no

Same syntax; removed from whatever WG_EASY_ALLOW_TOOLS left

ELICITATION

no

false replaces the approval dialog with the two-call token. Not prefixed

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 six: get_server_info, list_clients, get_client, create_client, enable_client, disable_client.

get_client_config, get_client_qrcode and generate_one_time_link are not in it, and neither is delete_client: all four either destroy something irreversibly or hand out a peer's private key. Name them where you want them.

WG_EASY_ALLOW_TOOLS=essential
WG_EASY_ALLOW_TOOLS=essential,get_client_config
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"
      }
    }
  }
}

Through mcp-hub

A client that cannot spawn a local process — ChatGPT connectors, Claude on the web, Cursor, LibreChat — reaches wg-easy-mcp through mcp-hub: one container serves many stdio MCP servers over Streamable HTTP, with an OAuth 2.1 login behind a single password and long-lived tokens for the clients that cannot do OAuth. Its /hub endpoint puts every server behind six meta-tools, so one connector reaches all of them without N×tool schemas in the model's context, and it speaks both protocol revisions — a question this server asks travels through it to the person at the far end.

Its /config/mcp.json uses Claude Code's format, so the entry is the one you already have:

{
  "mcpServers": {
    "wg-easy": {
      "command": "npx",
      "args": ["-y", "wg-easy-mcp"],
      "env": { "WG_EASY_ALLOW_TOOLS": "essential" },
      "denyTools": ["delete_client"]
    }
  }
}

allowTools and denyTools there are the hub's own per-server filter, which is not the same thing as *_ALLOW_TOOLS in env — the difference, and the mistake it invites, are in the client guide.

Tools

Tool

Description

list_clients

List all WireGuard clients with status and traffic statistics

get_client

Get the full details of a single client

create_client 👤

Create a new client (name, optional expiresAt)

update_client 👤

Update a client; only the provided fields are changed

enable_client 👤

Let a client connect again — re-arms a key pair already installed on the peer

disable_client

Block a client; it keeps its configuration and keys

delete_client 👤

Permanently delete a client

get_client_config

Get the client's WireGuard .conf file

get_client_qrcode

Get the client configuration as a QR code (SVG)

generate_one_time_link 👤

Generate a one-time config download link, valid five minutes

get_server_info

Release/update status, general settings and interface configuration (secrets redacted)

👤 asks a person through MCP elicitation · falls back to a two-call confirm_token where the client cannot show a dialog.

Structured output

Every tool declares an outputSchema and answers with structuredContent alongside the text block, so a client can use the result without parsing prose:

{
  "untrusted": true,
  "source": "wg-easy",
  "count": 2,
  "clients": [{ "id": 1, "name": "laptop", "enabled": true }],
}

The untrusted marker is a field and not only a sentence in the text, because a client that reads the structured half and ignores the text would otherwise get free-form client names, DNS entries and endpoints with no framing at all. Every tool carries it except delete_client, which reports an id this server was given and nothing that came back from the instance.

Three answers changed shape to fit, and all three for the same reason: a schema whose root is not an object is served to a 2025-era client rewritten as {result: …}, so the tool would answer differently depending on who asked.

Tool

Was

Is

list_clients

a bare array

{count, clients}

get_client_config

the .conf text

{configuration}

get_client_qrcode

the SVG markup

{svg}

An oversized answer is now shortened as an object rather than cut as a string: the longest text field is shortened first, then list entries are dropped, and a truncated field says what was cut and how much there was. A document sliced at a byte offset is not a smaller answer, it is an unparseable one — and the two channels have to carry the same value.

What wg-easy sends is described with every field optional and unknown fields allowed; only what this server builds is exact. The SDK validates each result against its schema before it goes out, so a stricter shape would turn a wg-easy release that adds a field into a tool that fails outright.

Safety

  • Five tools ask a person, not just the model. create_client, update_client, enable_client, delete_client and generate_one_time_link raise a real dialog through MCP elicitation where the client supports it. Only one of the five destroys anything — the others issue a VPN credential, re-arm one, can widen a route, and mint an unauthenticated URL that hands out a private key. disable_client is the one write tool that never asks: it can only withdraw access. Where the client cannot show a dialog they fall back to a random token valid for 5 minutes and bound to the exact target (for update_client, to the exact edit), which proves the call was made twice with the same arguments and nothing more. ELICITATION=false takes that fallback deliberately; it never removes the guard. See Asking a person.

  • Key material is redacted everywhere it is not the point. A field name is matched by its suffixpassword, passwd, passphrase, secret, token, apiKey, privateKey, preSharedKey, plus anything starting with totp — so metricsPassword, which carries the argon2 hash of the metrics token, is covered along with every other <prefix>Secret wg-easy invents. (key is not a suffix: it would take publicKey with it.) Values are replaced with [redacted] at every nesting level — in get_server_info's admin responses, which carry the WireGuard server key, and in list_clients and get_client, which carry each client's own key. Live one-time-link tokens are redacted from the same two, because GET /cnf/<token> serves the whole configuration with no login at all; expiresAt survives, so a listing still shows that a link is live. get_client_config, get_client_qrcode and generate_one_time_link are the deliberate exceptions: handing a peer its configuration is what they are for, and somebody asked.

  • Everything the wg-easy API returns carries an explicit untrusted-data marker and a 60 000-character budget, measured on the text that is actually emitted. Client names, DNS entries and endpoints are free-form strings, so they are marked as data to report rather than instructions to follow, control characters and BiDi overrides are stripped from them (field names included), and a single oversized field cannot flood the model's context.

  • Nothing the instance sends is taken on trust. Every field an output schema types is checked at the boundary and left out when it does not hold, so one record with a string id or a 1e999 cannot take a whole listing down with Output validation error. Entries that are not client records at all are counted in skipped rather than dropped in silence.

  • Response bodies have a ceiling (8 MiB, refused on a declared content-length before a byte is read) and the status is read before the body, so a 401 behind a large proxy page is still a 401. A refused login is repeated from memory for ten seconds rather than retried.

  • 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. Only its origin and path are kept, and no startup diagnostic echoes a value back.

  • Upstream error bodies are labelled as untrusted, stripped of control characters and cut at 200 characters; HTML error pages (reverse proxies) are dropped before being returned to the MCP client.

  • Caller input has a length: names and filters at 200 characters, addresses at 64, list parameters at 64 entries, and a client id bounded in its pattern rather than after Number().

  • WG_EASY_INSECURE_TLS only relaxes certificate validation for the wg-easy connection — it does not disable TLS verification process-wide.

  • WG_EASY_READ_ONLY=true registers list_clients, get_client and get_server_info, and nothing else. get_client_config and get_client_qrcode are reads and still not in that set: what they read is a client's private key in the clear, and a read-only mode that leaves key disclosure standing is not the mode its name promises.

  • 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.

Not exposed, on purpose

wg-easy v15 or newer only. Older versions expose a different, session-based API that this server does not implement.

No server administration. The tools cover the client lifecycle; the instance's own configuration, its admin accounts and its host stay outside the tool list.

Safety

  • Five tools ask a person first, through MCP elicitation: create_client, update_client, enable_client, delete_client and generate_one_time_link. Only one of them destroys anything — the others are on the list because destructiveHint is the wrong axis for what they do. A new client is a credential that reaches every network behind the VPN, update_client can widen serverAllowedIps, and enable_client re-arms a key pair that is already installed on a peer.

  • The approval is bound to the exact edit, so approving a rename does not license a later call that widens the routes.

  • disable_client deliberately stays ungated: it only ever withdraws access, and making the safe move the slow one would be the wrong trade.

  • Client names, addresses and the instance's own strings are marked as untrusted data, and oversized output is truncated with the omission stated.

  • WG_EASY_READ_ONLY=true registers the read tools and nothing else.

Documentation

The full guide, tool reference and security notes live at wg-easy-mcp.ni-c.de (source in docs/).

Development

npm install
npm run build     # compile TypeScript to dist/
npm test          # run the vitest test suite
npm run lint      # oxlint + 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.

Releasing

Releases are tag-driven. Bump package.json, move the [Unreleased] notes in CHANGELOG.md under the new version, commit, then:

git tag -s vX.Y.Z -m "vX.Y.Z"
git push origin main vX.Y.Z

The release workflow publishes to npm via Trusted Publishing (OIDC, with provenance), pushes the multi-arch container image to GHCR, creates the GitHub release from the CHANGELOG section, and updates the entry in the official MCP registry.

Contributing

Issues, discussions and pull requests are welcome — see CONTRIBUTING.md. For vulnerabilities please use private reporting rather than a public issue; the policy is in SECURITY.md.

License

MIT © Willi Thiel

Available Tools

11 tools
create_clientCreate WireGuard clientA

Create a new WireGuard client. Keys and IP addresses are generated by wg-easy. Returns the new client ID.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameYesDisplay name of the new client
expiresAtNoOptional expiry date as ISO string (e.g. 2026-12-31). Omit for no expiry.

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the burden of disclosing behavior. It mentions that keys and IPs are auto-generated by wg-easy and that the new client ID is returned. However, it does not disclose potential side effects, permission requirements, or whether the client is immediately active.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two concise sentences that front-load the core action and provide useful follow-up context. No unnecessary words or repetition.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description is sufficient for a simple creation tool with full schema coverage. It explains the core behavior, auto-generation, and return value. It lacks optional details like default state or uniqueness constraints, but these are not critical for basic usage.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema fully describes both parameters (name required, expiresAt optional) with descriptions, so baseline is 3. The description adds no additional parameter-level meaning; it only notes that keys/IPs are generated, which is implied by the tool's purpose.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: creating a new WireGuard client. It specifies the action (create), the resource (WireGuard client), and additional outcomes (generated keys/IPs, returns client ID). The verb 'create' distinguishes it from sibling tools that list, get, update, enable, disable, delete, or fetch configs.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage when a new client needs to be added, but it does not explicitly state when to use this tool versus alternatives like update_client or enable_client. It provides no exclusion criteria or conditional guidance.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

delete_clientDelete WireGuard clientA
Destructive

Permanently delete a WireGuard client. This is irreversible: the client loses VPN access and its keys cannot be restored. The first call returns a short-lived confirmation token; ask the user for confirmation, then call again with confirmToken.

ParametersJSON Schema
NameRequiredDescriptionDefault
clientIdYesNumeric ID of the client (see list_clients)
confirmTokenNoConfirmation token from a previous delete_client call for the same client. Omit on the first call.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description goes well beyond the destructiveHint annotation by explicitly stating the irreversible consequences: 'This is irreversible: the client loses VPN access and its keys cannot be restored.' It also reveals the behavioral nuance of requiring a confirmation token, which is not available in annotations. This fully informs the agent of the tool's operational traits.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is three sentences, each earning its place: purpose, irreversibility, and the confirmation flow. It is front-loaded with the primary action and contains no filler or redundant phrases. This is an excellent balance of completeness and brevity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the lack of an output schema, the description adequately covers all necessary behavioral context for a destructive operation. It explains the irreversible nature, the confirmation token workflow, and the impact on the client. The tool's complexity is fully addressed without needing to describe return formats.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema provides 100% coverage of both parameters (clientId and confirmToken) with their own descriptions. The tool description adds extra semantics by explaining why confirmToken is needed and its role in the two-step confirmation process. While the schema alone would be sufficient, the description enriches the understanding of the parameter behavior.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's primary function: 'Permanently delete a WireGuard client.' This is a specific verb+resource combination that fully distinguishes it from sibling tools like get_client, update_client, or disable_client. The title reinforces the action, and the description adds critical scope (permanent deletion, loss of VPN access).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context by explaining the two-step confirmation flow: 'The first call returns a short-lived confirmation token; ask the user for confirmation, then call again with confirmToken.' This tells the agent when to call again and how to use the token. However, it does not explicitly mention alternatives (e.g., when to prefer disable_client over delete_client), so it lacks explicit when-not conditions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

disable_clientDisable WireGuard clientA
Idempotent

Disable a WireGuard client. The client keeps its configuration but can no longer connect.

ParametersJSON Schema
NameRequiredDescriptionDefault
clientIdYesNumeric ID of the client (see list_clients)

TDQS

A4.3/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With idempotentHint annotation present, the description adds value by detailing the non-destructive nature ('keeps its configuration') and the effect ('can no longer connect'), going beyond the annotation. It omits active connection handling but remains sufficient given the annotation coverage.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, direct and free of fluff. The purpose and key behavioral constraint are front-loaded, with no unnecessary words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Simple one-parameter tool with good schema and annotation coverage. Description covers purpose, effect, and non-destructive behavior; no output schema exists. Adequate for tool selection and invocation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Input schema covers 100% of parameters, with clientId described as 'Numeric ID of the client (see list_clients).' The description adds no parameter-level detail, so the baseline score of 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description states 'Disable a WireGuard client' with a specific verb and resource. It further clarifies the client 'keeps its configuration but can no longer connect,' distinguishing it from delete_client and clearly opposing enable_client.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Provides clear context: it disables access while preserving configuration, implying a temporary revocation use case. However, it does not explicitly name alternatives like delete_client or enable_client, so exclusions are implicit rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

enable_clientEnable WireGuard clientA
Idempotent

Enable a WireGuard client so it can connect again.

ParametersJSON Schema
NameRequiredDescriptionDefault
clientIdYesNumeric ID of the client (see list_clients)

TDQS

A4/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotations already declare idempotentHint=true, so the description does not need to restate that. The description adds minimal behavioral context beyond the annotation, such as the effect of enabling the client. It does not contradict the annotations, but also does not disclose additional details like what happens if the client is already enabled.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, concise sentence that directly states the tool's purpose. It contains no fluff or redundant information, making it optimally concise and well-structured for quick agent comprehension.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool is simple with one parameter and no output schema, and the description combined with the idempotent annotation provides sufficient context for an agent to understand the operation. However, it does not mention return value or behavior when already enabled, which would be useful but is not critical given the idempotent annotation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema fully documents the single parameter (clientId) with a description and constraints, achieving 100% schema coverage. The description itself adds no parameter-specific information, so it relies on the schema as baseline. No further semantic enrichment is provided.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb 'Enable' with a clear resource 'WireGuard client' and adds the purpose 'so it can connect again', which clearly differentiates it from siblings like disable_client or create_client. It also implicitly indicates a state transition from disabled to enabled.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'so it can connect again' provides clear context that this tool is for re-enabling a previously disabled client, which distinguishes it from create_client or update_client. However, it does not explicitly state when not to use it or name alternatives, so it misses the top score for explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_clientGet WireGuard clientA
Read-only

Get the full details of a single WireGuard client.

ParametersJSON Schema
NameRequiredDescriptionDefault
clientIdYesNumeric ID of the client (see list_clients)

TDQS

A3.8/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint: true, covering the safety profile. The description adds the scoping promise of 'full details' and 'single', but does not disclose return format, pagination, error behavior, or authentication requirements, providing limited additional behavioral transparency.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single sentence of eight words, front-loaded with the verb 'Get', and contains no filler words. Every word contributes to understanding the tool's purpose.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple single-parameter read tool with a read-only annotation, the description is mostly adequate. It clearly states the operation and scope, though 'full details' is vague and there is no output schema to define the return structure. Still, the context is sufficient for an agent to select the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The only parameter clientId is fully described in the schema with a type, range, and a cross-reference to list_clients, giving 100% schema coverage. The description adds no parameter-specific semantics, so baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses the specific verb 'Get', identifies the resource as 'WireGuard client', and specifies scope with 'single', which clearly distinguishes it from list_clients and other get variants like get_client_config or get_client_qrcode.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage for fetching a single client's details via the word 'single', but it does not explicitly state when to use this tool versus alternatives, nor does it mention exclusions or prerequisites beyond the schema's reference to list_clients.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_client_configGet WireGuard client configurationA
Read-only

Get the WireGuard configuration file (wg .conf format) for a client. SENSITIVE: the output contains the client private key — treat it as a secret and do not repeat it unnecessarily.

ParametersJSON Schema
NameRequiredDescriptionDefault
clientIdYesNumeric ID of the client (see list_clients)

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The annotation already declares readOnlyHint=true, but the description adds critical security context: the output contains the client private key and should be treated as secret. It also discloses the output format (wg .conf), going beyond the structured annotation.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two sentences, front-loaded with the core function and a concise security warning. Every word earns its place with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The tool has a single parameter, read-only annotation, and no output schema. The description explains the return format ('wg .conf') and adds the vital sensitivity caveat, covering all essential context for correct use.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema fully describes clientId with 'Numeric ID of the client (see list_clients)', so baseline 3 applies. The description adds no extra parameter meaning, but none is needed.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('Get') and resource ('WireGuard configuration file (wg .conf format)') clearly distinguishing it from siblings like get_client_qrcode or get_client. It states exactly what is returned.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines2/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

No explicit guidance on when to use this tool vs alternatives. The description does not mention get_client_qrcode, generate_one_time_link, or other related tools, so an agent receives no help choosing among them beyond the tool's name.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_client_qrcodeGet WireGuard client QR codeA
Read-only

Get the client configuration as a QR code (SVG markup) for scanning with the WireGuard mobile app. SENSITIVE: the QR code encodes the client private key — treat it as a secret.

ParametersJSON Schema
NameRequiredDescriptionDefault
clientIdYesNumeric ID of the client (see list_clients)

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description discloses that the QR code encodes the client private key and explicitly warns to treat it as a secret, providing critical security context beyond the readOnlyHint annotation. It also specifies the output format as SVG markup, which is useful behavioral information.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two concise sentences: the first states the purpose and output format, the second delivers a necessary security warning. Every word adds value, with no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a single-parameter read-only tool with full schema coverage, the description adequately covers the essential context: what it returns (SVG QR code), why it is used (mobile app scanning), and a critical sensitivity warning. The lack of an output schema is mitigated by the explicit mention of the return format.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The only parameter, clientId, is fully described in the schema with type, range, and a reference to list_clients. The description adds no extra parameter semantics, so the baseline of 3 is appropriate given 100% schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states it retrieves the client configuration as a QR code in SVG markup for use with the WireGuard mobile app. The specific verb 'Get' plus the resource 'client QR code' distinguishes it from sibling tools like get_client_config, which returns plain configuration text.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'for scanning with the WireGuard mobile app' provides clear context on when to use this tool. However, it does not explicitly mention alternatives or state when not to use it, e.g., versus get_client_config, so it slightly misses the top score.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_server_infoGet wg-easy server infoA
Read-only

Get information about the wg-easy instance: release/update status, general settings and the WireGuard interface configuration. Secret fields (private keys, passwords) are redacted.

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The readOnlyHint annotation already signals a read-only operation, and the description adds useful behavioral context by stating that secret fields (private keys, passwords) are redacted. This goes beyond the annotation and gives the agent important safety information.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and front-loaded, consisting of two sentences that first state the main purpose and then add the redaction behavior. Every sentence earns its place with no wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple getter with no parameters and no output schema, the description covers the key information categories (release/update status, settings, interface config) and the redaction behavior. It is slightly limited in not detailing the return format, but this is a minor gap for a tool of this simplicity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool has zero parameters, so there is no parameter semantics to clarify. The description doesn't need to add anything here, which meets the baseline of 4 for parameter-less tools.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose: to get information about the wg-easy instance, specifying categories such as release/update status, general settings, and WireGuard interface configuration. This distinguishes it from the sibling tools, which are all client-focused (list_clients, create_client, etc.).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies it is for server-level information, but it does not explicitly state when to use this tool over alternatives or mention any exclusions. Usage guidance is therefore implied rather than stated.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_clientsList WireGuard clientsA
Read-only

List all WireGuard clients of the wg-easy instance, including their status (enabled/expired), addresses and traffic statistics.

ParametersJSON Schema
NameRequiredDescriptionDefault
sortNoSort by name, ascending or descending
filterNoOptional name filter (substring match)

TDQS

A4.2/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The readOnlyHint annotation already indicates a safe read operation, and the description adds meaningful context by specifying the returned fields (status, addresses, traffic statistics) and that it lists all clients. It does not overstate behavior or contradict annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a single, well-structured sentence that starts with the action and includes all essential information without unnecessary words. It wastes no space and is easy to parse.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a relatively simple list operation, the description plus schema and readOnlyHint provide enough context. It states the scope ('all clients') and the key return contents. A minor gap is the absence of a mention of response shape or array format, but this is not critical given no output schema and the straightforward nature of the tool.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with both 'sort' and 'filter' clearly documented in the input schema. The tool description adds no additional parameter-level detail, but the schema fully covers semantics, so the baseline score of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description uses a specific verb ('List') and clearly identifies the resource ('all WireGuard clients of the wg-easy instance') and the information returned (status, addresses, traffic statistics). This effectively distinguishes it from sibling tools like get_client, create_client, and delete_client.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The phrase 'List all WireGuard clients' clearly conveys when to use this tool: when you need a complete overview of clients rather than a single client (get_client) or a mutating operation. However, it does not explicitly mention alternative tools or exclusion criteria, so it stops short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

update_clientUpdate WireGuard clientA

Update a WireGuard client. Only the provided fields are changed; all other settings are preserved.

ParametersJSON Schema
NameRequiredDescriptionDefault
dnsNoDNS servers for the client, or null to use the server default
mtuNoMTU for the client
nameNoNew display name
enabledNoEnable or disable the client
clientIdYesNumeric ID of the client (see list_clients)
expiresAtNoExpiry date as ISO string, or null to remove the expiry
allowedIpsNoCIDRs routed through the tunnel on the client side, or null to use the server default
ipv4AddressNoIPv4 address of the client
ipv6AddressNoIPv6 address of the client
serverAllowedIpsNoAdditional CIDRs the server routes to this client
persistentKeepaliveNoPersistent keepalive interval in seconds (0 = off)

TDQS

A3.9/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations are empty, so the description carries the burden of behavioral disclosure. It explicitly states that only provided fields are changed and all other settings are preserved, which is important partial-update semantics. It does not mention permissions or error behavior, so it is not a 5.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two short sentences with no filler. The most important behavioral detail, partial updates with preservation of other settings, is included immediately after the purpose statement.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers the core update semantics, but with no annotations and no output schema, there is no mention of return values, error behavior, or how this relates to dedicated enable/disable tools. For an 11-parameter mutation tool, slightly more context would be helpful.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents all parameters. The description adds only the general partial-update concept and no per-parameter detail, which matches the baseline for full schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a clear verb and resource: 'Update a WireGuard client.' The added sentence about partial updates distinguishes it from create/delete/get tools and clarifies its scope. This is unambiguous and easily distinguished from sibling tools like create_client or delete_client.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description implies usage: use when you need to modify an existing client. However, it does not explicitly state when to prefer this over siblings like enable_client or disable_client, nor does it mention exclusions or alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool update
    • Changedupdate_client2 fields changed
      • removedInput schema / properties / expiresAt / anyOf
        Removed value: -[
        -  {
        -    "type": "string"
        -  },
        -  {
        -    "type": "null"
        -  }
        -]
      • addedInput schema / properties / expiresAt / type
        Added value: +[
        +  "string",
        +  "null"
        +]
  2. 10 tool updatesv0.2.2
    • Changedcreate_client1 field changed
      • removedInput schema / additionalProperties
        Removed value: -false
    • Changeddelete_client4 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / clientId / maximum
        Added value: +9007199254740991
      • removedInput schema / properties / confirm
        Removed value: -{
        -  "default": false,
        -  "description": "Must be true to actually delete the client. Ask the user for confirmation first.",
        -  "type": "boolean"
        -}
      • addedInput schema / properties / confirmToken
        Added value: +{
        +  "description": "Confirmation token from a previous delete_client call for the same client. Omit on the first call.",
        +  "type": "string"
        +}
    • Changeddisable_client2 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / clientId / maximum
        Added value: +9007199254740991
    • Changedenable_client2 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / clientId / maximum
        Added value: +9007199254740991
    • Changedgenerate_one_time_link2 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / clientId / maximum
        Added value: +9007199254740991
    • Changedget_client2 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / clientId / maximum
        Added value: +9007199254740991
    • Changedget_client_config2 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / clientId / maximum
        Added value: +9007199254740991
    • Changedget_client_qrcode2 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / clientId / maximum
        Added value: +9007199254740991
    • Changedlist_clients1 field changed
      • removedInput schema / additionalProperties
        Removed value: -false
    • Changedupdate_client8 fields changed
      • removedInput schema / additionalProperties
        Removed value: -false
      • addedInput schema / properties / clientId / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / expiresAt / anyOf
        Added value: +[
        +  {
        +    "type": "string"
        +  },
        +  {
        +    "type": "null"
        +  }
        +]
      • removedInput schema / properties / expiresAt / type
        Removed value: -[
        -  "string",
        -  "null"
        -]
      • addedInput schema / properties / mtu / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / mtu / minimum
        Added value: +-9007199254740991
      • addedInput schema / properties / persistentKeepalive / maximum
        Added value: +9007199254740991
      • addedInput schema / properties / persistentKeepalive / minimum
        Added value: +-9007199254740991
  3. 11 tool updatesv0.1.0
    • First observedcreate_client
    • First observeddelete_client
    • First observeddisable_client
    • First observedenable_client
    • First observedgenerate_one_time_link
    • First observedget_client
    • First observedget_client_config
    • First observedget_client_qrcode
    • First observedget_server_info
    • First observedlist_clients
    • First observedupdate_client

TDQS

A4.3/5.0

Scored across 11 tools

Disambiguation5/5

Each tool maps cleanly to a distinct resource and action: client list/get/create/update/enable/disable/delete, server info, and three clearly separated config delivery methods (raw file, QR code, one-time link). Although multiple tools surface client configuration, their output formats and purposes are explicitly distinct.

Naming Consistency5/5

All tool names follow a consistent verb_noun snake_case pattern, using standard lifecycle verbs (list, get, create, update, enable, disable, delete). Config-related tools are uniformly prefixed with get_client_ or generate_one_time_link, making the naming predictable.

Tool Count5/5

Eleven tools is a well-scoped size for a WireGuard client management server: it covers the full client lifecycle plus configuration delivery and server info without redundancy. Each tool serves a distinct need and none feels like filler.

Completeness5/5

The surface provides complete CRUD lifecycle coverage for clients (list, get, create, update, delete) along with operational actions (enable/disable) that wg-easy users need. Configuration retrieval is covered in multiple practical formats, including a shareable one-time link, and server info rounds out the domain.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers