Skip to main content
Glama

MCPDactyl

MCP server for the Pterodactyl Panel, versions 1.x and 2.0. Manage servers, files, databases and more across multiple panels from one MCP server. Runs over stdio and Streamable HTTP, locally, in Docker, or as a remote server on Cloudflare Workers.

Panels are not baked into the install config — you add them at runtime and switch between them. MCPDactyl detects whether a panel runs 1.x or 2.0 and offers the tools that fit it.

Status: v0.1. The full Client API and Application (admin) API for 1.x and 2.0, plus the 2.0 Admin API (~230 tools on a 2.0 panel). 2.0 support follows the 2.0 beta documentation and has not been run against a live 2.0 panel yet; 1.x is the better-exercised path. See ARCHITECTURE.md for the design.

Install

Needs Node 20+ and pnpm.

git clone https://github.com/MrMirhan/mcpdactyl.git
cd mcpdactyl
pnpm install
pnpm build

Related MCP server: Pterodactyl MCP Server

Run (stdio)

node dist/index.js

Register it with an MCP client, using the absolute path of your clone. Claude Code:

claude mcp add mcpdactyl -- node /path/to/mcpdactyl/dist/index.js

Any client that reads an mcpServers config (Claude Desktop, Cursor, …):

{
  "mcpServers": {
    "mcpdactyl": { "command": "node", "args": ["/path/to/mcpdactyl/dist/index.js"] }
  }
}

Then add a panel from the chat with panel_add (see Panels).

Run (Streamable HTTP)

node dist/index.js --http --port 3000 --host 127.0.0.1
# endpoint: http://127.0.0.1:3000/mcp  (POST/GET/DELETE)

Each MCP session gets its own active-panel state; saved panels are shared via the config file. Set MCPDACTYL_HTTP_TOKEN to require Authorization: Bearer <token> on every request. Bind to a public host only behind auth/TLS — the panel registry is shared across clients (or use MCPDACTYL_STATELESS=1 so every call must carry inline creds).

A caller that acts for different people can pin each session to one panel instead: send x-ptero-base-url and x-ptero-client-key and/or x-ptero-application-key headers on the initialize request. That session talks to that panel only; nothing is read from or written to the shared store, and no key appears in a tool argument. With MCPDACTYL_SEALED=1 the tools also stop accepting baseUrl/clientKey/applicationKey arguments and panel_add, panel_remove and panel_use are not registered.

Docker (HTTP)

docker build -t mcpdactyl .
docker run -p 3000:3000 -e MCPDACTYL_HTTP_TOKEN=your-secret mcpdactyl

The image is a self-contained bundle (no node_modules). Seed panels with -e MCPDACTYL_PANELS='[{"name":"prod","baseUrl":"https://panel","clientKey":"ptlc_…"}]' or mount a config dir at ~/.config/mcpdactyl. Always set MCPDACTYL_HTTP_TOKEN when exposing the port. The image serves the client tools by default; add -e MCPDACTYL_TOOLS=all for the admin tools too.

Cloudflare Workers (remote, free tier)

worker/index.ts runs MCPDactyl as a remote MCP server via the agents McpAgent on a Durable Object (per-session active panel) with Workers KV for the shared panel registry. The WebSocket console tool is omitted on Workers (ws is Node-only). All other tools are identical — they reuse the same pteroRequest and tool modules.

npx wrangler kv namespace create PANELS   # replace REPLACE_WITH_YOUR_KV_NAMESPACE_ID in wrangler.jsonc
npx wrangler deploy                        # needs a Cloudflare account (free plan is enough)

Endpoint: https://<worker>.workers.dev/mcp (Streamable HTTP). Choose the surface with the MCPDACTYL_TOOLS var (wrangler.jsonc ships with all); seed read-only panels with an MCPDACTYL_PANELS secret or let clients panel_add at runtime (persisted to KV).

Protect the public endpoint with a bearer token. Set MCPDACTYL_HTTP_TOKEN as a secret and every request must send Authorization: Bearer <token> — otherwise anyone who reaches the URL can use stored panel keys:

npx wrangler secret put MCPDACTYL_HTTP_TOKEN   # paste a long random token

