Pufferfish-MCP
Pufferfish-MCP
An MCP server for controlling Coral game panels — Coral is the panel software also known as "Pufferfish" — power, console commands, files, backups, SFTP, and server listing. Multi-panel aware — tools resolve servers by name across every panel you've added.
Coral is not Pterodactyl. This project shares an architecture (and some code shape) with Pterodactyl-MCP, but it is not a fork wired up to the same API — Coral's client API (/api/v2/client/...) is a different, incompatible surface from Pterodactyl's. Endpoint paths, response shapes, and available actions all differ; don't assume anything documented for Pterodactyl-MCP applies here.
⚠️ Not yet verified against a live panel. This server was written against Coral's published swagger spec only — it has not been built and run end-to-end against a real Coral instance. Expect API-shape mismatches once you try it for real, especially around
list_filesandlist_backupsresponse field names, which could not be fully confirmed from the spec alone. Treat the first real run as a debugging session.
Setup
1. Build (Node 22+):
npm install
npm run buildThis produces dist/server.js (the MCP server entry point) and dist/cli.js (the pufferfish-mcp CLI).
2. Get a Client API key. Log into your Coral panel account and look for an API keys page under your account settings (the exact path isn't confirmed — check your panel's account settings for an "API keys" page). Create a key there; it acts as you, scoped to whatever servers your account can see. Repeat per panel if you use more than one.
3. Register the MCP server with your panel(s) as environment variables. This is the primary, recommended way to configure panels — no CLI flags or files to manage. Each panel is declared with two env vars: PUFFERFISH_<ALIAS>_URL and PUFFERFISH_<ALIAS>_KEY, where <ALIAS> is whatever short name you want to refer to that panel by (e.g. PROD, SURVIVAL).
Using the Claude Code CLI:
claude mcp add --scope user pufferfish -e PUFFERFISH_PROD_URL=https://panel.example.com -e PUFFERFISH_PROD_KEY=XXXX -e PUFFERFISH_DEFAULT_PANEL=prod -- node /path/to/Pufferfish-MCP/dist/server.jsOr the equivalent raw JSON, if you're editing the MCP settings file directly:
{
"mcpServers": {
"pufferfish": {
"command": "node",
"args": ["/path/to/Pufferfish-MCP/dist/server.js"],
"env": {
"PUFFERFISH_PROD_URL": "https://panel.example.com",
"PUFFERFISH_PROD_KEY": "XXXX",
"PUFFERFISH_DEFAULT_PANEL": "prod"
}
}
}
}Add more panels by repeating the pattern with a different alias, e.g. PUFFERFISH_SURVIVAL_URL / PUFFERFISH_SURVIVAL_KEY. Aliases are lowercased automatically and must otherwise look like [a-z0-9][a-z0-9_-]*.
Plus one server-wide variable: PUFFERFISH_DEFAULT_PANEL sets which panel alias tools use when they omit panel and more than one panel is configured. If exactly one panel is configured, it's used automatically even without a default set.
4. Verify:
node dist/cli.js doctorChecks each configured panel: authenticates against the client API and lists visible servers, and prints whether each panel's config came from environment variables or the config-file fallback (see below). Pass an alias (doctor prod) to check just one panel. Exits with status 1 if any panel fails.
Optional: config-file fallback
If you'd rather not put keys in your MCP settings, add-panel writes panels to a local config file instead (~/.pufferfish-mcp/config.json by default, override with PUFFERFISH_MCP_CONFIG):
node dist/cli.js add-panel prod --url https://panel.example.com --client-key XXXX --defaultEnv vars and the config file can be used together — for any given panel alias, env vars win on a per-field basis. The config file is created with restrictive permissions (owner-only, via chmod 0600 on Unix or icacls on Windows).
MCP tools
Tool | Description |
| List configured Coral panels: alias, base URL, whether a client key is set, and which panel is the default. Never prints the actual key value. |
| Lists servers visible to the configured key(s). With no panel given, searches every configured panel. |
| Gets live resource utilization (CPU, memory, disk, network, uptime) for a server. |
| Sends a power action ( |
| Sends a console command to a running server. Fire-and-forget — no output capture. |
| Lists files and directories at a path on a server. |
| Reads a file's contents from a server. Large files are truncated. |
| Overwrites a file's contents on a server. Destructive — requires |
| Lists backups for a server. |
| Creates a new backup for a server (optional |
| Uploads/downloads a file or directory (recursively) over SFTP. Use for large files or bulk transfers; |
| One-time SFTP setup for a panel: generates and registers an ed25519 SSH key ( |
All server-targeting tools accept a server argument — "alias:name-or-id", a full UUID, a UUID-short identifier, or a unique (case-insensitive, substring-matched) server name — plus an optional panel argument to restrict/select which panel to search.
SFTP
A server's SFTP address is a separate, node-level address reported by GET /server/{id} as
sftp_ip/sftp_port (e.g. <node-name>.<panel-host>:2022) — it is not the same as the
server's public game address (confirmed against a live panel: the game address was a
<host>:25017-style address, while SFTP was on a completely different host and port). sftp_transfer
fetches this per-server before connecting.
Run sftp_setup once per panel (via the MCP tool, or generate/register a key any way you like) to
get credentials in place, then sftp_transfer works immediately. Host keys are trusted on first use
and pinned to ~/.pufferfish-mcp/known_hosts.json — a later mismatch refuses the connection rather
than silently accepting a different key.
node dist/cli.js set-password <alias> stores an account password as an SFTP fallback (never used
for panel API auth) if you'd rather not use a generated key.
Notes
Auth is API-key only — no panel passwords are used to talk to the panel API; a password is only ever an SFTP fallback.
write_filerefuses to run withoutconfirm: true.Server references resolve by name across all configured panels when
panelis omitted; an ambiguous match lists the candidates so you can disambiguate or prefix withpanel:.The SFTP username is assumed to be
<panel-account-username>.<uuid_short>, matching Pterodactyl's convention — this is not confirmed against a real Coral panel and may need adjusting insrc/sftp.ts(connectClient) once tested.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/BSpoones/Pufferfish-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server