Skip to main content
Glama

pterodactyl-mcp

CI License: MIT Node.js >= 22 MCP

Let an AI assistant look after your game server — safely.

pterodactyl-mcp is a Model Context Protocol server that connects Claude (or any MCP client) to a server hosted on Pterodactyl Panel. Ask about the server in plain language and the assistant can check its status, read the console and log files, edit configs, take backups and restart it — with guardrails that stop a confused model from deleting your world.

It works with any Pterodactyl panel — self-hosted or a commercial host — using an ordinary Client API key from your account page. No panel admin access or plugins required.

Things you can ask:

  • "Is the server up, and what's the memory doing?"

  • "Something's wrong — pull the recent console output and tell me what's failing."

  • "Did Geyser actually bind to its Bedrock port on the last boot?"

  • "Take a backup, then change the Bedrock MOTD in the Geyser config."

  • "Upload this plugin jar and restart the server."

More examples, with what happens behind the scenes: docs/USE_CASES.md. Ready-to-paste prompts, including a daily/weekly/monthly activity report: docs/PROMPTS.md.

Features

  • 20 tools covering servers, live resources, console, files (including binary uploads), power, backups, schedules, network allocations and startup variables.

  • Read-only mode for day-to-day diagnosis — register a second, write-enabled profile only for maintenance.

  • Human confirmation before anything destructive, via MCP elicitation when your client supports it, or a single-use preview-and-confirm token when it doesn't.

  • Automatic backup before file writes, deletes and kill — and the change is aborted if the backup fails.

  • Protected paths (world folders, server.properties, ops.json, … by default) that write and delete tools refuse to touch.

  • Blast-radius limits — per-process mutation budget, 10-file bulk-delete cap, 30-second power cooldown.

  • Append-only audit log of every attempted, refused and completed change, with secrets redacted.

  • Console-aware — reads the Wings websocket, and tells the model to use logs/latest.log when the output it wants has already scrolled out of the buffer.

These guards protect against mistakes, not attackers. Anyone holding the API key can do everything this server does directly in the panel. See How mutations work for the full safety model.

Related MCP server: Pterodactyl MCP Server

Contents

Quick start

You need Node.js 22 or newer and a Pterodactyl Client API key (how to get one).

1. Build it

git clone https://github.com/N1jada/pterodactyl-mcp.git
cd pterodactyl-mcp
npm install
npm run build

2. Find your server's short ID — it's the 8-character code in the panel URL when you open the server, e.g. https://panel.example.com/server/1a2b3c4d.

3. Register it with Claude Code as a read-only profile (the safe default):

claude mcp add pterodactyl-ro \
  -e PTERODACTYL_PANEL_URL=https://panel.example.com \
  -e PTERODACTYL_API_KEY=ptlc_your_key_here \
  -e PTERODACTYL_DEFAULT_SERVER=1a2b3c4d \
  -e PTERODACTYL_READ_ONLY=true \
  -- node "$(pwd)/dist/index.js"

Then ask Claude "What's the status of my server?". When you're ready to let it make changes, add the maintenance profile too. Using Claude Desktop or another client? See Claude Desktop — any MCP client that can launch a stdio server works.

Want to try it without a real server? A mock panel is included:

node test/mock-panel/server.mjs 4567 &    # fake panel on http://127.0.0.1:4567
npx @modelcontextprotocol/inspector --cli node dist/index.js \
  -e PTERODACTYL_PANEL_URL=http://127.0.0.1:4567 -e PTERODACTYL_API_KEY=mock-key \
  -e PTERODACTYL_DEFAULT_SERVER=1a2b3c4d \
  --method tools/call --tool-name ptero_get_server_resources

Or point any profile above at http://127.0.0.1:4567 with the key mock-key.