Claude's built-in remote-MCP connector expects OAuth, so for a bearer connect through mcp-remote, which injects the header:

{ "mcpServers": { "mcpdactyl": {
  "command": "npx",
  "args": ["mcp-remote", "https://<worker>.workers.dev/mcp", "--header", "Authorization: Bearer <token>"]
}}}

pnpm cf:check validates the build without deploying; pnpm cf:dev runs it locally.

Free-tier fit: Workers 100k req/day, Durable Objects on the free plan (SQLite), KV 100k reads + 1k writes/day — ample for a personal proxy. CPU limit (10ms/invocation) is fine because the work is I/O-bound (fetch to the panel).

Panels

No URL or key in the MCP config. Manage panels via tools:

  • panel_add { name, baseUrl, clientKey?, applicationKey?, apiVersion?, makeDefault?, test? }

  • panel_list — keys masked

  • panel_use { name } — active panel for this session

  • panel_test { name? } — validate keys and re-detect the panel's API version

  • panel_remove { name }

Every panel-targeting tool also accepts panel (a saved name) or inline baseUrl + clientKey/applicationKey. Resolution order: inline > panel name > active > default.

Client API keys start with ptlc_, Application (admin) keys with ptla_. A tool fails clearly if the selected panel lacks the key type it needs.

Panel versions (1.x and 2.0)

Each panel's API version is detected the first time a version-bound tool needs it, from whether /api/admin/version exists (2.0) or not (1.x). With only an application key the check uses /api/application/tags. The answer is cached on the panel (detectedApiVersion); panel_test probes again, for a panel upgraded since. Pin it with apiVersion: "1" or "2" in panel_add (or in MCPDACTYL_PANELS) to skip detection.

The version decides what is offered and how a call is sent:

  • 1.x: nest tools (admin_nest_list, admin_nest_get) are listed. admin_egg_list without nest collects every egg through the nests.

  • 2.0: tag tools (admin_tag_list, admin_tag_get), admin_node_deployable and the whole Admin API (adminapi_*, 115 tools) are listed. admin_egg_list and admin_egg_get use the flat egg routes, and a nest id is mapped to its tag through legacy_nest_id.

  • Unknown (not detected yet): both small sets are listed and the Admin API is not.

The tool list follows the active panel and the client is sent tools/list_changed when it changes. A tool that needs one version also checks it when called, since a call can name another panel, and says which version the panel runs. On 2.0 a root administrator's client key also works where an application key is asked for.

