pterodactyl-mcp
Allows an AI assistant to manage game servers hosted on a Pterodactyl Panel, including checking status and resources, reading console output and logs, editing files and configs, managing backups, controlling power, and more.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@pterodactyl-mcpIs my server online and what's the memory usage?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
pterodactyl-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.logwhen 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
Registering with Claude Code (and Claude Desktop)
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 build2. 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_resourcesOr point any profile above at http://127.0.0.1:4567 with the key mock-key.
Generating a Pterodactyl Client API key
Log into the panel (e.g.
https://your-panel.example.com).Go to Account → API Credentials.
Create a new API key. This produces a Client key, prefixed
ptlc_....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 |
| — | Panel base URL, e.g. |
| — | The Client API key ( |
Optional
Variable | Default | Effect |
| unset | Server short identifier (e.g. |
|
| Default largest file |
Guardrails
Variable | Default | Effect |
|
| When |
| unset | Comma-separated allowlist of server short IDs a mutating call may target. If unset and |
|
| File and backup deletion refuse unless this is |
|
| The |
|
| Comma-separated glob patterns that write/delete tools refuse to touch. Matching is case-sensitive, backslashes are normalised to |
| unset | Comma-separated globs carved back out of |
|
| Mutating tool calls allowed per process lifetime; refuses once exhausted. Restart the process to reset the budget. |
|
| Take a backup automatically before any file write, file delete, or |
|
| 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_SERVERis 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_SERVERSnamed 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 explicitserverargument 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.jsFull-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 |
| 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) |
| Full static configuration for one server: limits, feature limits, allocations, SFTP host, Docker image, resolved startup command. | true | false | true | false | — (read-only) |
| Live power state (running/offline/...) and current CPU, memory, disk, network, uptime. | true | false | true | false | — (read-only) |
| Recent console output collected from the Wings websocket over a bounded window. See Console caveats. | true | false | true | false | — (read-only) |
| Send a command to the running server's console. Confirms dispatch only — does not return the command's output. | false | true | false | false |
|
| Directory listing relative to the server root. | true | false | true | false | — (read-only) |
| Read a file's contents. Refuses files above | true | false | true | false | — (read-only) |
| Write/overwrite a file. | false | true | true | false |
|
| Upload a binary local file (plugin jar, zip, image) from the machine running this MCP server to the game server. The complement to | false | true | true | false |
|
| Rename/move a file. | false | false | false | false |
|
| Copy a file. | false | false | false | false | Same as |
| Delete one or more files. | false | true | true | false |
|
|
| false | true | false | false |
|
| List backups for a server. | true | false | true | false | — (read-only) |
| Create a backup. The natural thing to do before any risky change. | false | false | false | false |
|
| Delete a backup. Irreversible. | false | true | true | false |
|
| 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) |
| Read the server's scheduled tasks. | true | false | true | false | — (read-only) |
| List network allocations (ports) assigned to the server. | true | false | true | false | — (read-only) |
| 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 beyondserver.ptero_get_server_resources: no parameters beyondserver.
Console (src/tools/console.ts)
ptero_get_console_log:window_seconds(integer 1-60, default5) — collection window.max_lines(integer 1-1000, default400) — 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 iffilterparses 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, defaultfalse).Guard:
kind: 'command',destructive: false,wantsAutoBackup: false, nopaths. Note: its annotations declaredestructiveHint: true, but the guard's owndestructiveflag isfalse— 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 toPTERODACTYL_MAX_READ_BYTES).tail_lines(integer ≥ 1, optional; mutually exclusive withhead_lines).head_lines(integer ≥ 1, optional; mutually exclusive withtail_lines).
ptero_write_file:path(string, min 1 char, required).content(string, required) — replaces the entire file.dry_run(boolean, defaultfalse).confirmation_token(string, optional).Guard:
kind: 'write',paths: [path],destructiveistrueonly 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_BYTESinsrc/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 oflocal_path) — a single file name, refused if it contains/or\\.dry_run(boolean, defaultfalse).confirmation_token(string, optional).Guard:
kind: 'write',paths: [remote_dir + remote_name],destructiveistrueonly when the remote file already exists (or existence couldn't be determined),wantsAutoBackup: true.
ptero_rename_file:root(string, default/) — directoryfrom/toare relative to.from(string, min 1 char, required).to(string, min 1 char, required).dry_run(boolean, defaultfalse).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, defaultfalse).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 toroot; more than 10 is refused by the guard's bulk-file cap, not by this schema.dry_run(boolean, defaultfalse).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(enumstart | stop | restart | kill, required).dry_run(boolean, defaultfalse).confirmation_token(string, optional).wait_seconds(integer 0-60, default0) — poll every 2s after dispatch and reportstate_after.Guard:
kind: 'power',powerSignal: signal,destructive=signal !== 'start',wantsAutoBackup=signal === 'kill', nopaths.
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, defaulttrue) — block until the panel reports the backup complete (up to ~2 minutes) viacreateBackupAndWait;falsereturns immediately with just theuuid.dry_run(boolean, defaultfalse).Guard:
kind: 'backup_create',destructive: false,wantsAutoBackup: false, nopaths. This tool has noconfirmation_tokenparameter — it never needs one.
ptero_delete_backup:backup_uuid(string, required).dry_run(boolean, defaultfalse).confirmation_token(string, optional).Guard:
kind: 'backup_delete',destructive: true,wantsAutoBackup: false, nopaths.
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 beyondserver.ptero_list_allocations: no parameters beyondserver.ptero_get_startup_variables: no parameters beyondserver.
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:
GET /api/client/servers/{id}/files/uploadat the panel (with the API key) returns{"object":"signed_url","attributes":{"url":"https://<node>:<port>/upload/file?token=<jwt>"}}. The JWT is scopedFileUpload, lives 15 minutes, and is single-use — so the tool mints a fresh one inside every upload and never stores or reuses one.POST <that url>&directory=<remote_dir>goes straight to the Wings node, asmultipart/form-datawith the file in a field namedfileswhose part filename is the name it will get on disk. The panel API key is deliberately not sent on this hop: Wings registers/upload/fileoutside its authorization middleware and authenticates from thetokenquery 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 passeddry_run: true. Nothing changed; the response'spreviewshows what would happen. No confirmation token is issued and this does not count againstPTERODACTYL_MAX_MUTATIONS.needs_confirmation— the operation is destructive and the connected MCP client does not support elicitation (see below). The response carries apreviewof exactly what will change, and aconfirmation_tokenthat: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 resolvedpaths, 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_tokenset.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 asbackup_idin 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_fileonlogs/latest.loginstead — 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_commandonly 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/panelsource (1.0-develop) defaults to 256/minute, admin-configurable viaAPP_API_CLIENT_RATELIMIT. This server does not hardcode either number — it readsX-RateLimit-Limit/X-RateLimit-Remaining/X-RateLimit-Resetfrom 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.mjsandscripts/live-verify-upload.mjs(sequences on throwawaymcp-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_statehas only been exercised by unit tests and the mock-panel smoke run. Both scripts read.envfrom 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_filedecides create-vs-overwrite from a directory listing, and panels have been seen answeringGET /files/listfor a missing directory with a 500UnexpectedValueException(not a 404). The tool cannot tell "not there" from "could not look", so it reportsaction: "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 withptero_delete_backup, take backups manually and setPTERODACTYL_AUTO_BACKUP=falsefor 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 typecheckTesting with MCP Inspector
npm run inspector # npx @modelcontextprotocol/inspector node dist/index.jsThis 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 jsonEach --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
docs/SPEC.md— the original requirements and safety model.docs/ARCHITECTURE.md— module layout and shared contracts.docs/pterodactyl-api.md— the Client API and Wings websocket behaviour this server relies on.
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
Pick (or create) the
src/tools/*.tsfile for the relevant area.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.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.logpattern inconsole.tsis the canonical example).Read-only tool: call the client directly, wrap in
try { return ok(...) } catch (e) { return fail(e) }, done.Mutating tool: build a
MutationRequest(tool, server, args, kind, paths, powerSignal, fileCount, dryRun, confirmationToken, preview, destructive, wantsAutoBackup) and pass it torunMutation(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 theexecutecallback passed torunMutation.Set all four annotations explicitly (
readOnlyHint,destructiveHint,idempotentHint,openWorldHint: false).Register the new
registerXxxTools(ctx)call insrc/index.ts.Add tests under
test/tools/with a mockedPteroClient(seetest/tools/servers.test.tsfor the pattern) — no network in tests.Exercise the new tool at least once with
npm run inspector, and add it to the tables in this README.
Acknowledgements
Pterodactyl Panel and Wings, whose open source code was the reference for every API call and websocket message this server makes.
The Model Context Protocol project, for the TypeScript SDK and MCP Inspector.
The community-maintained Client API docs at pteroapi.com and pterodactyl-api-docs.netvpx.com, which were a great starting point.
License
MIT. Not affiliated with or endorsed by the Pterodactyl project.
Available Tools
20 toolsptero_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.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | File or directory to duplicate, relative to the server root, e.g. `plugins/Geyser-Spigot/config.yml`. | |
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| dry_run | No | When 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_token | No | Two-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
| Name | Required | Description |
|---|---|---|
| note | No | Reminder that the panel chooses the copy's name; list the directory to see it. |
| path | No | Server-relative path that was copied. |
| reason | No | Why the call was refused. |
| server | Yes | |
| status | Yes | success = 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. |
| message | No | |
| preview | No | What would / did change. |
| variable | No | Environment variable that caused the refusal. |
| backup_id | No | UUID of the automatic pre-change backup, if one was taken. |
| expires_in_s | No | |
| confirmed_via | No | |
| confirmation_token | No |
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| name | No | Backup name. Omit to let the panel assign a default name. | |
| wait | No | Wait for the backup to finish before returning (up to ~2 minutes). false returns immediately with just the uuid — check ptero_list_backups for completion. | |
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| dry_run | No | When 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. | |
| ignored | No | Newline-separated list of glob patterns to exclude from the backup, e.g. "cache/**\n*.log". |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | No | |
| uuid | No | |
| bytes | No | |
| reason | No | Why the call was refused. |
| server | Yes | |
| status | Yes | success = 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. |
| message | No | |
| preview | No | What would / did change. |
| variable | No | Environment variable that caused the refusal. |
| backup_id | No | UUID of the automatic pre-change backup, if one was taken. |
| completed | No | True once the backup has finished (only when wait:true). |
| waited_ms | No | Milliseconds spent polling for completion (only when wait:true). |
| bytes_human | No | |
| completed_at | No | |
| expires_in_s | No | |
| confirmed_via | No | |
| is_successful | No | |
| confirmation_token | No |
TDQS
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.
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.
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.
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.
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.
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 backupADestructiveIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| dry_run | No | When 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_uuid | Yes | UUID of the backup to delete (from ptero_list_backups). | |
| confirmation_token | No | Two-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
| Name | Required | Description |
|---|---|---|
| uuid | No | |
| reason | No | Why the call was refused. |
| server | Yes | |
| status | Yes | success = 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. |
| message | No | |
| preview | No | What would / did change. |
| variable | No | Environment variable that caused the refusal. |
| backup_id | No | UUID of the automatic pre-change backup, if one was taken. |
| expires_in_s | No | |
| confirmed_via | No | |
| confirmation_token | No |
TDQS
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.
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.
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.
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.
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.
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 serverADestructiveIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| root | No | Directory the entries in `files` live in, relative to the server root. Defaults to `/`. E.g. `plugins` when deleting `foo.jar`. | / |
| files | Yes | Names 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. | |
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| dry_run | No | When 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_token | No | Two-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
| Name | Required | Description |
|---|---|---|
| root | No | |
| files | No | Names deleted, relative to `root`. |
| reason | No | Why the call was refused. |
| server | Yes | |
| status | Yes | success = 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. |
| message | No | |
| preview | No | What would / did change. |
| variable | No | Environment variable that caused the refusal. |
| backup_id | No | UUID of the automatic pre-change backup, if one was taken. |
| expires_in_s | No | |
| confirmed_via | No | |
| deleted_count | No | |
| confirmation_token | No |
TDQS
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.
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.
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.
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.
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.
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 URLARead-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).
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| backup_uuid | Yes | UUID of the backup to download (from ptero_list_backups). |
Output Schema
| Name | Required | Description |
|---|---|---|
| url | Yes | Signed, short-lived Wings URL. Never logged or audited. |
| note | Yes | |
| uuid | Yes |
TDQS
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.
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.
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.
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.
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.
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 consoleARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| filter | No | Optional 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. | |
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| max_lines | No | Stop 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_seconds | No | How long to stay connected collecting console output, in seconds (1-60, default 5). Collection stops early once `max_lines` is reached. |
Output Schema
| Name | Required | Description |
|---|---|---|
| note | No | Caveats worth surfacing: the server was offline, the node throttled a request, or the filter matched nothing. |
| lines | Yes | Collected console lines, ANSI escape codes stripped, oldest first. Filtered by `filter` when one was given. |
| state | Yes | Wings-reported power state at the time of collection (offline/starting/running/stopping), or "unknown" if no status event arrived during the window. |
| server | Yes | Server short identifier the log was read from. |
| truncated | Yes | True when `max_lines` cut off further backlog or streamed output. |
| line_count | Yes | Number of lines in `lines` (after filtering). |
| duration_ms | Yes | Wall-clock time the collection took, in milliseconds. |
| window_seconds | Yes | The collection window that was actually used. |
TDQS
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.
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.
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.
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.
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.
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 detailsARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. |
Output Schema
| Name | Required | Description |
|---|---|---|
| name | Yes | |
| node | Yes | Name of the node hosting the server. |
| uuid | Yes | |
| limits | Yes | Resource ceilings configured on the panel. |
| status | Yes | Panel 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. |
| identifier | Yes | |
| invocation | Yes | Resolved startup command. Redacted by the panel without startup:read permission. |
| allocations | Yes | Ports assigned to this server. |
| description | Yes | |
| docker_image | Yes | Container image the server runs in. |
| egg_features | No | |
| is_suspended | Yes | Suspended servers reject power and console actions. |
| server_owner | No | True when the API key owns the server rather than being a subuser. |
| sftp_details | Yes | |
| is_installing | Yes | |
| feature_limits | Yes | |
| is_transferring | Yes | True while the server is being moved between nodes. |
| is_node_under_maintenance | No |
TDQS
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.
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.
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.
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.
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.
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 usageARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. |
Output Schema
| Name | Required | Description |
|---|---|---|
| server | Yes | Server short identifier these figures describe. |
| uptime_ms | Yes | Milliseconds since the process started. 0 when offline. |
| disk_bytes | Yes | |
| disk_human | Yes | |
| cpu_absolute | Yes | CPU percent across all cores: 100 = one full core, 200 = two cores. |
| is_suspended | Yes | |
| memory_bytes | Yes | |
| memory_human | Yes | |
| uptime_human | Yes | |
| current_state | Yes | Daemon power state: offline, starting, running, or stopping. |
| network_rx_bytes | Yes | |
| network_rx_human | Yes | |
| network_tx_bytes | Yes | |
| network_tx_human | Yes |
TDQS
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.
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.
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.
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.
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.
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 variablesARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. |
Output Schema
| Name | Required | Description |
|---|---|---|
| server | Yes | |
| variables | Yes | User-viewable egg variables only; hidden ones never appear here. |
| docker_image | No | The container image currently in use, when the panel reports one. |
| startup_command | Yes | The startup command with egg variable placeholders resolved. |
| raw_startup_command | Yes | The startup command template before placeholder substitution. |
TDQS
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.
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.
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.
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.
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.
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 allocationsARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| server | Yes | |
| allocations | Yes |
TDQS
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.
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.
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.
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.
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.
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 backupsARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| per_page | No | Backups per page; the panel clamps this to 50. Omit for the panel default (20). |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | Number of backups on this call (the panel does not paginate this list further here). |
| server | Yes | |
| backups | Yes | |
| backup_count | No | Count of non-failed backups, from the panel (meta.backup_count), when reported. |
| backup_limit | No | Maximum backups this server may hold at once, when the panel reports it. |
TDQS
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.
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.
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.
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.
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.
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 directoryARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| directory | No | Directory to list, relative to the server root. Defaults to `/` (the root). Examples: `plugins`, `logs`, `plugins/Geyser-Spigot`. Leading slashes are optional. | / |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| server | Yes | |
| entries | Yes | Directories first, then files, each group sorted by name. |
| directory | Yes | Directory that was listed, as a server-relative path (`/` = server root). |
| file_count | Yes | |
| directory_count | Yes |
TDQS
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.
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.
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.
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.
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.
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 schedulesARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. |
Output Schema
| Name | Required | Description |
|---|---|---|
| count | Yes | |
| server | Yes | |
| schedules | Yes |
TDQS
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.
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.
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.
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.
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.
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 serversARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| page | No | 1-based page number. Omit for the first page. |
Output Schema
| Name | Required | Description |
|---|---|---|
| page | No | Current page number. |
| count | Yes | Number of servers on this page. |
| total | No | Total servers across all pages, when the panel reports it. |
| servers | Yes | Servers this API key can access, for the requested page. |
| has_more | Yes | True when further pages exist; request them with `page`. |
| total_pages | No | Total number of pages. |
TDQS
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.
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.
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.
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.
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.
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 serverARead-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.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | File 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. | |
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| max_bytes | No | Refuse 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_lines | No | Return only the first N lines. Applied after the full file is fetched. Mutually exclusive with tail_lines. | |
| tail_lines | No | Return 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
| Name | Required | Description |
|---|---|---|
| path | Yes | Server-relative path that was read. |
| server | Yes | |
| content | Yes | File contents, after any head_lines/tail_lines trimming. Verbatim otherwise. |
| size_bytes | Yes | Full size of the file on disk, per the directory listing. |
| truncated_to | Yes | null when the whole file is returned. Otherwise describes the trim that was applied, e.g. "last 200 of 5310 lines". |
| lines_returned | Yes | Number of lines in `content`. |
TDQS
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.
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.
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.
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.
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.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| to | Yes | New path, relative to `root`. Give a different directory here to move the file rather than just rename it. Must not already exist. | |
| from | Yes | Existing path, relative to `root`. E.g. `plugins/old.jar`. | |
| root | No | Directory 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`. | / |
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| dry_run | No | When 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_token | No | Two-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
| Name | Required | Description |
|---|---|---|
| to | No | |
| from | No | |
| root | No | |
| reason | No | Why the call was refused. |
| server | Yes | |
| status | Yes | success = 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. |
| message | No | |
| preview | No | What would / did change. |
| to_path | No | Full server-relative destination path. |
| variable | No | Environment variable that caused the refusal. |
| backup_id | No | UUID of the automatic pre-change backup, if one was taken. |
| from_path | No | Full server-relative source path. |
| expires_in_s | No | |
| confirmed_via | No | |
| confirmation_token | No |
TDQS
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.
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.
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.
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.
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.
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 commandADestructive
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.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| command | Yes | The 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_run | No | When 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
| Name | Required | Description |
|---|---|---|
| reason | No | Why the call was refused. |
| server | Yes | |
| status | Yes | success = 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. |
| command | No | The exact command that was dispatched. |
| message | No | |
| preview | No | What would / did change. |
| variable | No | Environment variable that caused the refusal. |
| backup_id | No | UUID of the automatic pre-change backup, if one was taken. |
| dispatched | No | True once the panel accepted the command for delivery to the daemon. |
| expires_in_s | No | |
| confirmed_via | No | |
| confirmation_token | No |
TDQS
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.
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.
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.
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.
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.
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 stateADestructive
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.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| signal | Yes | Power 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_run | No | When 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_seconds | No | After 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_token | No | Two-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
| Name | Required | Description |
|---|---|---|
| reason | No | Why the call was refused. |
| server | Yes | |
| signal | No | The power signal that was sent. Present only on `status: "success"`. |
| status | Yes | success = 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. |
| message | No | |
| preview | No | What would / did change. |
| variable | No | Environment variable that caused the refusal. |
| backup_id | No | UUID of the automatic pre-change backup, if one was taken. |
| state_after | No | Daemon power state after polling for `wait_seconds`. Only present when `wait_seconds` was greater than 0. |
| expires_in_s | No | |
| confirmed_via | No | |
| previous_state | No | Daemon power state captured immediately before the signal was dispatched (offline/starting/running/stopping/unknown). Present only on `status: "success"`. |
| confirmation_token | No |
TDQS
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.
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.
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.
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.
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.
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 serverADestructiveIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| dry_run | No | When 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_path | Yes | ABSOLUTE 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_dir | No | Destination 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_name | No | File 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_token | No | Two-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
| Name | Required | Description |
|---|---|---|
| path | No | Server-relative path the bytes were uploaded to. |
| bytes | No | Size of the local file, in bytes, as sent. |
| action | No | |
| reason | No | Why the call was refused. |
| server | Yes | |
| sha256 | No | sha256 of the LOCAL file. Compare it against the uploaded file yourself if it matters. |
| status | Yes | success = 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. |
| message | No | |
| preview | No | What would / did change. |
| variable | No | Environment variable that caused the refusal. |
| backup_id | No | UUID of the automatic pre-change backup, if one was taken. |
| expires_in_s | No | |
| confirmed_via | No | |
| confirmation_token | No |
TDQS
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.
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.
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.
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.
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.
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 serverADestructiveIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| path | Yes | File path relative to the server root, e.g. `plugins/Geyser-Spigot/config.yml`. Parent directories must already exist. Leading slashes are optional. | |
| server | No | Server short identifier (e.g. 1a2b3c4d). Omit to use PTERODACTYL_DEFAULT_SERVER. Call ptero_list_servers to discover valid identifiers. | |
| content | Yes | The complete new contents of the file. Everything currently in the file is replaced. Include a trailing newline if the format expects one. | |
| dry_run | No | When 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_token | No | Two-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
| Name | Required | Description |
|---|---|---|
| path | No | Server-relative path written. |
| action | No | |
| reason | No | Why the call was refused. |
| server | Yes | |
| status | Yes | success = 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. |
| message | No | |
| preview | No | What would / did change. |
| variable | No | Environment variable that caused the refusal. |
| backup_id | No | UUID of the automatic pre-change backup, if one was taken. |
| expires_in_s | No | |
| bytes_written | No | |
| confirmed_via | No | |
| content_sha256 | No | sha256 of the content written, for verification. |
| confirmation_token | No |
TDQS
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.
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.
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.
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.
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.
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.
20 tool updates
v0.1.0- First observed
ptero_copy_file - First observed
ptero_create_backup - First observed
ptero_delete_backup - First observed
ptero_delete_file - First observed
ptero_get_backup_download_url - First observed
ptero_get_console_log - First observed
ptero_get_server - First observed
ptero_get_server_resources - First observed
ptero_get_startup_variables - First observed
ptero_list_allocations - First observed
ptero_list_backups - First observed
ptero_list_files - First observed
ptero_list_schedules - First observed
ptero_list_servers - First observed
ptero_read_file - First observed
ptero_rename_file - First observed
ptero_send_console_command - First observed
ptero_set_power_state - First observed
ptero_upload_file - First observed
ptero_write_file
TDQS
Scored across 20 tools
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.
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.
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.
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
Related MCP Connectors
Manage FadeHost game servers, Discord bots and VPS: console, stats, backups, logs, lifecycle.
Create, configure, manage Minecraft servers — plugins, files, console, modpacks, backups, metrics.
Manage Laravel Forge servers, sites, and deployments from your AI assistant.
- mcpOAuthnet.hepcloud
Manage HepCloud (Turkish cloud) servers and managed PostgreSQL from your AI assistant. OAuth 2.1.
Related MCP Servers
- AlicenseBqualityCmaintenanceEnables AI assistants to interact with and manage Minecraft servers through a standardized interface, supporting server monitoring, player management, log analysis, and command execution.11MIT
- AlicenseNot gradedqualityDmaintenanceEnables managing Pterodactyl Game Panel servers via Client and Application APIs, including power actions, files, databases, backups, schedules, and administrative operations.115 npmMIT

truetick-mcpofficial
AlicenseBqualityFmaintenanceManage TrueTick Minecraft hosting servers from AI agents: create/start/stop, live TPS/MSPT metrics, RCON console, files, backups, and Modrinth/CurseForge mods.2734 npmMIT- AlicenseNot gradedqualityDmaintenanceEnables natural language management of Pebblehost Minecraft servers, including server status, control, console commands, file management, and backups.MIT