Generating a Pterodactyl Client API key

  1. Log into the panel (e.g. https://your-panel.example.com).

  2. Go to Account → API Credentials.

  3. Create a new API key. This produces a Client key, prefixed ptlc_....

  4. Restricting Allowed IPs is optional — leave it blank unless you want to pin the key to the machine running this server.

Use a Client key (ptlc_...), not an Application (admin) key. Application keys are for the Application API (users, nodes, server provisioning) and are rejected outright on every Client API route this server calls.

Configuration

All configuration is environment variables, loaded once at startup by src/config.ts. Values are frozen after load; restart the server to pick up changes. Booleans accept 1/true/yes/on and 0/false/no/off (case-insensitive).

Required

Variable

Default

Effect

PTERODACTYL_PANEL_URL

—

Panel base URL, e.g. https://panel.example.com. No trailing slash, no /api/client suffix — that's appended internally. Must be http:// or https://.

PTERODACTYL_API_KEY

—

The Client API key (ptlc_...) from above. Never logged, never audited, never included in an error message.

Optional

Variable

Default

Effect

PTERODACTYL_DEFAULT_SERVER

unset

Server short identifier (e.g. 1a2b3c4d) used when a tool call omits its server argument.

PTERODACTYL_MAX_READ_BYTES

524288 (512 KiB)

Default largest file ptero_read_file will return; refuses larger files with a message suggesting the caller narrow the request or pass a larger max_bytes. A per-call max_bytes argument can override this, but is itself hard-capped at 4194304 bytes (4 MiB, the panel's own edit-size limit) regardless of how high this variable is set.

Guardrails

Variable

Default

Effect

PTERODACTYL_READ_ONLY

false

When true, every mutating tool refuses outright. Recommended for the day-to-day profile.

PTERODACTYL_ALLOWED_SERVERS

unset

Comma-separated allowlist of server short IDs a mutating call may target. If unset and PTERODACTYL_DEFAULT_SERVER is also unset, the guard fails closed: every mutating call is refused, since there is no way to tell which server was meant to be in bounds.

PTERODACTYL_ALLOW_DELETE

false

File and backup deletion refuse unless this is true.

PTERODACTYL_ALLOW_KILL

false

The kill power signal refuses unless this is true (risks world corruption — it does not save before terminating).

PTERODACTYL_PROTECTED_PATHS

world/**, world_nether/**, world_the_end/**, server.properties, ops.json, whitelist.json, banned-*.json

Comma-separated glob patterns that write/delete tools refuse to touch. Matching is case-sensitive, backslashes are normalised to / first, and percent-encoded path segments are decoded (and re-checked) before matching, so a %2e%2e or world%2Flevel.dat-style argument can't slip past it. A path containing a .. segment, or one that resolves to the server root ("", /, ., ./), is always refused regardless of this list. Setting this variable to an empty string does not disable protection — an empty value is treated the same as unset and the built-in defaults still apply; to genuinely disable it you must supply a pattern that matches nothing.

PTERODACTYL_UNPROTECTED_PATHS

unset

Comma-separated globs carved back out of PTERODACTYL_PROTECTED_PATHS. A path that matches one of these is not refused by the protected-path check, so a deploy profile can open exactly world/datapacks/mypack/** without unprotecting the world. The .. and server-root refusals still apply regardless, and every percent-decoding of the path must fall inside the exception.

PTERODACTYL_MAX_MUTATIONS

20

Mutating tool calls allowed per process lifetime; refuses once exhausted. Restart the process to reset the budget.

PTERODACTYL_AUTO_BACKUP

true

Take a backup automatically before any file write, file delete, or kill; abort the operation if the backup fails.

PTERODACTYL_AUDIT_LOG

~/.pterodactyl-mcp/audit.jsonl

Path to the append-only JSONL audit trail. Relative paths are resolved against the process's working directory.

Allowed-servers semantics (PTERODACTYL_ALLOWED_SERVERS, per src/config.ts / src/guard.ts):

  • Set (comma-separated list): a mutating call is allowed only against a server short ID in that list.

  • Unset, but PTERODACTYL_DEFAULT_SERVER is set: the allowlist defaults to [defaultServer] — mutations are restricted to that one server only.

  • Neither set: the guard fails closed — every mutating call is refused with PTERODACTYL_ALLOWED_SERVERS named as the variable to set, because "which server may I change?" has to be answered deliberately rather than left open by omission. (Read-only tools are never restricted by this variable in any case; you always need an explicit server argument or a default to resolve which server a call targets at all.)

Registering with Claude Code

Register the server twice, with different configs: a read-only profile for day-to-day inspection, and a full-access profile you enable deliberately for maintenance. Most diagnostic work needs no write access at all — treat pterodactyl-ro as the default, and reach for pterodactyl-admin only when you intend to change something.

Replace /absolute/path/to/dist/index.js, the panel URL, the API key, and the server ID with your own values in every example below.

claude mcp add

Read-only (default) profile:

claude mcp add pterodactyl-ro \
  -e PTERODACTYL_PANEL_URL=https://panel.example.com \
  -e PTERODACTYL_API_KEY=ptlc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
  -e PTERODACTYL_DEFAULT_SERVER=1a2b3c4d \
  -e PTERODACTYL_READ_ONLY=true \
  -- node /absolute/path/to/dist/index.js

Full-access (maintenance) profile — ALLOW_DELETE/ALLOW_KILL are left false here; turn them on only for the session where you actually need them:

claude mcp add pterodactyl-admin \
  -e PTERODACTYL_PANEL_URL=https://panel.example.com \
  -e PTERODACTYL_API_KEY=ptlc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx \
  -e PTERODACTYL_DEFAULT_SERVER=1a2b3c4d \
  -e PTERODACTYL_AUTO_BACKUP=true \
  -e PTERODACTYL_ALLOW_DELETE=false \
  -e PTERODACTYL_ALLOW_KILL=false \
  -- node /absolute/path/to/dist/index.js

.mcp.json

Equivalent project-level config (.mcp.json in your project root):

{
  "mcpServers": {
    "pterodactyl-ro": {
      "command": "node",
      "args": ["/absolute/path/to/dist/index.js"],
      "env": {
        "PTERODACTYL_PANEL_URL": "https://panel.example.com",
        "PTERODACTYL_API_KEY": "ptlc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "PTERODACTYL_DEFAULT_SERVER": "1a2b3c4d",
        "PTERODACTYL_READ_ONLY": "true"
      }
    },
    "pterodactyl-admin": {
      "command": "node",
      "args": ["/absolute/path/to/dist/index.js"],
      "env": {
        "PTERODACTYL_PANEL_URL": "https://panel.example.com",
        "PTERODACTYL_API_KEY": "ptlc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "PTERODACTYL_DEFAULT_SERVER": "1a2b3c4d",
        "PTERODACTYL_AUTO_BACKUP": "true",
        "PTERODACTYL_ALLOW_DELETE": "false",
        "PTERODACTYL_ALLOW_KILL": "false"
      }
    }
  }
}

Claude Desktop

Add to claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json):

{
  "mcpServers": {
    "pterodactyl-ro": {
      "command": "node",
      "args": ["/absolute/path/to/dist/index.js"],
      "env": {
        "PTERODACTYL_PANEL_URL": "https://panel.example.com",
        "PTERODACTYL_API_KEY": "ptlc_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
        "PTERODACTYL_DEFAULT_SERVER": "1a2b3c4d",
        "PTERODACTYL_READ_ONLY": "true"
      }
    }
  }
}

Add a second pterodactyl-admin entry the same way as the .mcp.json example above if you want the maintenance profile available in Desktop too.

Tools

All tools are prefixed ptero_. readOnlyHint/destructiveHint/idempotentHint are advisory annotations per the MCP spec — clients are free to ignore them, which is exactly why the guard module (not annotations) is the real enforcement mechanism for mutating tools. openWorldHint is false for every tool: the panel is a closed, known system.

Tool

Purpose

readOnly

destructive

idempotent

openWorld

Guarded by

ptero_list_servers

List servers this API key can access (identifier, node, primary allocation, limits). Call first when you don't know a server's identifier.

true

false

true

false

— (read-only)

ptero_get_server

Full static configuration for one server: limits, feature limits, allocations, SFTP host, Docker image, resolved startup command.

true

false

true

false

— (read-only)

ptero_get_server_resources

Live power state (running/offline/...) and current CPU, memory, disk, network, uptime.

true

false

true

false

— (read-only)

ptero_get_console_log

Recent console output collected from the Wings websocket over a bounded window. See Console caveats.

true

false

true

false

— (read-only)

ptero_send_console_command

Send a command to the running server's console. Confirms dispatch only — does not return the command's output.

false

true

false

false

PTERODACTYL_READ_ONLY, PTERODACTYL_ALLOWED_SERVERS, PTERODACTYL_MAX_MUTATIONS, dry_run. No confirmation prompt (not classified destructive by the guard) and no auto-backup.

ptero_list_files

Directory listing relative to the server root.

true

false

true

false

— (read-only)

ptero_read_file

Read a file's contents. Refuses files above PTERODACTYL_MAX_READ_BYTES.

true

false

true

false

— (read-only)

ptero_write_file

Write/overwrite a file.

false

true

true

false

PTERODACTYL_READ_ONLY, PTERODACTYL_ALLOWED_SERVERS, PTERODACTYL_PROTECTED_PATHS, PTERODACTYL_MAX_MUTATIONS, PTERODACTYL_AUTO_BACKUP. Confirmation is required only when overwriting an existing file; writing a new path does not require it.

ptero_upload_file

Upload a binary local file (plugin jar, zip, image) from the machine running this MCP server to the game server. The complement to ptero_write_file, which is text-only.

false

true

true

false

PTERODACTYL_READ_ONLY, PTERODACTYL_ALLOWED_SERVERS, PTERODACTYL_PROTECTED_PATHS, PTERODACTYL_MAX_MUTATIONS, PTERODACTYL_AUTO_BACKUP, plus a hard 64 MiB local-file cap. Confirmation is required only when the remote file already exists (or existence could not be determined).

ptero_rename_file

Rename/move a file.

false

false

false

false

PTERODACTYL_READ_ONLY, PTERODACTYL_ALLOWED_SERVERS, PTERODACTYL_PROTECTED_PATHS, PTERODACTYL_MAX_MUTATIONS. No confirmation, no auto-backup.

ptero_copy_file

Copy a file.

false

false

false

false

Same as ptero_rename_file.

ptero_delete_file

Delete one or more files.

false

true

true

false

PTERODACTYL_READ_ONLY, PTERODACTYL_ALLOWED_SERVERS, PTERODACTYL_ALLOW_DELETE, PTERODACTYL_PROTECTED_PATHS, PTERODACTYL_MAX_MUTATIONS, 10-file bulk-delete cap, PTERODACTYL_AUTO_BACKUP. Always requires confirmation.

ptero_set_power_state

start / stop / restart / kill. Prefer stop over kill — kill is a hard stop and risks world corruption.

false

true

false

false

PTERODACTYL_READ_ONLY, PTERODACTYL_ALLOWED_SERVERS, PTERODACTYL_ALLOW_KILL (for kill only), PTERODACTYL_MAX_MUTATIONS, 30-second power cooldown, PTERODACTYL_AUTO_BACKUP (for kill only). Confirmation required for stop/restart/kill; not for start.

ptero_list_backups

List backups for a server.

true

false

true

false

— (read-only)

ptero_create_backup

Create a backup. The natural thing to do before any risky change.

false

false

false

false

PTERODACTYL_READ_ONLY, PTERODACTYL_ALLOWED_SERVERS, PTERODACTYL_MAX_MUTATIONS. No confirmation prompt, no auto-backup-before-backup.

ptero_delete_backup

Delete a backup. Irreversible.

false

true

true

false

PTERODACTYL_READ_ONLY, PTERODACTYL_ALLOWED_SERVERS, PTERODACTYL_ALLOW_DELETE, PTERODACTYL_MAX_MUTATIONS. Always requires confirmation.

ptero_get_backup_download_url

Generate a signed, short-lived download URL for a backup.

true

false

true

false

— (read-only; the URL itself is a secret — see How mutations work)

ptero_list_schedules

Read the server's scheduled tasks.

true

false

true

false

— (read-only)

ptero_list_allocations

List network allocations (ports) assigned to the server.

true

false

true

false

— (read-only)

ptero_get_startup_variables

Startup command template and egg (environment) variables.

true

false

true

false

— (read-only)

The annotation columns match the registerTool(...) calls in src/tools/*.ts; a structural test (test/integration/guard-coverage.test.ts) fails if a mutating tool is ever registered without going through the guard.

Tool parameters

Every input parameter for every registered tool, verified against src/tools/*.ts, grouped by source file. server (short identifier, optional, falls back to PTERODACTYL_DEFAULT_SERVER) is omitted below since every tool takes it identically. For a mutating tool, "Guard" gives the MutationRequest fields it sets — kind, destructive, wantsAutoBackup, and any paths/fileCount/powerSignal — which drive the guard decisions summarised in the table above.

Servers (src/tools/servers.ts)

  • ptero_list_servers: page (integer ≥ 1, optional) — 1-based page number; omit for page 1.

  • ptero_get_server: no parameters beyond server.

  • ptero_get_server_resources: no parameters beyond server.

Console (src/tools/console.ts)

  • ptero_get_console_log:

    • window_seconds (integer 1-60, default 5) — collection window.

    • max_lines (integer 1-1000, default 400) — stop early once reached. The node backlog alone is ~150 lines, so the default leaves room to observe streamed output too.

    • filter (string, optional) — regex if filter parses as one, else a case-insensitive substring match, applied after collection.

  • ptero_send_console_command:

    • command (string, 1-4096 chars, single line, no \r/\n, trimmed, required).

    • dry_run (boolean, default false).

    • Guard: kind: 'command', destructive: false, wantsAutoBackup: false, no paths. Note: its annotations declare destructiveHint: true, but the guard's own destructive flag is false — so, unlike every other tool where the two agree, this one dispatches with no confirmation prompt and no auto-backup despite the advisory hint.

Files (src/tools/files.ts)

  • ptero_list_files: directory (string, default /).

  • ptero_read_file:

    • path (string, min 1 char, required).

    • max_bytes (integer, 1 to 4194304, optional; defaults to PTERODACTYL_MAX_READ_BYTES).

    • tail_lines (integer ≥ 1, optional; mutually exclusive with head_lines).

    • head_lines (integer ≥ 1, optional; mutually exclusive with tail_lines).

  • ptero_write_file:

    • path (string, min 1 char, required).

    • content (string, required) — replaces the entire file.

    • dry_run (boolean, default false).

    • confirmation_token (string, optional).

    • Guard: kind: 'write', paths: [path], destructive is true only when the file already exists (or existence couldn't be determined), wantsAutoBackup: true.

  • ptero_upload_file:

    • local_path (string, min 1 char, required) — absolute path on the machine running the MCP server. The server reads the bytes itself; there is no way to pass content inline, and nothing is ever accepted as base64 through the model. Must be an existing, readable, regular file of at most 64 MiB (MAX_UPLOAD_BYTES in src/tools/files.ts; Wings' own per-file default is 100 MB).

    • remote_dir (string, default /) — destination directory on the server, not a file path.

    • remote_name (string, min 1 char, optional; defaults to the basename of local_path) — a single file name, refused if it contains / or \\.

    • dry_run (boolean, default false).

    • confirmation_token (string, optional).

    • Guard: kind: 'write', paths: [remote_dir + remote_name], destructive is true only when the remote file already exists (or existence couldn't be determined), wantsAutoBackup: true.

  • ptero_rename_file:

    • root (string, default /) — directory from/to are relative to.

    • from (string, min 1 char, required).

    • to (string, min 1 char, required).

    • dry_run (boolean, default false).

    • confirmation_token (string, optional).

    • Guard: kind: 'write', paths: [from_path, to_path], destructive: false, wantsAutoBackup: false.

  • ptero_copy_file:

    • path (string, min 1 char, required).

    • dry_run (boolean, default false).

    • confirmation_token (string, optional).

    • Guard: kind: 'write', paths: [path], destructive: false, wantsAutoBackup: false.

  • ptero_delete_file:

    • root (string, default /).

    • files (array of string, min 1 char each, at least 1 entry, required) — bare names relative to root; more than 10 is refused by the guard's bulk-file cap, not by this schema.

    • dry_run (boolean, default false).

    • confirmation_token (string, optional).

    • Guard: kind: 'delete', paths = every resolved target, fileCount: files.length, destructive: true, wantsAutoBackup: true.

Power (src/tools/power.ts)

  • ptero_set_power_state:

    • signal (enum start | stop | restart | kill, required).

    • dry_run (boolean, default false).

    • confirmation_token (string, optional).

    • wait_seconds (integer 0-60, default 0) — poll every 2s after dispatch and report state_after.

    • Guard: kind: 'power', powerSignal: signal, destructive = signal !== 'start', wantsAutoBackup = signal === 'kill', no paths.

Backups (src/tools/backups.ts)

  • ptero_list_backups: per_page (integer 1-50, optional; the panel's own default is 20).

  • ptero_create_backup:

    • name (string, max 191 chars, optional) — omit for a panel-assigned default name.

    • ignored (string, optional) — newline-separated glob patterns to exclude.

    • wait (boolean, default true) — block until the panel reports the backup complete (up to ~2 minutes) via createBackupAndWait; false returns immediately with just the uuid.

    • dry_run (boolean, default false).

    • Guard: kind: 'backup_create', destructive: false, wantsAutoBackup: false, no paths. This tool has no confirmation_token parameter — it never needs one.

  • ptero_delete_backup:

    • backup_uuid (string, required).

    • dry_run (boolean, default false).

    • confirmation_token (string, optional).

    • Guard: kind: 'backup_delete', destructive: true, wantsAutoBackup: false, no paths.

  • ptero_get_backup_download_url: backup_uuid (string, required). Not a mutating tool — it does not go through the guard or the audit log at all (see How mutations work).

Schedules, allocations & startup (src/tools/misc.ts)

  • ptero_list_schedules: no parameters beyond server.

  • ptero_list_allocations: no parameters beyond server.

  • ptero_get_startup_variables: no parameters beyond server.

Uploading binaries (ptero_upload_file)

ptero_write_file posts a UTF-8 request body to the panel, so it cannot carry a jar or a zip. Uploads take a different route, in two hops, both of which this tool performs for you:

  1. GET /api/client/servers/{id}/files/upload at the panel (with the API key) returns {"object":"signed_url","attributes":{"url":"https://<node>:<port>/upload/file?token=<jwt>"}}. The JWT is scoped FileUpload, lives 15 minutes, and is single-use — so the tool mints a fresh one inside every upload and never stores or reuses one.

  2. POST <that url>&directory=<remote_dir> goes straight to the Wings node, as multipart/form-data with the file in a field named files whose part filename is the name it will get on disk. The panel API key is deliberately not sent on this hop: Wings registers /upload/file outside its authorization middleware and authenticates from the token query parameter alone.

Wings answers a successful upload with an empty 200. That is a confirmation of receipt and nothing more — it does not tell you the file landed at the size you sent. Follow every upload with ptero_list_files on remote_dir and compare the size against the bytes the tool reports. (A new plugin jar also needs a server restart before it loads.)

The signed URL is a credential: like ptero_get_backup_download_url's URL it is never written to the audit log, and unlike that one it is never returned to the caller either.

How mutations work

Every mutating tool routes through a single Guard before it does anything, and returns one of four status values in its structured result:

  • dry_run — you passed dry_run: true. Nothing changed; the response's preview shows what would happen. No confirmation token is issued and this does not count against PTERODACTYL_MAX_MUTATIONS.

  • needs_confirmation — the operation is destructive and the connected MCP client does not support elicitation (see below). The response carries a preview of exactly what will change, and a confirmation_token that:

    • is generated server-side, cryptographically random, and never derivable by the caller;

    • is bound to a hash of tool name + server ID + normalised arguments AND the resolved effect (kind, the resolved paths, the power signal, and the effective file count) — changing any argument, or anything about what the call would actually touch, on the confirming call invalidates it;

    • is single-use and expires after 120 seconds;

    • lives in memory only, never persisted to disk, and is process-local: if the MCP client restarts the server between the two calls the token is unknown and a fresh preview is required.

    This preview is for the human, not for the calling model to round-trip silently. Surface it in your reply and wait for the user to approve before calling the tool again with confirmation_token set.

  • refused — a guardrail blocked the call. The response names the specific reason and the environment variable that would need to change to allow it, e.g. Refused: file deletion is disabled (variable: PTERODACTYL_ALLOW_DELETE).

  • success — the change was made. If a pre-flight backup was taken, its ID appears as backup_id in the response, giving you a concrete rollback path.

Elicitation vs. token fallback. When the connected client declares the MCP elicitation capability, destructive operations use elicitation/create instead of the token dance: the server presents the preview through the client's native confirmation UI and waits for an explicit accept/decline. Declining or dismissing is treated as a refusal, and so is a client that never answers: an elicitation that gets no response within 120 seconds (or whose request is aborted) times out and is treated as cancelled, i.e. refused — never as an implicit accept. When the client doesn't support elicitation, the two-phase token flow above is the fallback — functionally equivalent, just surfaced as a normal tool response instead of a UI prompt.

Power actions are rate-limited to one per 30 seconds, to stop restart loops — a second power action inside that window is refused, naming the seconds remaining.

Bulk file deletes are capped at 10 files per call. The guard checks max(fileCount, paths.length) against that cap, so an under-reported or omitted file count can't be used to sneak a larger operation past it — the number of paths actually resolved is always a floor on the effective count. A delete that resolves to more than 10 files either way is refused with a message to narrow the pattern; there is no legitimate reason for this server to remove a hundred files at once.

PTERODACTYL_MAX_MUTATIONS (default 20) is a budget of successful mutating calls per process lifetime — restart the server to reset it. It exists so a misbehaving agent loop can't run indefinitely.

Pre-flight backup (Layer 3). When a write, delete, or kill wants an automatic backup (PTERODACTYL_AUTO_BACKUP=true and the tool sets wantsAutoBackup), the guard calls createBackupAndWait and blocks the destructive change until that backup has actually completed — not merely been requested. The guard aborts the whole operation, refusing it outright, if the backup: throws (including a panel-reported failure), does not report a usable uuid, or does not complete within a hard 120-second timeout (BACKUP_TIMEOUT_MS in src/guard.ts, matching DEFAULT_TIMEOUT_MS in src/backupWait.ts) — a slow-but-eventually-successful backup does not get more time. The wait also honours the calling request's own cancellation: if the MCP client aborts the tool call while the backup is in flight, the guard stops waiting and refuses rather than proceeding with the destructive change anyway. This same instruction — prefer stop over kill, take a backup before risky changes, and surface confirmation previews to the human rather than round-tripping them automatically — is also given directly to the connected MCP client via the server's instructions string in src/index.ts.

Audit log. Every mutating call appends one or more JSON lines — dry_run, needs_confirmation, declined, refused, and, once a call actually proceeds, an attempted line followed by a final success or error line — to PTERODACTYL_AUDIT_LOG (default ~/.pterodactyl-mcp/audit.jsonl). A write failure is logged to stderr but never breaks the tool call. Example success line for a ptero_delete_file call (root plugins, one file, confirmed via token, with a pre-flight backup taken):

{"ts":"2026-09-05T10:15:32.041Z","tool":"ptero_delete_file","server":"1a2b3c4d","kind":"delete","args":{"server":"1a2b3c4d","root":"/plugins","files":["old-plugin.jar"]},"dry_run":false,"outcome":"success","paths":["plugins/old-plugin.jar"],"file_count":1,"confirmed_via":"token","backup_id":"3f2a1e4b-9c1d-4a5e-8b2f-6d7e8f9a0b1c","root":"/plugins","files":["old-plugin.jar"],"deleted_count":1}

args is exactly what the tool put in its MutationRequest.args (here server/root/files, not a path field — the shape differs per tool); the trailing root/files/deleted_count come from the tool's own result being merged onto the entry when the call commits. AuditEntry in src/audit.ts formally declares only ts/tool/server/args/kind/outcome/reason/ variable/confirmed_via/backup_id/error; the paths, power_signal, file_count, and per-tool result fields the guard also writes to every line are additional properties beyond that declared TypeScript shape — accepted at runtime (AuditSink.append takes a plain Record<string, unknown>), but worth knowing about if you parse the JSONL against the AuditEntry type.

Secrets are redacted from the audit log and from what's bound into a confirmation token — not from a tool's own return value. Before an entry is persisted, any argument or field whose key matches /token|key|secret|password|passwd|jwt|url|auth|bearer|credential|cookie|session/i is replaced with [REDACTED]; this same key-based pattern is applied independently in both src/guard.ts (for confirmation-token binding and previews) and src/audit.ts (for what actually reaches disk). On top of that, AuditLog also scrubs the literal value of the configured Pterodactyl API key (and any other configured secret) out of the fully-serialised line, so an API key pasted into, say, a console command argument is still caught even though its key name (command) doesn't look secret. None of this touches what a tool returns to its caller: ptero_get_backup_download_url, for instance, deliberately returns the real signed URL in its result (that's the point of the tool) — it just never reaches the audit trail, because that tool is read-only and never goes through the guard at all.

Console caveats

Pterodactyl doesn't expose console history over plain REST — the console is a Wings websocket, reached via a short-lived JWT minted per-call. Consequences that matter when using ptero_get_console_log / ptero_send_console_command:

  • The backlog buffer is small — 150 lines by default (Wings' system.websocket_log_count, admin-configurable per node). An hour after boot, plugin startup output has typically already rolled out of it.

  • For anything from boot time, use ptero_read_file on logs/latest.log instead — it has the full history the websocket buffer does not. This is the single most common mistake an agent will make here: querying the console for old output and confidently reporting "no such line" when it simply rolled off the buffer.

  • Command output is asynchronous. ptero_send_console_command only confirms that the command was dispatched to the daemon — Wings does not correlate responses with the command that produced them. Read the console (or the log file) separately, afterward, to see what actually happened.

Known limitations / open questions

  • Host-restricted endpoints. Some hosts sit in front of Pterodactyl and disable parts of the Client API. A Client API call that consistently 403s may be a host restriction rather than a key or permission problem — the error text calls this out, but there is no way for this server to detect or work around it. If you hit this, check with your host.

  • Panel extensions. Some panels run an extension framework (e.g. Blueprint) on top of Pterodactyl. Whether such extensions add or alter Client API endpoints is panel-specific — worth checking if something behaves unexpectedly.

  • Rate limit discrepancy. Community docs for the Pterodactyl Client API describe a default of 240 requests/minute; the current pterodactyl/panel source (1.0-develop) defaults to 256/minute, admin-configurable via APP_API_CLIENT_RATELIMIT. This server does not hardcode either number — it reads X-RateLimit-Limit / X-RateLimit-Remaining / X-RateLimit-Reset from response headers and, on a 429, reports the actual reset time rather than guessing. Treat the true limit as whatever your panel's own config sets.

  • Live verification. Every read-only tool, and the mutating file, backup, upload and console-command tools, have been run against a real panel with scripts/live-verify.mjs and scripts/live-verify-upload.mjs (sequences on throwaway mcp-throwaway-* files at the server root that clean up after themselves): create, dry run, overwrite two-phase confirmation, token replay refusal, abort when the pre-flight backup hits the panel's backup limit, rename, copy, protected-path refusal, bulk delete with auto-backup, binary upload, and backup deletion. ptero_set_power_state has only been exercised by unit tests and the mock-panel smoke run. Both scripts read .env from the repo root and mutate the configured server — point them at a test server, never at one with players on it.

  • Uploading into a directory that does not exist yet always asks for confirmation. ptero_upload_file decides create-vs-overwrite from a directory listing, and panels have been seen answering GET /files/list for a missing directory with a 500 UnexpectedValueException (not a 404). The tool cannot tell "not there" from "could not look", so it reports action: "unknown" and requires confirmation — the intended fail-safe, not a bug. Wings itself creates the missing parent directories during the upload, so the upload does then succeed.

  • Backup limit interacts with auto-backup. Many hosts give a server a small backup feature limit (sometimes just 1). With PTERODACTYL_AUTO_BACKUP=true (the default) the first file write, delete or kill takes a slot; once the limit is reached the next destructive change will fail its pre-flight backup (the panel refuses to create another) and be aborted by design. Either delete an older backup first with ptero_delete_backup, take backups manually and set PTERODACTYL_AUTO_BACKUP=false for that session, or ask your host to raise the limit.

Development

Contributions are welcome — see CONTRIBUTING.md.

npm install
npm run build        # tsc -> dist/
npm test             # vitest — unit + integration tests, no network
npm run typecheck

Testing with MCP Inspector

npm run inspector    # npx @modelcontextprotocol/inspector node dist/index.js

This opens the Inspector UI against the built server. Set the required env vars (PTERODACTYL_PANEL_URL, PTERODACTYL_API_KEY, ...) in the Inspector's connection form, or export them in your shell first.

For scripted checks use the Inspector CLI. Env vars must be passed with -e after the command (they are not inherited), and array/boolean arguments need --tool-args-json:

npx --yes @modelcontextprotocol/inspector --cli node dist/index.js \
  -e PTERODACTYL_PANEL_URL=https://panel.example.com -e PTERODACTYL_API_KEY=ptlc_... \
  -e PTERODACTYL_DEFAULT_SERVER=1a2b3c4d \
  --method tools/call --tool-name ptero_list_files \
  --tool-args-json '{"directory":"/plugins"}' --format json

Each --cli invocation starts a fresh server process, so confirmation tokens, the mutation budget and the power cooldown reset between calls. Two-phase flows therefore need one long-lived process; scripts/inspector-smoke.sh (needs jq) shows how, and runs every tool end to end against the mock panel in test/mock-panel/. Results of that run are in docs/INSPECTOR_RESULTS.md.

Design docs

Layout

src/
  index.ts              entrypoint: load config, build deps, register all tools, connect stdio
  config.ts             parse env -> Config (frozen); actionable, fatal validation errors
  client.ts             PteroClient: fetch wrapper for /api/client, rate-limit + error mapping
  errors.ts             PteroError hierarchy + toActionableMessage() helper
  guard.ts              Guard: every safety layer, in one module — no per-tool checks
  audit.ts              AuditLog: append-only JSONL with secret redaction
  confirm.ts            Confirmation: elicitation-or-token two-phase flow (used by guard)
  console/
    websocket.ts         WingsSocket: connect, auth, re-auth, event stream, bounded collect
  tools/
    _shared.ts           registerTool helper, common Zod fragments, result builders, runMutation()
    servers.ts            ptero_list_servers, ptero_get_server, ptero_get_server_resources
    console.ts             ptero_get_console_log, ptero_send_console_command
    files.ts                ptero_list_files, ptero_read_file, ptero_write_file, ptero_upload_file, ptero_rename_file, ptero_copy_file, ptero_delete_file
    power.ts                 ptero_set_power_state
    backups.ts                ptero_list_backups, ptero_create_backup, ptero_delete_backup, ptero_get_backup_download_url
    misc.ts                    ptero_list_schedules, ptero_list_allocations, ptero_get_startup_variables
test/
  guard.test.ts, confirm.test.ts, client.test.ts, audit.test.ts, config.test.ts, tools/*.test.ts
evals/
  evaluation.xml        10 read-only eval questions against the mock panel (mcp-builder Phase 4 format)

Each src/tools/*.ts file exports exactly one registerXxxTools(ctx: ToolContext) function, called once from src/index.ts.

Adding a tool

  1. Pick (or create) the src/tools/*.ts file for the relevant area.

  2. Define Zod input/output schemas. Import the shared fragments from _shared.ts (serverIdSchema, dryRunSchema, confirmationTokenSchema) rather than redefining them — every tool that resolves a server or supports dry-run/ confirmation should use the same shapes.

  3. Register with ctx.server.registerTool(name, { title, description, inputSchema, outputSchema, annotations }, handler). Write the description for the calling model: what it does, when to use it, what it does not do, and the alternative when relevant (the console-vs-logs/latest.log pattern in console.ts is the canonical example).

  4. Read-only tool: call the client directly, wrap in try { return ok(...) } catch (e) { return fail(e) }, done.

  5. Mutating tool: build a MutationRequest (tool, server, args, kind, paths, powerSignal, fileCount, dryRun, confirmationToken, preview, destructive, wantsAutoBackup) and pass it to runMutation(ctx, req, extra, execute, summarise) from _shared.ts — it handles every guard decision (refused/dry_run/needs_confirmation/proceed) and audit-commit for you. Never call the Pterodactyl API for a mutating effect outside of the execute callback passed to runMutation.

  6. Set all four annotations explicitly (readOnlyHint, destructiveHint, idempotentHint, openWorldHint: false).

  7. Register the new registerXxxTools(ctx) call in src/index.ts.

  8. Add tests under test/tools/ with a mocked PteroClient (see test/tools/servers.test.ts for the pattern) — no network in tests.

  9. Exercise the new tool at least once with npm run inspector, and add it to the tables in this README.

Acknowledgements

License

MIT. Not affiliated with or endorsed by the Pterodactyl project.

Available Tools

20 tools
ptero_copy_fileCopy a fileA

Duplicate a file or directory in place. THE PANEL CHOOSES THE NAME OF THE COPY — you cannot specify it. Copying config.yml produces something like config copy.yml (and config copy 2.yml the next time) in the same directory. If you need a specific name, copy first and then ptero_rename_file the result; call ptero_list_files afterwards to find out what the copy was actually called.

The obvious use is a hand-rolled safety net before editing a config: copy it, then ptero_write_file the original. For anything bigger than a single file, a real backup (ptero_create_backup) is better — it is off-server and restorable.

The source path is checked against PTERODACTYL_PROTECTED_PATHS. No confirmation and no automatic backup (nothing is overwritten), but the call is counted against PTERODACTYL_MAX_MUTATIONS and audited. Note the copy consumes disk quota.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesFile or directory to duplicate, relative to the server root, e.g. `plugins/Geyser-Spigot/config.yml`.
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
dry_runNoWhen true, validate and preview the change without performing it. Nothing is modified and no confirmation token is issued. Use this to reason about an operation before committing to it.
confirmation_tokenNoTwo-phase confirmation token. Leave this out on the first call: the tool will refuse to act and instead return a preview of exactly what would change, plus a single-use token that expires in 120 seconds. THE PREVIEW IS FOR THE HUMAN — show it to the user in your reply and let them decide. Do not silently round-trip the token back in an immediate second call. Only call again with the token once the user has seen the preview and approved it. The token is bound to a hash of these exact arguments, so changing any argument invalidates it.

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoReminder that the panel chooses the copy's name; list the directory to see it.
pathNoServer-relative path that was copied.
reasonNoWhy the call was refused.
serverYes
statusYessuccess = the change was made. refused = a guardrail blocked it (see reason/variable). dry_run = nothing changed; preview shows what would. needs_confirmation = nothing changed; SHOW the preview to the human and, only if they agree, call again with confirmation_token.
messageNo
previewNoWhat would / did change.
variableNoEnvironment variable that caused the refusal.
backup_idNoUUID of the automatic pre-change backup, if one was taken.
expires_in_sNo
confirmed_viaNo
confirmation_tokenNo

TDQS

A4/5.0
Behavior3/5

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

Adds useful behavioral detail: panel chooses the name, protected-path checks, no overwriting, mutation-limit counting, auditing, and disk-quota consumption. However, the phrase 'No confirmation' conflicts with the two-phase dry_run/confirmation_token flow in the input schema, making the behavioral guidance partially misleading.

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

Conciseness4/5

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

Three dense paragraphs, front-loaded with the core action and naming behavior. Each sentence carries useful information—naming scheme, workflow, alternatives, safety, quota—with minimal filler. Slightly long but justified by the unusual naming behavior.

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?

Covers purpose, naming uncertainty, workflow, alternatives, safety checks, mutation limits, audit, and quota. The 'No confirmation' statement conflicts with the documented confirmation-token flow, creating a gap in completeness that could mislead an agent, so it is not fully reliable.

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 coverage is 100%, so the baseline is 3. The description adds some relevant constraints (protected-path check, quota consumption) but these are behavioral rather than per-parameter semantics. It does not meaningfully extend the schema's parameter explanations.

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 opens with 'Duplicate a file or directory in place,' a specific verb and resource, and immediately explains the panel-controlled naming behavior. It clearly differentiates from siblings like ptero_rename_file and ptero_write_file by describing the post-copy discovery workflow.

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

Usage Guidelines5/5

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

Explicitly states the primary use case (safety net before editing a config), the workflow for getting a specific name (copy, rename, list), and the better alternative for larger operations (ptero_create_backup). This satisfies when/when-not guidance with named alternatives.

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

ptero_create_backupCreate a Pterodactyl backupA

Take a backup of the server right now. Safe. The natural thing to do BEFORE any file write, delete, or power kill — it gives you a rollback point.

By default (wait: true) this blocks until the panel reports the backup complete (polling for up to two minutes) and returns its final size and success state. Pass wait: false to return immediately with just the uuid if you do not want to block; check completion later with ptero_list_backups.

The panel enforces a per-server backup-count limit; creation fails with an actionable error when the server is full — the fix is ptero_delete_backup on an old one, not a retry.

ParametersJSON Schema
NameRequiredDescriptionDefault
nameNoBackup name. Omit to let the panel assign a default name.
waitNoWait for the backup to finish before returning (up to ~2 minutes). false returns immediately with just the uuid — check ptero_list_backups for completion.
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
dry_runNoWhen true, validate and preview the change without performing it. Nothing is modified and no confirmation token is issued. Use this to reason about an operation before committing to it.
ignoredNoNewline-separated list of glob patterns to exclude from the backup, e.g. "cache/**\n*.log".

Output Schema

ParametersJSON Schema
NameRequiredDescription
nameNo
uuidNo
bytesNo
reasonNoWhy the call was refused.
serverYes
statusYessuccess = the change was made. refused = a guardrail blocked it (see reason/variable). dry_run = nothing changed; preview shows what would. needs_confirmation = nothing changed; SHOW the preview to the human and, only if they agree, call again with confirmation_token.
messageNo
previewNoWhat would / did change.
variableNoEnvironment variable that caused the refusal.
backup_idNoUUID of the automatic pre-change backup, if one was taken.
completedNoTrue once the backup has finished (only when wait:true).
waited_msNoMilliseconds spent polling for completion (only when wait:true).
bytes_humanNo
completed_atNo
expires_in_sNo
confirmed_viaNo
is_successfulNo
confirmation_tokenNo

TDQS

A4.9/5.0
Behavior5/5

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

Annotations only provide flags, so the description carries the behavioral burden. It discloses blocking/polling behavior up to two minutes, return behavior differences between wait:true and wait:false, the per-server backup-count limit, and the actionable error path when full. The phrase 'Safe' aligns with destructiveHint=false and no contradiction exists.

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 front-loaded with the core purpose and use case, then adds wait behavior and failure handling in clearly separated paragraphs. Every sentence contributes useful context, with no filler or repetition beyond what is needed for operational clarity.

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 description covers when to use the tool, the main behavioral modes, and the key failure condition. Combined with the fully documented input schema and the presence of an output schema, an agent has everything needed to invoke it correctly without ambiguity.

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?

Schema coverage is 100%, so the baseline is 3, but the description adds meaningful meaning for the wait parameter: it explains polling, the final size and success state, and the immediate uuid-only return path. It also adds operation-level context about the backup-count limit that affects whether creation can succeed.

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?

States a specific verb and resource: 'Take a backup of the server right now.' It frames the tool as a rollback step before file writes, deletes, or power kills, which clearly distinguishes it from sibling backup tools like ptero_list_backups, ptero_delete_backup, and ptero_get_backup_download_url.

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

Usage Guidelines5/5

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

Explicitly says when to use it: before any file write, delete, or power kill, to create a rollback point. It also names alternatives: ptero_list_backups for checking completion when wait:false, and ptero_delete_backup as the fix when the per-server backup limit is full, with an explicit 'not a retry' warning.

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

ptero_delete_backupDelete a Pterodactyl backupA
DestructiveIdempotent

Permanently delete one backup. IRREVERSIBLE — there is no undo and no confirmation from the panel beyond this tool.

Requires PTERODACTYL_ALLOW_DELETE=true. Requires confirmation: the first call without confirmation_token returns a preview (name, size, created_at) and a token instead of deleting anything — THAT PREVIEW IS FOR THE HUMAN, show it and wait for approval before calling again with the token. A locked backup cannot be deleted here at all; unlock it in the panel first.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
dry_runNoWhen true, validate and preview the change without performing it. Nothing is modified and no confirmation token is issued. Use this to reason about an operation before committing to it.
backup_uuidYesUUID of the backup to delete (from ptero_list_backups).
confirmation_tokenNoTwo-phase confirmation token. Leave this out on the first call: the tool will refuse to act and instead return a preview of exactly what would change, plus a single-use token that expires in 120 seconds. THE PREVIEW IS FOR THE HUMAN — show it to the user in your reply and let them decide. Do not silently round-trip the token back in an immediate second call. Only call again with the token once the user has seen the preview and approved it. The token is bound to a hash of these exact arguments, so changing any argument invalidates it.

Output Schema

ParametersJSON Schema
NameRequiredDescription
uuidNo
reasonNoWhy the call was refused.
serverYes
statusYessuccess = the change was made. refused = a guardrail blocked it (see reason/variable). dry_run = nothing changed; preview shows what would. needs_confirmation = nothing changed; SHOW the preview to the human and, only if they agree, call again with confirmation_token.
messageNo
previewNoWhat would / did change.
variableNoEnvironment variable that caused the refusal.
backup_idNoUUID of the automatic pre-change backup, if one was taken.
expires_in_sNo
confirmed_viaNo
confirmation_tokenNo

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already mark the tool as destructive and idempotent, but the description adds crucial context beyond them: irreversibility with no undo, the no-op preview on first call, the single-use expiring token, the requirement for PTERODACTYL_ALLOW_DELETE=true, and the locked-backup failure mode.

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 dense but compact, with the most important warning front-loaded. Each sentence contributes operational value, and the all-caps emphasis is used sparingly for genuinely critical points like IRREVERSIBLE and the human-preview requirement.

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?

Between the detailed schema, the output schema, and the annotations, the description covers the remaining behavioral gaps: environment requirements, safe two-phase deletion, human approval, and a clear exclusion for locked backups. An agent has everything needed to invoke this 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?

Schema description coverage is 100%, and the schema already explains server, dry_run, backup_uuid, and confirmation_token in detail. The description reinforces the confirmation-token flow but does not add significant per-parameter meaning beyond the schema, so baseline 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 opens with a specific verb and resource: 'Permanently delete one backup.' This unambiguously distinguishes the tool from sibling backup operations like ptero_list_backups and ptero_create_backup, and from other delete tools like ptero_delete_file.

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

Usage Guidelines5/5

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

It gives explicit when-to-use and when-not-to-use guidance: the environment variable prerequisite, the two-phase confirmation flow, the rule to show the preview to the human and wait for approval, and the locked-backup exclusion with the alternative action ('unlock it in the panel first').

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

ptero_delete_fileDelete files from the serverA
DestructiveIdempotent

Permanently delete one or more files or directories. THIS IS IRREVERSIBLE WITHOUT A BACKUP — the panel has no trash and no undo. Deleting a directory deletes everything under it. Prefer ptero_rename_file (rename it out of the way) whenever the change might need undoing.

Every guardrail applies:

  • Deletion is OFF unless the operator set PTERODACTYL_ALLOW_DELETE=true; otherwise every call is refused.

  • Paths matching PTERODACTYL_PROTECTED_PATHS are refused — by default the world directories, server.properties, ops.json, whitelist.json and banned-*.json.

  • More than 10 files in one call is refused; narrow the list and work in batches.

  • An automatic backup is taken before the delete, and the operation is aborted if the backup fails.

The first call does NOT delete anything. It returns status "needs_confirmation" with a preview listing the root, the exact files and the count, plus a single-use token that expires in 120 seconds. THAT PREVIEW IS FOR THE HUMAN: put it in your reply, let them read the list, and only call again with the confirmation_token once they have said yes. Do not round-trip the token automatically — the whole point is that a person sees what is about to be destroyed.

Use dry_run=true if you only want to check what a delete would resolve to.

ParametersJSON Schema
NameRequiredDescriptionDefault
rootNoDirectory the entries in `files` live in, relative to the server root. Defaults to `/`. E.g. `plugins` when deleting `foo.jar`./
filesYesNames to delete, relative to `root` — bare names such as `foo.jar`, not full paths. Maximum 10 per call. Directories are deleted with all their contents.
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
dry_runNoWhen true, validate and preview the change without performing it. Nothing is modified and no confirmation token is issued. Use this to reason about an operation before committing to it.
confirmation_tokenNoTwo-phase confirmation token. Leave this out on the first call: the tool will refuse to act and instead return a preview of exactly what would change, plus a single-use token that expires in 120 seconds. THE PREVIEW IS FOR THE HUMAN — show it to the user in your reply and let them decide. Do not silently round-trip the token back in an immediate second call. Only call again with the token once the user has seen the preview and approved it. The token is bound to a hash of these exact arguments, so changing any argument invalidates it.

Output Schema

ParametersJSON Schema
NameRequiredDescription
rootNo
filesNoNames deleted, relative to `root`.
reasonNoWhy the call was refused.
serverYes
statusYessuccess = the change was made. refused = a guardrail blocked it (see reason/variable). dry_run = nothing changed; preview shows what would. needs_confirmation = nothing changed; SHOW the preview to the human and, only if they agree, call again with confirmation_token.
messageNo
previewNoWhat would / did change.
variableNoEnvironment variable that caused the refusal.
backup_idNoUUID of the automatic pre-change backup, if one was taken.
expires_in_sNo
confirmed_viaNo
deleted_countNo
confirmation_tokenNo

TDQS

A4.7/5.0
Behavior5/5

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

Discloses irreversibility, no trash/undo, recursive directory deletion, automatic backup before delete, and the two-phase confirmation with token expiry. This goes well beyond the destructiveHint/readOnlyHint annotations and explains the preview/confirmation behavior that annotations alone would not convey.

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?

Long but justified for a destructive tool: the warning is front-loaded, guardrails are bulleted, and the confirmation protocol is clearly sequenced. No filler.

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?

Covers operator-controlled enablement, protected paths, batch limits, backup behavior, and the human-in-the-loop confirmation flow. With an output schema present, nothing needed to call it correctly is missing.

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 coverage is 100%, so the schema already documents root, files, server, dry_run, and confirmation_token in detail. The description reinforces key constraints (batch limit, token binding, preview-for-human) but adds little parameter-specific meaning beyond the schema.

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 opens with 'Permanently delete one or more files or directories' — a specific verb and resource. It also names the safer sibling ptero_rename_file, distinguishing this destructive tool from the alternative.

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

Usage Guidelines5/5

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

Explicitly says to prefer ptero_rename_file when a change might need undoing. It also details when deletion is refused (PTERODACTYL_ALLOW_DELETE, protected paths, >10 files) and mandates the two-phase human confirmation workflow.

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

ptero_get_backup_download_urlGet a signed backup download URLA
Read-onlyIdempotent

Get a signed, short-lived URL for downloading one backup archive directly from storage.

Use this when the human wants to pull a backup down outside the panel. The URL grants access to the archive to whoever holds it, expires quickly, and is never written to the audit log — treat it as a bearer credential: do not store it, paste it into a chat log you will keep, or reuse it after it expires (request a fresh one instead).

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
backup_uuidYesUUID of the backup to download (from ptero_list_backups).

Output Schema

ParametersJSON Schema
NameRequiredDescription
urlYesSigned, short-lived Wings URL. Never logged or audited.
noteYes
uuidYes

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already indicate readOnlyHint=true, idempotentHint=true, and destructiveHint=false, but the description adds crucial behavioral detail: the URL is short-lived, grants access to anyone holding it, is never written to the audit log, and should be treated as a bearer credential. It also implies the return is a URL, not the archive itself. This goes well beyond annotations and is essential for safe use.

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 sentences, front-loading the purpose and then delivering critical security context. Every sentence earns its place; there is no filler or repetition. It is compact yet comprehensive.

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 an output schema, so return values are covered. The description addresses when to use, security handling, and the ephemeral nature of the URL. It also clarifies that the URL is for a single backup. Nothing essential is missing for an agent to call this 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 input schema provides 100% coverage with clear descriptions for both 'server' and 'backup_uuid', including an example and a pointer to ptero_list_servers for valid identifiers. The tool description does not add parameter-specific semantics beyond the schema, but with complete schema coverage, that is acceptable. It receives the baseline score.

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 specific verb-resource pair: 'get a signed, short-lived URL for downloading one backup archive.' It clearly distinguishes from siblings like ptero_list_backups (which lists backups) and ptero_create_backup (which creates them). No other sibling provides a download URL, so the purpose is unambiguous.

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

Usage Guidelines5/5

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

It explicitly says 'Use this when the human wants to pull a backup down outside the panel.' This is a clear condition for use. The description also provides security-oriented instructions (treat as bearer credential, don't store/paste/reuse), which act as usage constraints. Since no sibling offers a similar function, alternatives are not needed.

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

ptero_get_console_logRead the Pterodactyl live consoleA
Read-onlyIdempotent

Connect to the server's live console websocket and return the backlog it hands back on connect (the node's ring buffer, ~150 most recent lines by default) plus whatever new lines stream in during the collection window, then disconnect.

Pterodactyl has no "give me the last N lines" request over REST — this websocket round trip is the only way to read console output, and what you get is a live snapshot, not a query over history.

The buffer rolls over quickly: roughly an hour after boot the plugin startup lines are already gone from it. For boot-time or plugin-load output, use ptero_read_file on logs/latest.log instead — that has the full run history.

After calling ptero_send_console_command, you MUST call this tool to see what the command did: dispatching a command never returns its output by itself.

filter narrows the returned lines (case-insensitive substring, or a regex if it parses as one) without needing a wider window — e.g. filter: "geyser" to isolate Geyser lines in a busy log.

ParametersJSON Schema
NameRequiredDescriptionDefault
filterNoOptional case-insensitive filter applied to lines AFTER they are collected: a regular expression if `filter` parses as one, otherwise a plain substring match. Useful for pulling out e.g. Geyser lines ("geyser") from a busy console without widening the window.
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
max_linesNoStop collecting once this many lines have been gathered (1-1000, default 400). The node's backlog alone is ~150 lines, so the default leaves room to also observe lines streamed during `window_seconds`. `truncated: true` in the result means this cap cut collection short.
window_secondsNoHow long to stay connected collecting console output, in seconds (1-60, default 5). Collection stops early once `max_lines` is reached.

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoCaveats worth surfacing: the server was offline, the node throttled a request, or the filter matched nothing.
linesYesCollected console lines, ANSI escape codes stripped, oldest first. Filtered by `filter` when one was given.
stateYesWings-reported power state at the time of collection (offline/starting/running/stopping), or "unknown" if no status event arrived during the window.
serverYesServer short identifier the log was read from.
truncatedYesTrue when `max_lines` cut off further backlog or streamed output.
line_countYesNumber of lines in `lines` (after filtering).
duration_msYesWall-clock time the collection took, in milliseconds.
window_secondsYesThe collection window that was actually used.

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already mark it read-only, idempotent, and non-destructive, but the description adds crucial behavioral context beyond that: the websocket round trip is the *only* way to read console output, the buffer rolls over (~1 hour), and collection behavior is governed by `max_lines` and `window_seconds`. It also discloses the `truncated` flag. No contradiction with 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 well-structured: it opens with the core function, then explains why this is the only path, then the alternative, then the mandatory follow-up usage, and finally the filter. Every sentence adds unique value, and there is no fluff or repetition. It's long but appropriately so for a tool with non-obvious websocket behavior.

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 tool with websocket collection, streaming, filtering, and truncation, the description covers everything an agent needs: the mechanism, the buffer limitation, the alternative for historical logs, the requirement after sending commands, and the filter semantics. Since an output schema exists, return values don't need description. No relevant gap remains.

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%, and the schema already documents each parameter, including the filter's regex-vs-substring behavior. The description adds only minor elaboration (e.g., 'without needing a wider window') that largely repeats the schema. Since the schema carries the heavy lifting, a baseline 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 precisely states the verb and resource: 'Connect to the server's live console websocket and return the backlog... plus whatever new lines stream in.' It explicitly distinguishes this from the log-file tool `ptero_read_file` and even from `ptero_send_console_command`, so an agent can instantly tell what this tool does and what it doesn't.

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

Usage Guidelines5/5

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

The description gives explicit when-to-use and when-not-to-use guidance: it names `ptero_read_file` as the alternative for boot-time/plugin-load output and states 'you MUST call this tool to see what the command did' after `ptero_send_console_command`. This is unambiguous routing to the correct tool in each scenario.

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

ptero_get_serverGet Pterodactyl server detailsA
Read-onlyIdempotent

Get the full configuration of one server: name, node, panel lifecycle status, resource limits, feature limits, every network allocation (ip/port/notes, and which is primary), SFTP host and port, Docker image and the resolved startup command.

Use this to answer "how is this server configured", "what ports does it have", "how much memory is it allowed", or "what is it running".

This is static configuration. It does NOT tell you whether the server is up or what it is currently consuming — use ptero_get_server_resources for that. For the ports alone, ptero_list_allocations is narrower. Note that a port being allocated does not mean a service actually bound to it; confirm that in the console log or the relevant plugin config file.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.

Output Schema

ParametersJSON Schema
NameRequiredDescription
nameYes
nodeYesName of the node hosting the server.
uuidYes
limitsYesResource ceilings configured on the panel.
statusYesPanel lifecycle status: null when normal, else installing/install_failed/reinstall_failed/suspended/restoring_backup. This is NOT the power state — use ptero_get_server_resources for running/offline.
identifierYes
invocationYesResolved startup command. Redacted by the panel without startup:read permission.
allocationsYesPorts assigned to this server.
descriptionYes
docker_imageYesContainer image the server runs in.
egg_featuresNo
is_suspendedYesSuspended servers reject power and console actions.
server_ownerNoTrue when the API key owns the server rather than being a subuser.
sftp_detailsYes
is_installingYes
feature_limitsYes
is_transferringYesTrue while the server is being moved between nodes.
is_node_under_maintenanceNo

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the agent knows this is a safe read. The description adds meaningful behavioral context beyond annotations: 'This is static configuration' and the limitation that an allocated port does not imply a bound service. No contradictions.

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 detailed but every sentence serves a distinct purpose: the first enumerates contents, the second gives concrete use cases, the third clarifies limits and routes to siblings. Information is front-loaded and structured logically. Nothing is redundant.

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 presence of an output schema and comprehensive annotations, the description covers all necessary operational context: what data is returned, how it differs from similar tools, and the important semantic caveat about port allocations. An agent can confidently select and interpret the result without further guessing.

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% for the single 'server' parameter, which already explains the short identifier, the default via PTERODACTYL_DEFAULT_SERVER, and how to discover valid identifiers. The description adds no additional parameter-specific details beyond the schema, so the 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 opens with a precise verb and resource ('Get the full configuration of one server') and enumerates exactly what is returned: name, node, lifecycle status, resource limits, feature limits, allocations, SFTP, Docker image, startup command. It also names the sibling tools it is not (ptero_get_server_resources, ptero_list_allocations), making selection unambiguous.

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

Usage Guidelines5/5

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

The description explicitly states when to use it ('Use this to answer...') and what it does NOT do ('does NOT tell you whether the server is up... use ptero_get_server_resources'). It also gives a narrower alternative for ports alone and a practical caveat about allocated vs. bound ports. This fully covers when-to-use and when-not-to.

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

ptero_get_server_resourcesGet Pterodactyl server resource usageA
Read-onlyIdempotent

Get the live power state and current resource usage of a server: whether it is running, memory and disk in use, CPU percentage, network bytes in and out, and process uptime.

Use this to answer "is the server up?", "what is the memory doing?" or "how long has it been up?". This is the tool that reports running vs offline — ptero_get_server reports panel lifecycle status, which is a different thing.

Figures are cached by the panel for about 20 seconds, so calling repeatedly in quick succession returns identical numbers; that is the cache, not a frozen server. cpu_absolute is a percentage across all cores (200 means two full cores), and compares against the limits.cpu from ptero_get_server. When the server is offline every figure is 0. This tool does not explain why something is wrong — use ptero_get_console_log for that.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.

Output Schema

ParametersJSON Schema
NameRequiredDescription
serverYesServer short identifier these figures describe.
uptime_msYesMilliseconds since the process started. 0 when offline.
disk_bytesYes
disk_humanYes
cpu_absoluteYesCPU percent across all cores: 100 = one full core, 200 = two cores.
is_suspendedYes
memory_bytesYes
memory_humanYes
uptime_humanYes
current_stateYesDaemon power state: offline, starting, running, or stopping.
network_rx_bytesYes
network_rx_humanYes
network_tx_bytesYes
network_tx_humanYes

TDQS

A4.5/5.0
Behavior4/5

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

Annotations already declare readOnly, idempotent, and non-destructive hints, so the bar for behavioral disclosure is lower. The description adds valuable context beyond those hints: 20-second panel caching, cpu_absolute meaning across cores, comparison with limits.cpu, and zeroed metrics when offline.

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?

Every sentence serves a distinct purpose: definition, use cases, sibling differentiation, caching caveat, CPU semantics, offline behavior, and follow-up routing. The information is dense but front-loaded and stays relevant with no filler.

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-optional-parameter read-only tool with an output schema, the description covers the surprising behaviors an agent needs to interpret results correctly and even routes to the console-log tool for deeper diagnosis. Nothing essential is missing.

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 sole parameter 'server' is fully documented in the input schema, including how to discover valid identifiers and the default-server fallback. With 100% schema coverage, the description does not need to repeat parameter detail, so the baseline 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?

The description opens with a specific verb and resource: it gets live power state and resource usage metrics. It also explicitly distinguishes itself from ptero_get_server, which reports panel lifecycle status, so an agent can identify the right tool without ambiguity.

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

Usage Guidelines5/5

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

It gives concrete question patterns ('is the server up?', 'what is the memory doing?') and names the two alternatives: ptero_get_server for panel lifecycle status and ptero_get_console_log for diagnosing why something is wrong. This is explicit when-to-use and when-not-to-use guidance.

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

ptero_get_startup_variablesGet Pterodactyl startup command and egg variablesA
Read-onlyIdempotent

Get the resolved startup command, the raw (unsubstituted) command template, the Docker image, and every user-viewable egg variable — name, env-var name, description, current and default values, whether it's editable, and its validation rule string.

Use this to see how the server is configured to start — e.g. which jar file, memory flags, or Geyser toggle are set — before troubleshooting a boot failure or explaining current configuration.

Hidden (non-user-viewable) variables are never returned by the panel and so never appear here. This tool is read-only: it cannot change a variable, and this server does not currently expose a tool that does — that has to be done through the panel UI.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.

Output Schema

ParametersJSON Schema
NameRequiredDescription
serverYes
variablesYesUser-viewable egg variables only; hidden ones never appear here.
docker_imageNoThe container image currently in use, when the panel reports one.
startup_commandYesThe startup command with egg variable placeholders resolved.
raw_startup_commandYesThe startup command template before placeholder substitution.

TDQS

A4.1/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is known. The description adds valuable behavioral context beyond the annotations: hidden variables are never returned, the tool cannot mutate anything, and no update tool exists. This goes beyond what the structured annotations alone provide.

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

Conciseness4/5

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

The description is front-loaded with the full return payload in the first sentence, then adds a practical use case, then disclosure about hidden variables and read-only behavior. Every sentence carries substantive information and there is no fluff; it is slightly long but not padded.

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 covers the main operational needs: what the tool returns, why an agent would use it, what it cannot do, and the hidden-variable caveat. An output schema exists, so return structure is already available. Minor gaps like error behavior for an invalid server identifier are not material given the schema's default fallback and sibling listing guidance.

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 single optional 'server' parameter is fully documented in the input schema, including the default and how to discover valid identifiers. The description adds no new parameter-level meaning, so the baseline 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 names a specific verb ('Get') and a precise set of resources: resolved startup command, raw template, Docker image, and user-viewable egg variables with their attributes. It also gives a concrete use case (inspecting jar file, memory flags, Geyser toggle), which clearly distinguishes it from sibling tools like power state, file, or console tools.

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 explicitly states when to use the tool: 'before troubleshooting a boot failure or explaining current configuration.' It also clearly says the tool cannot change variables and that no sibling tool does, routing changes to the panel UI. It does not name a specific alternative sibling for similar config reads, but the guidance is otherwise concrete and useful.

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

ptero_list_allocationsList Pterodactyl network allocationsA
Read-onlyIdempotent

List the network allocations (ip:port pairs) assigned to this server, and which one is the default/primary.

Use this to find out which port a particular service is meant to use — for example, which port Geyser/Bedrock should bind to — before checking whether it actually bound, which you confirm separately via the console log or logs/latest.log (ptero_read_file). A port being allocated here does not mean anything is actually listening on it.

This is read-only: adding, removing, or repointing allocations is not exposed by this server.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
serverYes
allocationsYes

TDQS

A4.7/5.0
Behavior5/5

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

Even with readOnlyHint=true and destructiveHint=false in the annotations, the description adds valuable behavioral context: it returns allocated ip:port pairs plus the default/primary, does not indicate whether anything is listening, and explicitly states that adding/removing/repointing allocations is not exposed. No contradiction exists.

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 front-loaded with the core purpose, followed by concrete usage guidance and a clear read-only note. Every sentence contributes usable information without redundancy or fluff.

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 simple list tool with an output schema and rich annotations, the description fully covers what the agent needs: what is returned, how to interpret it, the key limitation about listening ports, and the read-only scope. Nothing essential is missing.

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 coverage is 100% for the single optional server parameter, which already documents the short identifier, the default environment variable fallback, and how to discover valid identifiers. The description does not need to add more and does not meaningfully extend the schema's parameter documentation.

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 specific verb and resource: list the network allocations (ip:port pairs) assigned to this server, including the default/primary. This clearly distinguishes it from sibling tools like ptero_list_files, ptero_list_backups, and ptero_list_schedules.

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

Usage Guidelines5/5

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

It explicitly tells the agent when to use the tool (to find which port a service should bind to) and when not to rely on it alone (allocation does not mean something is listening), and names the alternative confirmation path via ptero_read_file on logs/latest.log.

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

ptero_list_backupsList Pterodactyl backupsA
Read-onlyIdempotent

List a server's backups: uuid, name, size, whether each one completed successfully, whether it is locked against deletion, and its created/completed timestamps.

Use this to find a rollback point before or after a risky change, or to check whether a backup started with ptero_create_backup wait:false has finished yet (completed_at is null until it has). Call ptero_create_backup BEFORE any risky file write, delete, or power kill — this tool only reports what already exists, it does not take one for you.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
per_pageNoBackups per page; the panel clamps this to 50. Omit for the panel default (20).

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYesNumber of backups on this call (the panel does not paginate this list further here).
serverYes
backupsYes
backup_countNoCount of non-failed backups, from the panel (meta.backup_count), when reported.
backup_limitNoMaximum backups this server may hold at once, when the panel reports it.

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true and destructiveHint=false; description adds valuable semantics: completed_at is null until the backup finishes, and it only reports what exists. No contradiction between text and annotations, and the added detail goes beyond the structured hints.

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

Conciseness4/5

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

Three sentences each earn their place: the field list, the usage scenario, and the explicit clarification of scope. Slightly verbose but information-dense and front-loaded with the primary purpose.

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?

Output schema covers return structure, description covers usage and limitations, annotations cover safety. Nothing an agent needs to call it correctly is missing, including the pointer to ptero_create_backup as the complementary 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 covers both parameters fully (server with default and discovery hint, per_page with clamp and default). Description adds no additional parameter info beyond what the schema already provides, so the 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?

Clear verb 'list' with resource 'server backups', enumerates the fields returned (uuid, name, size, success, locked, timestamps), and stands apart from sibling tools like ptero_create_backup and ptero_delete_backup as a read-only reporting tool.

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

Usage Guidelines5/5

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

Explicitly states when to use (finding rollback points before/after risky changes, checking async backup completion) and explicitly warns to call ptero_create_backup before risky operations, clarifying that this tool only reports existing backups and does not create one.

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

ptero_list_filesList files in a server directoryA
Read-onlyIdempotent

List one directory on the game server, relative to the server root. Returns each entry's name, full server-relative path, whether it is a file or a directory, size, unix mode, MIME type and last-modified time. Directories are listed first, then files, each group sorted by name.

Use this to find out what is actually on disk before reading or changing anything: which plugins are installed (plugins), which world folders exist, which log files are available (logs), or the exact spelling of a config path.

The path on each entry is the value other file tools want — pass it to ptero_read_file, or use it with ptero_delete_file.

This is not recursive: it lists one level. To go deeper, call it again with a child directory's path. It also does not return file contents — use ptero_read_file.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
directoryNoDirectory to list, relative to the server root. Defaults to `/` (the root). Examples: `plugins`, `logs`, `plugins/Geyser-Spigot`. Leading slashes are optional./

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
serverYes
entriesYesDirectories first, then files, each group sorted by name.
directoryYesDirectory that was listed, as a server-relative path (`/` = server root).
file_countYes
directory_countYes

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already signal read-only, idempotent, and non-destructive behavior. The description adds valuable behavioral context beyond those annotations: it is non-recursive, returns entries with full server-relative paths, lists directories before files, and sorts each group by name. No contradiction with 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 well-structured and front-loaded: result semantics first, then use cases, then limitations. Every sentence carries useful information for tool selection or invocation, with no filler or repetition of schema content.

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 rich input schema, safe annotations, and presence of an output schema, the description covers everything an agent needs: what is listed, how results are ordered, the non-recursive behavior, the lack of file contents, and how the returned paths connect to other file tools. Nothing important is missing.

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?

Schema coverage is 100%, so the baseline is 3. The description adds extra practical meaning by explaining that the returned `path` is the value other file tools expect and by giving concrete directory examples like `plugins/Geyser-Spigot`. This enriches parameter understanding beyond the schema.

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?

States a specific verb and resource: 'List one directory on the game server, relative to the server root.' It also describes exactly what each entry contains and the ordering, so an agent can distinguish this from file-content and write/delete tools without opening schemas.

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

Usage Guidelines5/5

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

Explicitly says when to use it ('Use this to find out what is actually on disk before reading or changing anything'), what it is not ('not recursive', 'does not return file contents'), and names ptero_read_file as the alternative for contents. This gives clear routing guidance against sibling tools.

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

ptero_list_schedulesList Pterodactyl schedulesA
Read-onlyIdempotent

List a server's scheduled tasks (the panel's Schedules feature): cron timing, whether each is active or currently running, whether it only fires while the server is online, last/next run time, and the ordered tasks each run executes (command/power/backup, with their payload and delay).

Use this to find out what automation is already configured — e.g. a nightly restart or an automatic backup — before assuming a state change was manual, or before adding a new schedule by hand through the panel to avoid a clash.

This is read-only: creating, editing, or deleting schedules is not exposed by this server. Use the panel UI for that.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.

Output Schema

ParametersJSON Schema
NameRequiredDescription
countYes
serverYes
schedulesYes

TDQS

A4.4/5.0
Behavior4/5

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

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, so the safety profile is covered declaratively. The description adds value beyond this by explicitly stating that mutations are 'not exposed by this server' — a scope boundary disclosure — and by detailing the semantic contents of each schedule entry (task types, payload, delay). No contradiction with annotations.

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

Conciseness4/5

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

The description is organized into three purposeful paragraphs: what is returned, when to use it, and its read-only boundary. It is front-loaded with the core purpose and each section earns its place. The first paragraph's field enumeration overlaps somewhat with the existing output schema, making it marginally longer than strictly necessary, but the redundancy is compact and aids rapid comprehension.

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 low-complexity list tool with one optional parameter, rich annotations, and an output schema, the description is complete. It covers purpose, output semantics, use-case context, and scope limitations. Nothing an agent needs to select and invoke this tool correctly is missing.

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% — the single optional 'server' parameter is fully documented with an example, a default fallback (PTERODACTYL_DEFAULT_SERVER), and a pointer to ptero_list_servers for valid identifiers. Per the baseline rule for high coverage, the description need not add parameter detail; it adds none, which is acceptable.

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 opens with a specific verb+resource: 'List a server's scheduled tasks (the panel's Schedules feature)'. It further enumerates exactly what is returned (cron timing, active/running state, online-only flag, last/next run, ordered tasks with payload and delay), leaving no ambiguity about the tool's scope. Among the 20 sibling tools, it is uniquely identifiable as the schedule-listing tool.

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

Usage Guidelines5/5

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

The second paragraph gives explicit when-to-use guidance: discover existing automation before assuming a state change was manual or before adding a new schedule via the panel to avoid clashes. It also states an explicit when-not-to-use boundary: creating/editing/deleting schedules is not exposed, and directs the agent to 'the panel UI for that'.

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

ptero_list_serversList Pterodactyl serversA
Read-onlyIdempotent

List the game servers this Pterodactyl API key can access, with their short identifiers, node, primary allocation and resource limits.

Use this first when you do not already know a server identifier, or when a call fails with "not found" — every other ptero_* tool takes that identifier as its server argument.

This does NOT report whether a server is running: status here is the panel lifecycle field (installing/suspended/etc.) and is null for a normal server whether it is up or down. Call ptero_get_server_resources for the live power state.

Results are paginated by the panel (50 per page). Pass page to fetch further pages; has_more tells you whether any remain.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNo1-based page number. Omit for the first page.

Output Schema

ParametersJSON Schema
NameRequiredDescription
pageNoCurrent page number.
countYesNumber of servers on this page.
totalNoTotal servers across all pages, when the panel reports it.
serversYesServers this API key can access, for the requested page.
has_moreYesTrue when further pages exist; request them with `page`.
total_pagesNoTotal number of pages.

TDQS

A4.9/5.0
Behavior5/5

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

Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior, and the description does not contradict them. It adds valuable non-obvious context: the `status` field is the panel lifecycle field, not a running indicator, and is null for normal servers regardless of power state. It also discloses 50-per-page pagination and the meaning of `has_more`.

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 compact and front-loaded, with each paragraph serving a distinct purpose: scope, usage cue, status caveat, and pagination. There is no filler, repetition, or unnecessary detail, making it easy for an agent to parse and apply.

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 read-only, one-parameter list tool with an output schema and complete annotations, the description covers everything the agent needs: what is returned, when to call it, how to paginate, and what `status` does and does not mean. No critical behavioral or usage detail is missing.

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?

Schema description coverage is 100%, so the baseline is 3 because the only parameter `page` is already documented in the schema. The description adds extra actionable value by explaining that pagination is 50 per page, that `page` fetches further pages, and that `has_more` signals remaining results, going beyond the schema's basic parameter definition.

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 opens with a specific verb and resource: 'List the game servers this Pterodactyl API key can access,' and names the returned fields: short identifiers, node, primary allocation, and resource limits. It is clearly distinguishable from ptero_get_server and ptero_get_server_resources because it is explicitly about listing all accessible servers rather than fetching one resource or live power state.

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

Usage Guidelines5/5

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

The description gives explicit when-to-use guidance: 'Use this first when you do not already know a server identifier, or when a call fails with "not found"' and notes that every other ptero_* tool requires that identifier. It also directs the agent to ptero_get_server_resources when live power state is needed, providing a clear alternative.

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

ptero_read_fileRead a file from the serverA
Read-onlyIdempotent

Read a text file from the game server, relative to the server root. Returns the contents plus the file size.

THIS IS THE WAY TO GET FULL BOOT-TIME OUTPUT. Read logs/latest.log. The live console (ptero_get_console_log) only keeps roughly the last 150 lines, so within an hour of boot the plugin startup lines — which port Geyser bound to, which plugin failed to load, why the world took so long — have already rolled out of it. logs/latest.log has the whole history of the current boot; older boots are gzipped in logs/ as <date>-<n>.log.gz (this tool cannot decompress those). If a question is about what happened at startup, read the log file — do not answer from the console buffer and do not assume the buffer is complete.

Other good uses: plugin configuration (plugins/Geyser-Spigot/config.yml), server.properties, eula.txt, crash reports in crash-reports/.

Size guard: the tool first checks the size in the directory listing and REFUSES to fetch anything larger than max_bytes (default from PTERODACTYL_MAX_READ_BYTES, hard cap 4 MiB, which is the panel's own limit). It never partially downloads a huge file. head_lines / tail_lines trim AFTER the download, so they do not help you get past the size guard — the panel has no range-read endpoint.

Binary files (jars, region files, images) are not readable this way; use ptero_list_files to inspect them by size and date instead.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesFile path relative to the server root, e.g. `logs/latest.log` or `plugins/Geyser-Spigot/config.yml`. Leading slashes are optional. Use ptero_list_files if you are unsure of the exact path.
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
max_bytesNoRefuse to read a file larger than this many bytes. Defaults to PTERODACTYL_MAX_READ_BYTES. Hard-capped at 4194304 (4 MiB), the panel's own edit-size limit. Raise it deliberately when a refusal tells you the file is bigger than the default but still within the cap.
head_linesNoReturn only the first N lines. Applied after the full file is fetched. Mutually exclusive with tail_lines.
tail_linesNoReturn only the last N lines. Applied after the full file is fetched, so it reduces context, not download size. Mutually exclusive with head_lines. This is usually what you want for `logs/latest.log`.

Output Schema

ParametersJSON Schema
NameRequiredDescription
pathYesServer-relative path that was read.
serverYes
contentYesFile contents, after any head_lines/tail_lines trimming. Verbatim otherwise.
size_bytesYesFull size of the file on disk, per the directory listing.
truncated_toYesnull when the whole file is returned. Otherwise describes the trim that was applied, e.g. "last 200 of 5310 lines".
lines_returnedYesNumber of lines in `content`.

TDQS

A5/5.0
Behavior5/5

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

Beyond the readOnlyHint annotation, the description discloses key behaviors: the size guard that refuses oversized files, the fact that head/tail trimming happens after download (so it doesn't bypass the size limit), and the inability to read binary files. These are critical operational details not visible in the annotations or schema.

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 thorough yet organized with clear paragraphs and bullet-like separation. It front-loads the most critical use case (boot logs) and then covers other uses, followed by limitations. No unnecessary filler; every sentence adds value, making it easy for an agent to parse quickly.

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 description is comprehensive for a complex tool with an output schema and rich annotations. It covers key use cases, critical limitations, and operational constraints. The presence of an output schema means return values are already documented, so the description focuses on when and how to use the tool, which it does fully.

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

Parameters5/5

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

Even though the input schema already covers all parameters at 100%, the description adds substantial semantic context. It explains the default and hard cap for max_bytes, the relationship between head_lines and tail_lines (mutually exclusive, post-download), and practical advice like using tail_lines for logs. This goes well beyond the schema descriptions.

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 specifies the action ('Read a text file from the game server') and the resource (file relative to server root), with concrete examples. It distinguishes itself from siblings by emphasizing that this is the definitive method for retrieving full boot logs, unlike the console log tool.

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

Usage Guidelines5/5

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

The description provides explicit when-to-use guidance, including a critical scenario (boot-time diagnostics) and names the alternative tool (ptero_get_console_log) with a concrete reason to prefer this one. It also lists other common use cases (config files, crash reports) and notes when not to use it (binary files, large files).

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

ptero_rename_fileRename or move a fileA

Rename a file or directory — and, because from and to are both interpreted relative to root, MOVE it between directories too. root="/", from="plugins/old.jar", to="plugins/disabled/old.jar" moves the jar into the disabled folder. The destination directory must already exist.

This is the safe way to take a plugin or config out of service: rename it rather than deleting it, and it can be renamed back. Prefer this over ptero_delete_file whenever the change might need undoing.

Both the source and the destination are checked against PTERODACTYL_PROTECTED_PATHS, so a rename cannot be used to move something out of a protected directory. No backup is taken (nothing is destroyed) and no confirmation is required, but the call is counted against PTERODACTYL_MAX_MUTATIONS and audited.

It does not create directories and it does not overwrite: if to already exists the panel returns an error.

ParametersJSON Schema
NameRequiredDescriptionDefault
toYesNew path, relative to `root`. Give a different directory here to move the file rather than just rename it. Must not already exist.
fromYesExisting path, relative to `root`. E.g. `plugins/old.jar`.
rootNoDirectory that `from` and `to` are relative to. Defaults to `/` (the server root), which lets you move between directories by giving full paths in `from` and `to`./
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
dry_runNoWhen true, validate and preview the change without performing it. Nothing is modified and no confirmation token is issued. Use this to reason about an operation before committing to it.
confirmation_tokenNoTwo-phase confirmation token. Leave this out on the first call: the tool will refuse to act and instead return a preview of exactly what would change, plus a single-use token that expires in 120 seconds. THE PREVIEW IS FOR THE HUMAN — show it to the user in your reply and let them decide. Do not silently round-trip the token back in an immediate second call. Only call again with the token once the user has seen the preview and approved it. The token is bound to a hash of these exact arguments, so changing any argument invalidates it.

Output Schema

ParametersJSON Schema
NameRequiredDescription
toNo
fromNo
rootNo
reasonNoWhy the call was refused.
serverYes
statusYessuccess = the change was made. refused = a guardrail blocked it (see reason/variable). dry_run = nothing changed; preview shows what would. needs_confirmation = nothing changed; SHOW the preview to the human and, only if they agree, call again with confirmation_token.
messageNo
previewNoWhat would / did change.
to_pathNoFull server-relative destination path.
variableNoEnvironment variable that caused the refusal.
backup_idNoUUID of the automatic pre-change backup, if one was taken.
from_pathNoFull server-relative source path.
expires_in_sNo
confirmed_viaNo
confirmation_tokenNo

TDQS

A4.3/5.0
Behavior3/5

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

The description discloses protected-path checks, no-overwrite behavior, no-directory-creation, and mutation accounting, which adds real value beyond the annotations. However, it states 'no confirmation is required' while the confirmation_token parameter says the tool will refuse to act without a token and requires human approval, an internal inconsistency that undermines an otherwise strong disclosure.

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

Conciseness4/5

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

The description is front-loaded with the core action and move capability, and every paragraph adds operational context. It is longer than necessary and contains the contradictory confirmation statement, but there is no filler.

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 mutation tool with six parameters, the description covers use case, constraints, safety, and relationship to sibling tools; a rich output schema covers the return value. The confirmation-token contradiction is the main completeness gap, preventing a 5.

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?

Schema coverage is 100%, so the schema already documents all six parameters. The description adds a concrete move example and reinforces that from/to are both root-relative, going slightly beyond the bare schema.

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 names the operation ('Rename a file or directory') and immediately extends it to moving by interpreting both from and to relative to root, with a concrete example. This clearly distinguishes the tool from ptero_delete_file and ptero_copy_file.

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

Usage Guidelines5/5

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

It explicitly says to prefer this over ptero_delete_file whenever a change might need undoing, giving a clear when-to-use rule. It also sets boundaries by stating the destination directory must already exist and that overwriting is not supported.

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

ptero_send_console_commandSend a Pterodactyl console commandA
Destructive

Send a command to the server console via the panel's command endpoint (the panel forwards it to the running process). This confirms DISPATCH ONLY — it does NOT return the command's output. Wings does not correlate console output with the command that produced it, so there is no request/response shape to report here, faked or otherwise: the output is asynchronous. Call ptero_get_console_log immediately afterwards (a window_seconds of 3-5 is usually enough) to read what the command did.

Do not use this to stop, restart or kill the server. A command like stop will shut it down, but ptero_set_power_state is the correct, guarded way to change power state and should be preferred for that.

The panel answers with HTTP 502 when the target server is offline, since console commands require a running server — that is reported back as an actionable error telling you to start the server with ptero_set_power_state first.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
commandYesThe exact command to send, as you would type it at the console (no leading `/`). 1-4096 characters, a single line, trimmed of surrounding whitespace.
dry_runNoWhen true, validate and preview the change without performing it. Nothing is modified and no confirmation token is issued. Use this to reason about an operation before committing to it.

Output Schema

ParametersJSON Schema
NameRequiredDescription
reasonNoWhy the call was refused.
serverYes
statusYessuccess = the change was made. refused = a guardrail blocked it (see reason/variable). dry_run = nothing changed; preview shows what would. needs_confirmation = nothing changed; SHOW the preview to the human and, only if they agree, call again with confirmation_token.
commandNoThe exact command that was dispatched.
messageNo
previewNoWhat would / did change.
variableNoEnvironment variable that caused the refusal.
backup_idNoUUID of the automatic pre-change backup, if one was taken.
dispatchedNoTrue once the panel accepted the command for delivery to the daemon.
expires_in_sNo
confirmed_viaNo
confirmation_tokenNo

TDQS

A4.7/5.0
Behavior5/5

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

Annotations already mark this as destructive and non-read-only, but the description adds substantial behavioral context: the action is asynchronous, output is not correlated by Wings, no request/response shape exists, and the panel returns HTTP 502 when the server is offline. This goes well beyond the structured annotation fields and does not contradict them.

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 front-loaded with the core action and then uses every remaining sentence for a high-value caveat: dispatch-only semantics, the follow-up log call, the power-state alternative, and the offline error behavior. Nothing feels redundant or promotional; the length is justified by the tool's async and destructive nature.

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 tool's complexity—async console dispatch, destructive potential, and offline failure mode—the description covers all essential operational context: what is returned, what is not returned, how to observe results, which sibling tool to use for power state, and how offline errors are reported. An output schema exists, so not detailing return fields is acceptable.

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 all three parameters (server, command, dry_run) already documented in detail. The description adds a relevant example command (`stop`) and mentions `window_seconds` for the follow-up log call, but it does not need to restate parameter meanings. Baseline 3 is appropriate since the schema carries the parameter documentation burden.

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 opens with a specific verb and resource: 'Send a command to the server console via the panel's command endpoint.' It also clarifies the exact scope of the action by stating it is 'DISPATCH ONLY' and does not return command output, which clearly distinguishes it from ptero_get_console_log and ptero_set_power_state.

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

Usage Guidelines5/5

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

The description gives explicit usage guidance: call ptero_get_console_log immediately afterwards to read output, do not use this tool to stop/restart/kill the server, and prefer ptero_set_power_state for power changes. It also explains the offline 502 behavior and directs the agent to start the server first. This leaves no ambiguity about when to use this tool versus alternatives.

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

ptero_set_power_stateSet Pterodactyl server power stateA
Destructive

Send a power signal to the server. start boots it from offline. stop gracefully shuts it down, saving the world first, and disconnects any connected players. restart stops then starts it again, briefly disconnecting players. kill forcibly terminates the process immediately, without saving.

kill is a hard stop and risks world corruption: prefer stop in almost every case, and reach for kill only when the server is hung and unresponsive to a normal stop. kill additionally refuses to run unless PTERODACTYL_ALLOW_KILL=true is set, and when it does proceed an automatic backup is taken first (the kill is aborted if that backup fails).

stop, restart and kill are destructive and require explicit human confirmation before they run — via MCP elicitation where the client supports it, otherwise a two-phase confirmation_token. On the first call (no token) nothing changes: you get back a preview of the current state and what the signal will do. THIS PREVIEW IS FOR THE HUMAN — show it in your reply and wait for their decision; do not silently call the tool again with the token yourself. Only call again, with the same arguments plus confirmation_token, once the human has approved it. start needs no confirmation.

Power actions are rate-limited to one per 30 seconds regardless of signal, to stop restart loops — a second power call inside that window is refused, naming how long to wait.

Set wait_seconds (0-60, default 0) to poll the live power state every 2 seconds after the signal is dispatched and report it back as state_after, instead of returning immediately with only the signal that was sent.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
signalYesPower signal to send. start = boot; stop = graceful shutdown (disconnects players); restart = stop then start (disconnects players); kill = hard-kill the process (risks world corruption — prefer stop).
dry_runNoWhen true, validate and preview the change without performing it. Nothing is modified and no confirmation token is issued. Use this to reason about an operation before committing to it.
wait_secondsNoAfter dispatching the signal, poll the power state every 2 seconds for up to this many seconds (0-60, default 0 = do not wait) and report the final state as `state_after`.
confirmation_tokenNoTwo-phase confirmation token. Leave this out on the first call: the tool will refuse to act and instead return a preview of exactly what would change, plus a single-use token that expires in 120 seconds. THE PREVIEW IS FOR THE HUMAN — show it to the user in your reply and let them decide. Do not silently round-trip the token back in an immediate second call. Only call again with the token once the user has seen the preview and approved it. The token is bound to a hash of these exact arguments, so changing any argument invalidates it.

Output Schema

ParametersJSON Schema
NameRequiredDescription
reasonNoWhy the call was refused.
serverYes
signalNoThe power signal that was sent. Present only on `status: "success"`.
statusYessuccess = the change was made. refused = a guardrail blocked it (see reason/variable). dry_run = nothing changed; preview shows what would. needs_confirmation = nothing changed; SHOW the preview to the human and, only if they agree, call again with confirmation_token.
messageNo
previewNoWhat would / did change.
variableNoEnvironment variable that caused the refusal.
backup_idNoUUID of the automatic pre-change backup, if one was taken.
state_afterNoDaemon power state after polling for `wait_seconds`. Only present when `wait_seconds` was greater than 0.
expires_in_sNo
confirmed_viaNo
previous_stateNoDaemon power state captured immediately before the signal was dispatched (offline/starting/running/stopping/unknown). Present only on `status: "success"`.
confirmation_tokenNo

TDQS

A4.9/5.0
Behavior5/5

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

Beyond destructiveHint=true, it discloses that stop/restart/kill require confirmation, the first call is preview-only, kill is gated behind an environment variable plus auto-backup and aborts if the backup fails, and power actions are rate-limited. This adds substantial non-obvious behavior not visible from annotations alone.

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?

Although long, every paragraph carries a distinct safety or workflow fact, and the most critical warnings (kill risk, confirmation, preview) are front-loaded. Paragraph breaks keep it scannable rather than a wall of text.

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 destructive, confirmation-gated, rate-limited tool with five parameters and an output schema, this description is complete: an agent knows when to act, what will happen, what can go wrong, how to confirm, and what wait_seconds changes about the return value.

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 schema already covers all five parameters with 100% description coverage, so the baseline is high. The description still adds real value by explaining world-saving semantics for stop, corruption risk for kill, the preview/two-phase token contract, and the state_after polling effect of wait_seconds.

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 opening sentence pins the action to a specific verb ('Send a power signal') and resource ('the server'), and the four signal names make the scope unmistakable. It is clearly distinct from the sibling read, file, backup, and console-command tools.

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

Usage Guidelines5/5

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

It gives explicit operational rules for choosing signals: prefer stop, use kill only when hung, and start needs no confirmation. It also explains the two-phase confirmation workflow and rate limit, so an agent knows exactly when to call, when to wait, and when to avoid the tool.

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

ptero_upload_fileUpload a local file to the serverA
DestructiveIdempotent

Upload a file from the machine running this MCP server to the game server, BYTE FOR BYTE. This is the tool for binaries — plugin jars, zips, datapack archives, images, region files — anything ptero_write_file cannot carry because that tool is text-only and would corrupt non-UTF-8 bytes.

You pass a PATH, not content: local_path must be an absolute path to a file that already exists on the machine this server runs on, and the server reads the bytes itself. There is no way to hand it base64 or any other inline payload, so if the file only exists in this conversation, write it to local disk first and pass that path.

It uploads exactly one file and does not unpack anything: a .zip or .tar.gz arrives as an archive, still compressed. There is no decompress tool here.

Creating a NEW remote file runs immediately. OVERWRITING an existing one is destructive: the first call returns status "needs_confirmation" with a preview (remote path, current size, new size) and a confirmation_token, and an automatic backup is taken before the upload happens. Show that preview to the human and only call again with the token once they have agreed. Protected paths (PTERODACTYL_PROTECTED_PATHS) are refused outright, and files larger than 64 MiB are refused before anything is read or sent.

VERIFY AFTERWARDS. The panel hands out a short-lived signed URL and the node answers the upload with an empty 200 — that confirms receipt and nothing more. It does not tell you the file landed at the size you sent, and it never tells you whether the server will accept it. Call ptero_list_files on remote_dir and check the size against the bytes this tool reports. A new plugin jar also needs a server restart before it loads.

The file content is never written to the audit log — only its sha256 and length — and neither is the signed upload URL.

ParametersJSON Schema
NameRequiredDescriptionDefault
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
dry_runNoWhen true, validate and preview the change without performing it. Nothing is modified and no confirmation token is issued. Use this to reason about an operation before committing to it.
local_pathYesABSOLUTE path on the machine running this MCP server, e.g. `/Users/me/build/MyPlugin-1.2.0.jar`. Must be an existing, readable, regular file (not a directory, not a device) of at most 64 MiB. Relative paths are refused: this process's working directory is not something you can see.
remote_dirNoDestination DIRECTORY on the game server, relative to the server root — not the destination file path. Defaults to `/` (the server root). Examples: `plugins`, `plugins/Geyser-Spigot`. The file name comes from `remote_name`/`local_path`./
remote_nameNoFile name to use on the server. Defaults to the basename of `local_path`. This is a single name, not a path: it must not contain `/`. Use `remote_dir` to choose the directory.
confirmation_tokenNoTwo-phase confirmation token. Leave this out on the first call: the tool will refuse to act and instead return a preview of exactly what would change, plus a single-use token that expires in 120 seconds. THE PREVIEW IS FOR THE HUMAN — show it to the user in your reply and let them decide. Do not silently round-trip the token back in an immediate second call. Only call again with the token once the user has seen the preview and approved it. The token is bound to a hash of these exact arguments, so changing any argument invalidates it.

Output Schema

ParametersJSON Schema
NameRequiredDescription
pathNoServer-relative path the bytes were uploaded to.
bytesNoSize of the local file, in bytes, as sent.
actionNo
reasonNoWhy the call was refused.
serverYes
sha256Nosha256 of the LOCAL file. Compare it against the uploaded file yourself if it matters.
statusYessuccess = the change was made. refused = a guardrail blocked it (see reason/variable). dry_run = nothing changed; preview shows what would. needs_confirmation = nothing changed; SHOW the preview to the human and, only if they agree, call again with confirmation_token.
messageNo
previewNoWhat would / did change.
variableNoEnvironment variable that caused the refusal.
backup_idNoUUID of the automatic pre-change backup, if one was taken.
expires_in_sNo
confirmed_viaNo
confirmation_tokenNo

TDQS

A5/5.0
Behavior5/5

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

Even though annotations already mark destructiveHint=true, the description adds substantial operational detail: overwriting is two-phase with a preview and single-use token, automatic backup is taken, protected paths are refused, files over 64 MiB are refused, the empty 200 confirms only receipt not integrity, and the audit log excludes file content and signed URLs. This materially exceeds what the annotations alone convey.

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 long but front-loads the core purpose and key constraint in the first sentence, then each paragraph delivers a distinct operational fact: binary vs text, path semantics, no unpacking, confirmation flow, verification, and audit behavior. Every sentence carries safety or correctness consequence, so nothing feels wasted.

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 destructive, high-stakes upload tool with an output schema, this description covers every operational concern an agent needs: when to write content to disk first, the two-phase confirmation protocol with human-in-the-loop expectations, size and path refusals, how to verify success via ptero_list_files, and server restart implications. Nothing relevant to correctly invoking the tool is left unexplained.

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

Parameters5/5

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

Schema coverage is already 100%, and the description adds further meaning on top: local_path must be absolute and existing on the MCP host with no inline payload possible, remote_dir is a directory not a destination path, remote_name must not contain '/', and confirmation_token is tied to the exact arguments and expires in 120 seconds. This gives an agent the operational context the schema alone does not fully imply.

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 names a specific verb and resource: 'Upload a file from the machine running this MCP server to the game server, BYTE FOR BYTE.' It explicitly distinguishes itself from the sibling ptero_write_file by noting that tool is text-only and corrupts non-UTF-8 bytes, so an agent can immediately tell which tool fits a binary file.

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

Usage Guidelines5/5

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

The description gives explicit when-to-use guidance: use this for binaries such as plugin jars, zips, and images, and names ptero_write_file as the alternative that should not be used for non-UTF-8 content. It also gives post-use verification guidance via ptero_list_files and notes that archives are not decompressed, so no decompress tool is expected.

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

ptero_write_fileWrite a file to the serverA
DestructiveIdempotent

Write a text file on the game server. The body you pass REPLACES the file entirely — this is not an append and not a patch. There is no partial write.

ALWAYS call ptero_read_file on the same path first and build the new content from what is actually there. Writing a config from memory silently drops every setting you did not happen to include.

Creating a NEW file runs immediately. OVERWRITING an existing file is treated as destructive: the first call returns status "needs_confirmation" with a preview (path, current size, new size) and a confirmation_token, and an automatic backup is taken before the write actually happens. Show that preview to the human and only call again with the token once they have agreed.

Protected paths (PTERODACTYL_PROTECTED_PATHS — by default the world directories, server.properties, ops.json, whitelist.json and banned-*.json) are refused outright.

The file content itself is never written to the audit log; only its sha256 and length are.

ParametersJSON Schema
NameRequiredDescriptionDefault
pathYesFile path relative to the server root, e.g. `plugins/Geyser-Spigot/config.yml`. Parent directories must already exist. Leading slashes are optional.
serverNoServer short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers.
contentYesThe complete new contents of the file. Everything currently in the file is replaced. Include a trailing newline if the format expects one.
dry_runNoWhen true, validate and preview the change without performing it. Nothing is modified and no confirmation token is issued. Use this to reason about an operation before committing to it.
confirmation_tokenNoTwo-phase confirmation token. Leave this out on the first call: the tool will refuse to act and instead return a preview of exactly what would change, plus a single-use token that expires in 120 seconds. THE PREVIEW IS FOR THE HUMAN — show it to the user in your reply and let them decide. Do not silently round-trip the token back in an immediate second call. Only call again with the token once the user has seen the preview and approved it. The token is bound to a hash of these exact arguments, so changing any argument invalidates it.

Output Schema

ParametersJSON Schema
NameRequiredDescription
pathNoServer-relative path written.
actionNo
reasonNoWhy the call was refused.
serverYes
statusYessuccess = the change was made. refused = a guardrail blocked it (see reason/variable). dry_run = nothing changed; preview shows what would. needs_confirmation = nothing changed; SHOW the preview to the human and, only if they agree, call again with confirmation_token.
messageNo
previewNoWhat would / did change.
variableNoEnvironment variable that caused the refusal.
backup_idNoUUID of the automatic pre-change backup, if one was taken.
expires_in_sNo
bytes_writtenNo
confirmed_viaNo
content_sha256Nosha256 of the content written, for verification.
confirmation_tokenNo

TDQS

A5/5.0
Behavior5/5

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

Even though annotations already mark this as destructive and idempotent, the description adds crucial behavioral detail: the first call returns needs_confirmation with a preview and token, an automatic backup is taken, the token expires in 120 seconds and is bound to argument hash, protected paths are refused, and file content is never written to the audit log. This goes well beyond the 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 long but every block earns its place: replacement semantics, read-first guidance, new-vs-overwrite workflow, protected paths, and audit logging. It is front-loaded with the most important warning about destructive replacement and stays focused throughout.

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 high-risk mutation tool with two-phase confirmation, the description is fully complete. It covers the exact call sequence, confirmation preview, token lifecycle, protected paths, backup behavior, and audit-log implications, so an agent has all necessary context to invoke it correctly.

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

Parameters5/5

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

Although schema coverage is 100%, the description adds significant meaning: content must be the complete new file and may need a trailing newline; dry_run validates without issuing a token; confirmation_token is single-use, time-limited, and invalidated by argument changes. This meaningfully enriches what the schema provides.

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 specific verb and resource: 'Write a text file on the game server' and immediately clarifies that the body REPLACES the file entirely rather than appending or patching. This clearly differentiates it from ptero_read_file and other file tools even before considering siblings.

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

Usage Guidelines5/5

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

The description explicitly instructs the agent to ALWAYS call ptero_read_file first and build new content from what exists. It also specifies when writes run immediately (new files) versus when confirmation is required (overwrites), tells the agent to show the preview to the human, and calls out protected paths that are refused.

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. 20 tool updatesv0.1.0
    • First observedptero_copy_file
    • First observedptero_create_backup
    • First observedptero_delete_backup
    • First observedptero_delete_file
    • First observedptero_get_backup_download_url
    • First observedptero_get_console_log
    • First observedptero_get_server
    • First observedptero_get_server_resources
    • First observedptero_get_startup_variables
    • First observedptero_list_allocations
    • First observedptero_list_backups
    • First observedptero_list_files
    • First observedptero_list_schedules
    • First observedptero_list_servers
    • First observedptero_read_file
    • First observedptero_rename_file
    • First observedptero_send_console_command
    • First observedptero_set_power_state
    • First observedptero_upload_file
    • First observedptero_write_file

TDQS

A4.3/5.0

Scored across 20 tools

Disambiguation5/5

Every tool targets a distinct resource and action: server listing, configuration, live resources, console, power, files, backups, schedules, and startup variables are all cleanly separated. Potentially confusing pairs like ptero_get_server vs ptero_get_server_resources and ptero_get_console_log vs ptero_read_file are explicitly differentiated in their descriptions.

Naming Consistency5/5

All tools follow a uniform ptero_ prefix followed by a verb_noun pattern (list_servers, get_server, write_file, set_power_state, create_backup, get_backup_download_url). The convention is perfectly consistent across all 20 tools with no mixed styles or vague verbs.

Tool Count3/5

At 20 tools, the server is on the heavy side for its scope, covering server info, power, console, files, backups, schedules, allocations, and startup variables. The count is justified by the breadth of the domain, but it feels dense compared to typical well-scoped servers.

Completeness3/5

Core workflows are well covered: full file CRUD (list/read/write/upload/rename/copy/delete), backup lifecycle (list/create/delete/download), power control, console read/write, and configuration introspection. However, schedules are read-only with no create/edit/delete, and startup variables and allocations cannot be mutated, leaving notable gaps for agents that need to modify server configuration.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    Enables AI assistants to interact with and manage Minecraft servers through a standardized interface, supporting server monitoring, player management, log analysis, and command execution.
    11
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables natural language management of Pebblehost Minecraft servers, including server status, control, console commands, file management, and backups.
    MIT