Storage & env

  • Panels persist to ~/.config/mcpdactyl/panels.json (chmod 600).

  • MCPDACTYL_CONFIG_DIR — override the config directory.

  • MCPDACTYL_PANELS — JSON seed read at boot, never written to disk.

  • MCPDACTYL_STATELESS=1 — disable persistence; every call must carry inline creds.

  • MCPDACTYL_TRANSPORT=http|stdio, MCPDACTYL_HTTP_HOST, MCPDACTYL_HTTP_PORT, MCPDACTYL_HTTP_TOKEN — HTTP transport.

  • MCPDACTYL_SEALED=1 — hide the credential arguments and the panel-switching tools (see Run (Streamable HTTP)).

  • MCPDACTYL_TOOLS=client|admin|all — which API surface to expose (default client). Application tools need a ptla_ key (or, on 2.0, a root admin's ptlc_ key); the Admin API needs a root admin's ptlc_ key.

Tools

Panel: panel_add, panel_list, panel_use, panel_test, panel_remove.

Full Client API (all accept panel / inline creds):

  • Servers: server_list, server_get, server_resources, server_power, server_command, server_activity

  • Settings: server_startup_get, server_set_variable, server_rename, server_reinstall, server_docker_image

  • Console: server_console_tail (WebSocket, bounded capture window)

  • Files: files_list, files_read, files_write, files_rename, files_copy, files_mkdir, files_delete, files_compress, files_decompress, files_chmod, files_pull, files_download_url, files_upload_url

  • Databases: db_list, db_create, db_rotate_password, db_delete

  • Schedules: schedule_list, schedule_get, schedule_create, schedule_update, schedule_delete, schedule_execute, schedule_task_create, schedule_task_update, schedule_task_delete

  • Network: network_list, network_assign, network_set_primary, network_set_notes, network_delete

  • Backups: backup_list, backup_create, backup_get, backup_download_url, backup_restore, backup_toggle_lock, backup_delete

  • Subusers: subuser_list, subuser_get, subuser_create, subuser_update, subuser_delete, permissions_list, and subuser_set_files (only for panels running an SFTP-permissions addon; it is a route the stock panel does not have)

  • Account: account_get, account_activity, account_2fa_get, account_2fa_enable, account_2fa_disable, account_update_email, account_update_password, account_apikey_list, account_apikey_create, account_apikey_delete, account_sshkey_list, account_sshkey_create, account_sshkey_remove

Application API (admin, ptla_ key; opt-in via MCPDACTYL_TOOLS=admin or all):

  • Users: admin_user_list, admin_user_get, admin_user_get_external, admin_user_create, admin_user_update, admin_user_delete

  • Servers: admin_server_list, admin_server_get, admin_server_get_external, admin_server_create, admin_server_update_details, admin_server_update_build, admin_server_update_startup, admin_server_suspend, admin_server_unsuspend, admin_server_reinstall, admin_server_delete

  • Server databases: admin_server_db_list, admin_server_db_get, admin_server_db_create, admin_server_db_reset_password, admin_server_db_delete

  • Nodes: admin_node_list, admin_node_get, admin_node_deployable, admin_node_config, admin_node_create, admin_node_update, admin_node_delete, admin_node_alloc_list, admin_node_alloc_create, admin_node_alloc_delete

  • Locations: admin_location_list, admin_location_get, admin_location_create, admin_location_update, admin_location_delete

  • Nests & eggs: admin_nest_list, admin_nest_get (Pterodactyl 1.x only), admin_egg_list, admin_egg_get (pass nest on 1.x; omit it on 2.0)

  • Tags (Pterodactyl 2.0, replace nests): admin_tag_list, admin_tag_get

Admin API (Pterodactyl 2.0 only, a root administrator's ptlc_ key; MCPDACTYL_TOOLS=admin or all): one adminapi_* tool per operation of /api/admin: users, servers (mounts, transfer, rebuild, suspension, databases, backups), nodes (allocations, tags, utilization, deploy token), locations, mounts, eggs (variables, scripts, export, import, catalog), tags, settings, database hosts, API keys, extensions and the panel version. The tools are generated from the OpenAPI document of the 2.0 docs: node scripts/gen-admin-api.mjs [openapi-v2.json | URL] rewrites src/tools/admin/definitions.ts. Query filters such as filter[name] are arguments named filter_name. Uploads (adminapi_install_extension, adminapi_import_egg, adminapi_update_egg_from_import) take the file as base64, or the JSON text itself for an egg.

Develop

pnpm typecheck         # tsc --noEmit
pnpm typecheck:worker  # the same for the Cloudflare Worker entry
pnpm lint              # biome
pnpm test              # vitest: request client, panel registry, version detection, tools, Admin API
pnpm build             # tsup -> dist/index.js
pnpm smoke             # end-to-end stdio test, no real panel needed
pnpm smoke:http        # end-to-end Streamable HTTP test
pnpm cf:check          # Worker build dry-run

CI (.github/workflows/ci.yml) runs all of these. node scripts/gen-admin-api.mjs regenerates the Admin API tools from the 2.0 OpenAPI document.

License

MIT, see LICENSE.

Available Tools

75 tools
account_2fa_disableDisable 2FAC

Disable two-factor authentication with the account password.

Inputs: password (required), panel, baseUrl, clientKey, +1 more.

account_2fa_enableEnable 2FAB

Enable two-factor authentication by confirming a TOTP code. Returns recovery tokens.

Inputs: code (required), panel, baseUrl, clientKey, +1 more.

account_2fa_getGet 2FA setupB

Get the TOTP secret / QR image URL to enable two-factor authentication.

Inputs: panel, baseUrl, clientKey, applicationKey.

account_activityAccount activity logC

Get the account activity log.

Inputs: page, sort, event, panel, +5 more.

account_apikey_createCreate API keyB

Create a new client API key. The secret is only returned once.

Inputs: description (required), panel, baseUrl, clientKey, +2 more.

account_apikey_deleteDelete API keyC

Revoke a client API key by its identifier.

Inputs: identifier (required), panel, baseUrl, clientKey, +1 more.

account_apikey_listList API keysB

List the account's client API keys.

Inputs: panel, baseUrl, clientKey, applicationKey.

account_getGet accountB

Get the authenticated user's account details.

Inputs: panel, baseUrl, clientKey, applicationKey.

account_sshkey_createAdd SSH keyC

Add an SSH public key to the account.

Inputs: name (required), public_key (required), panel, baseUrl, +2 more.

account_sshkey_listList SSH keysC

List the account's SSH keys.

Inputs: panel, baseUrl, clientKey, applicationKey.

account_sshkey_removeRemove SSH keyC

Remove an SSH key from the account by fingerprint.

Inputs: fingerprint (required), panel, baseUrl, clientKey, +1 more.

account_update_emailUpdate emailB

Change the account email. Requires the current password.

Inputs: email (required), password (required), panel, baseUrl, +2 more.

account_update_passwordUpdate passwordC

Change the account password.

Inputs: password (required), current_password (required), password_confirmation (required), panel, +3 more.

backup_createCreate a backupC

Start a new backup. ignored is a newline-separated list of glob patterns to exclude.

Inputs: server (required), name, panel, baseUrl, +4 more.

backup_deleteDelete a backupC

Delete a backup from the server.

Inputs: backup (required), server (required), panel, baseUrl, +2 more.

backup_download_urlGet a backup download URLB

Return a one-time signed URL to download a backup. Fetch it outside the model context.

Inputs: backup (required), server (required), panel, baseUrl, +2 more.

backup_getGet a backupC

Get details for one backup.

Inputs: backup (required), server (required), panel, baseUrl, +2 more.

backup_listList backupsC

List the server's backups.

Inputs: server (required), page, panel, baseUrl, +3 more.

backup_restoreRestore a backupB

Restore a backup to the server. truncate wipes existing files first.

Inputs: backup (required), server (required), panel, baseUrl, +3 more.

backup_toggle_lockToggle backup lockB

Lock or unlock a backup (locked backups cannot be deleted or rotated out).

Inputs: backup (required), server (required), panel, baseUrl, +2 more.

db_createCreate a databaseC

Create a new database on the server.

Inputs: server (required), database (required), panel, remote, +3 more.

db_deleteDelete a databaseC

Delete a database from the server.

Inputs: server (required), database (required), panel, baseUrl, +2 more.

db_listList databasesC

List the server's databases.

Inputs: server (required), panel, baseUrl, clientKey, +2 more.

db_rotate_passwordRotate database passwordC

Generate a new password for a database.

Inputs: server (required), database (required), panel, baseUrl, +2 more.

files_chmodChange file permissionsC

Set the mode (e.g. 644, 755) of a file under a root directory.

Inputs: server (required), file, mode, root, +5 more.

files_compressCompress filesC

Create an archive from one or more files/directories under a root.

Inputs: files (required), server (required), root, panel, +3 more.

files_copyCopy a fileC

Copy a file or directory. The copy is placed next to the original.

Inputs: server (required), location (required), panel, baseUrl, +2 more.

files_decompressDecompress an archiveC

Extract an archive file under a root directory.

Inputs: file (required), server (required), root, panel, +3 more.

files_deleteDelete filesC

Delete one or more files/directories under a root directory.

Inputs: files (required), server (required), root, panel, +3 more.

files_download_urlGet a file download URLB

Return a one-time signed URL to download a file (binary-safe). Fetch it outside the model context.

Inputs: file (required), server (required), panel, baseUrl, +2 more.

files_listList filesC

List files and directories at a path on the server.

Inputs: server (required), panel, baseUrl, clientKey, +2 more.

files_mkdirCreate a directoryC

Create a new folder under a root directory.

Inputs: name (required), server (required), root, panel, +3 more.

files_pullPull a remote fileC

Download a remote URL directly onto the server.

Inputs: url (required), server (required), panel, baseUrl, +6 more.

files_readRead file contentsA

Read the raw contents of a file. Use for text/config files; large or binary files are better downloaded.

Inputs: file (required), server (required), panel, baseUrl, +2 more.

files_renameRename or move a fileC

Rename or move a file/directory within the server. Paths are relative to root.

Inputs: server (required), to, from, root, +5 more.

files_upload_urlGet a file upload URLB

Return a one-time signed URL to upload files to the server. directory is appended to the signed URL, because Wings reads the target folder from it and the panel's own response ignores it.

Inputs: server (required), panel, baseUrl, clientKey, +2 more.

files_writeWrite file contentsB

Write raw content to a file, creating or overwriting it.

Inputs: file (required), server (required), content (required), panel, +3 more.

network_assignAssign an allocationB

Request a new allocation. With no ip/port the next available one is auto-assigned.

Inputs: server (required), ip, port, panel, +3 more.

network_deleteDelete an allocationC

Unassign an allocation from the server.

Inputs: server (required), allocation (required), panel, baseUrl, +2 more.

network_listList allocationsC

List the server's network allocations (IP/port assignments).

Inputs: server (required), panel, baseUrl, clientKey, +1 more.

network_set_notesSet allocation notesC

Update the notes on an allocation.

Inputs: notes (required), server (required), allocation (required), panel, +3 more.

network_set_primarySet primary allocationC

Mark an allocation as the server's primary.

Inputs: server (required), allocation (required), panel, baseUrl, +2 more.

panel_addAdd or update a panelA

Register a Pterodactyl panel by name with its base URL and API key(s). Persisted locally (chmod 600). Re-adding the same name updates it.

Inputs: name (required), baseUrl (required), test, clientKey, +3 more.

panel_listList panelsA

List registered panels. API keys are masked.

Inputs: no named parameters.

panel_removeRemove a panelC

Delete a registered panel by name.

Inputs: name (required).

panel_testTest panel credentialsB

Check which API keys work for a panel by making a lightweight request to each API.

Inputs: name.

panel_useSet active panelB

Set the active panel for this session. Tools called without an explicit panel arg use it.

Inputs: name (required).

permissions_listList permission keysA

List all available subuser permission keys (use with subuser_create).

Inputs: panel, baseUrl, clientKey, applicationKey.

schedule_createCreate a scheduleC

Create a schedule with a cron expression.

Inputs: hour (required), name (required), month (required), minute (required), +9 more.

schedule_deleteDelete a scheduleC

Delete a schedule and its tasks.

Inputs: server (required), schedule (required), panel, baseUrl, +2 more.

schedule_executeRun a schedule nowC

Trigger a schedule to run immediately.

Inputs: server (required), schedule (required), panel, baseUrl, +2 more.

schedule_getGet a scheduleC

Get one schedule and its tasks.

Inputs: server (required), schedule (required), panel, baseUrl, +2 more.

schedule_listList schedulesC

List the server's scheduled tasks.

Inputs: server (required), panel, baseUrl, clientKey, +1 more.

schedule_task_createAdd a task to a scheduleC

Add a task. action is command, power, or backup; payload is the command, power signal, or ignored globs.

Inputs: action (required), server (required), schedule (required), time_offset (required), +7 more.

schedule_task_deleteDelete a schedule taskC

Remove a task from a schedule.

Inputs: task (required), server (required), schedule (required), panel, +3 more.

schedule_task_updateUpdate a schedule taskD

Update a task within a schedule.

Inputs: task (required), action (required), server (required), schedule (required), +8 more.

schedule_updateUpdate a scheduleC

Update a schedule. Pterodactyl requires the full cron expression and name on update.

Inputs: hour (required), name (required), month (required), minute (required), +10 more.

server_activityServer activity logC

Get the server's activity log.

Inputs: server (required), page, sort, event, +6 more.

server_commandSend console commandC

Send a command to a running server's console. The server must be online.

Inputs: server (required), command (required), panel, baseUrl, +2 more.

server_console_tailTail server consoleA

Open the console WebSocket, replay recent output and collect live output for a few seconds, then return it as text. The server should be running.

Inputs: server (required), panel, baseUrl, seconds, +3 more.

server_docker_imageSet Docker imageB

Change the server's Docker image (must be one allowed by its egg).

Inputs: server (required), docker_image (required), panel, baseUrl, +2 more.

server_getGet server detailsB

Get details for one server by its short identifier or UUID.

Inputs: server (required), panel, baseUrl, clientKey, +1 more.

server_listList serversB

List servers the client API key can access on the selected panel.

Inputs: page, type, uuid, panel, +7 more.

server_powerSend power actionC

Send a power signal to a server: start, stop, restart, or kill.

Inputs: server (required), signal (required), panel, baseUrl, +2 more.

server_reinstallReinstall serverB

Trigger a server reinstall. This can wipe server files; use with care.

Inputs: server (required), panel, baseUrl, clientKey, +1 more.

server_renameRename serverC

Change the server's name and optionally its description.

Inputs: name (required), server (required), panel, baseUrl, +3 more.

server_resourcesGet server resource usageB

Current state and CPU / memory / disk / network usage for a server.

Inputs: server (required), panel, baseUrl, clientKey, +1 more.

server_set_variableSet startup variableC

Set the value of a startup environment variable.

Inputs: key (required), value (required), server (required), panel, +3 more.

server_startup_getGet startup configB

Get the server's startup command and configurable variables.

Inputs: server (required), panel, baseUrl, clientKey, +1 more.

subuser_createInvite a subuserB

Add a user to the server by email with a set of permission keys (see permissions_list).

Inputs: email (required), server (required), permissions (required), panel, +5 more.

subuser_deleteRemove a subuserC

Remove a user's access to the server.

Inputs: user (required), server (required), panel, baseUrl, +2 more.

subuser_getGet a subuserC

Get one subuser and their permissions.

Inputs: user (required), server (required), panel, baseUrl, +2 more.

subuser_listList subusersC

List users with access to the server.

Inputs: server (required), panel, baseUrl, clientKey, +1 more.

subuser_set_filesSet a subuser's file blocklistA

Set which files and directories a subuser may not touch, on panels carrying the sftp-permissions addon. This is a route of its own: the fields are read back by subuser_list but sending them to subuser_update does nothing. Patterns are gitignore syntax, matched by wings — '.jar' matches at any depth, a trailing slash means a directory, and '!' re-allows a path. Note that wings anchors every negation to the server root, so an exception has to name its full path: '!/plugins/AxVaults/messages.yml' works where '!/messages.yml' does not. A root admin bypasses the list entirely.

Inputs: user (required), server (required), denyfiles (required), hidefiles (required), +4 more.

subuser_updateUpdate subuser permissionsC

Replace a subuser's permission set.

Inputs: user (required), server (required), permissions (required), extra, +6 more.

Tool Schema Changelog

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

Loading tool schema changelog…

    TDQS

    C2.6/5.0

    Scored across 75 tools

    Disambiguation4/5

    Tools are generally cleanly separated by resource and action, and adjacent tools like subuser_update vs subuser_set_files are explicitly distinguished. A few pairs remain close enough to require description-checking (files_pull vs files_upload_url, backup_download_url vs files_download_url, panel_list vs panel_test), but most boundaries are clear.

    Naming Consistency4/5

    Names consistently use snake_case and a resource-prefixed pattern (backup_*, files_*, schedule_*, account_*). Minor deviations exist where the action is implicit or noun-like, such as server_resources, server_power, server_activity, and files_mkdir, but the convention remains readable and predictable.

    Tool Count1/5

    At 75 tools, this surface is far beyond a reasonable tool count for an agent-facing MCP server and creates a heavy selection burden. The broad Pterodactyl management scope justifies many operations, but not this many in a single toolset.

    Completeness4/5

    Coverage is extensive across files, backups, schedules, network allocations, subusers, panels, and account management, with full lifecycle operations for most resources. Minor gaps remain around server-level creation/deletion or transfer/admin operations, but core workflows have no dead ends.

    Maintenance

    ActivityMaintained
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      A
      quality
      D
      maintenance
      Enables managing Ploi.io servers, sites, databases, and Docker containers through the Ploi API, supporting both local stdio and remote Cloudflare Worker deployments with multi-tenant authentication.
      32
      ISC
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables AI agents to manage, configure, and operate game servers hosted on Pterodactyl panels, including power actions, console commands, file operations, plugin installation, and backups. It also supports Cloudflare challenge bypass and automatic request pacing for reliable panel automation.
      1
      MIT