aapanel-mcp
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., "@aapanel-mcp show me all the websites on my aaPanel and their SSL status"
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.
aapanel-mcp
An MCP server that gives AI CLI agents full control of an aaPanel (the btPanel fork) hosting panel over its HTTP API.
The panel speaks a signature-based API that no generic HTTP MCP client can use: authentication is a per-request MD5 signature rather than a header, and the caller is expected to keep a session cookie across calls. This server implements that protocol once, correctly, and exposes it as 57 described panel operations plus 2 meta tools and 3 resources.
Why the tools are not generic
There is deliberately no "call any panel endpoint" tool. A model that can only choose from individually described operations cannot invent a destructive call it was never shown, and every argument is validated against a schema before the request leaves the process.
Related MCP server: Plesk MCP Server
Install
With npx, no install step
npx aapanel-mcpPoint it at a panel and it will negotiate MCP over stdio on stdin/stdout, which is what a CLI agent launches as a subprocess.
As a dependency
npm install -g aapanel-mcp
# or, per project:
npm install aapanel-mcpThe aapanel-mcp binary is the server. Requires Node 20.10 or newer.
From source
git clone https://github.com/devochkaskustikom/aapanel-mcp.git
cd aapanel-mcp
npm install
npm run buildConfigure the panel
Two things must be true in the aaPanel UI before any client can connect:
Settings → API Interface → Modify — enable the API and generate a key.
Add your client's IP to the whitelist. This is not optional. A request from an address that is not on the list is refused by the panel regardless of how correct the signature is. If you run the agent on the same machine as the panel, that is
127.0.0.1.
Point the server at the panel and give it the key:
export AAPANEL_PANEL_URL="https://your-panel.example.com:8888"
export AAPANEL_API_KEY="your-api-interface-key"The key in your message is a real credential. Rotate it in the panel UI, and prefer delivering it through the environment or a secret manager rather than committing a config file.
Configuration
Environment variables win over the config file, which wins over defaults. Copy
aapanel.config.example.json to aapanel.config.json (project root) or
~/.aapanel-mcp.json for a persistent setup.
Setting | Env var | Default | Meaning |
Panel URL |
|
| Must include the port. |
API key |
| — | Required. |
Read-only |
|
| Refuses every state-changing tool. |
Timeout |
|
| Per-request timeout. |
Self-signed TLS |
|
| Accept an unverifiable panel certificate. |
Dangerous ops |
|
| Unlocks root credentials and raw file access. |
Config path |
| — | Override the config file location. |
Safety model
The server starts read-only. Two independent gates protect the panel:
readOnly(default on) refuses everywriteoperation. The refusal tells the agent to show the user the parameters it would have sent, rather than silently failing.allowDangerous(default off) is a second, harder gate over the five operations that can expose or replace credentials:Tool
Why it is gated
danger_mysql_root_passwordReads the MySQL root password from panel config.
danger_mysql_reset_root_passwordReplaces it, breaking every existing root login.
danger_read_fileReads any file the panel user can read.
danger_write_fileWrites any such file, bypassing all site-tool validation.
danger_update_panelReplaces the panel itself.
Generated credentials are redacted on the way out. When site_create returns a
panel-generated FTP or database password, the value in the tool result is
replaced with ***redacted*** — including inside nested objects and arrays. Ask
the user to read the password from the panel UI instead of relying on the
transcript.
Wire to your agent
ZCode / Claude Code / Cursor (stdio)
Installed globally, the binary is on PATH:
{
"mcpServers": {
"aapanel": {
"command": "aapanel-mcp",
"env": {
"AAPANEL_PANEL_URL": "https://your-panel.example.com:8888",
"AAPANEL_API_KEY": "your-api-interface-key",
"AAPANEL_READ_ONLY": "true"
}
}
}
}Installed per project, point command at your node and the build output:
{
"mcpServers": {
"aapanel": {
"command": "node",
"args": ["/absolute/path/to/node_modules/aapanel-mcp/dist/src/index.js"],
"env": {
"AAPANEL_PANEL_URL": "https://your-panel.example.com:8888",
"AAPANEL_API_KEY": "your-api-interface-key",
"AAPANEL_READ_ONLY": "true"
}
}
}
}Either way, the panel is contacted over HTTP from wherever the agent runs, so that host's IP must be on the panel's whitelist.
Set AAPANEL_READ_ONLY to "false" only once you trust the agent with
production changes. When you do, keep AAPANEL_ALLOW_DANGEROUS at "false".
Harness
Harness drives an agent loop that shells out to tools. Give the loop this server as an MCP endpoint and let it connect over stdio. Two Harness-specific notes:
Harness agents are good at composing steps but bad at remembering that a destructive call needs a numeric id. The
aapanel_capabilitiestool is cheap to call and returns every operation with its current availability, so let the agent call it first when the task is open-ended.Long panel operations (backups, panel updates) are asynchronous. The panel exposes
panel_install_task_count; instruct the agent to poll it rather than assuming an operation finished when the call returned.
Tools
aapanel_capabilities returns this list at runtime, along with which
operations the current mode actually permits.
Panel and system — aapanel_status, aapanel_capabilities,
panel_system_total, panel_disk_info, panel_network_status,
panel_install_task_count, panel_check_update, panel_mysql_status
Websites (read) — site_list, site_get, site_types, site_list_domains,
site_get_root, site_php_versions, site_php_version, site_rewrite_templates,
site_get_rewrite, site_get_config, site_get_ssl, site_dir_userini,
site_delete_check, site_list_backups
Websites (write) — site_create, site_delete, site_start, site_stop,
site_add_domain, site_remove_domain, site_set_php_version,
site_set_run_path, site_set_dir_userini, site_set_rewrite, site_set_index,
site_backup
Databases (read) — db_list, db_tables, db_access_get, db_backups,
db_recycle_bin, db_delete_check
Databases (write) — db_create, db_set_password, db_set_access,
db_backup, db_delete, db_optimize_table, db_repair_table,
db_sync_from_server, db_restore, db_import_sql
SSL — ssl_list, ssl_upload, ssl_deploy, ssl_disable
Dangerous — the five tools in the safety table above.
Resources
Reading an inventory as a resource is often cheaper than a tool call:
URI | Contents |
| OS, panel version, CPU, memory, disks, live network. |
| One site record, listed by |
| All MySQL databases. |
How the protocol works
request_time = unix timestamp in seconds
request_token = md5(str(request_time) + md5(api_key))Both are sent as ordinary form fields on every POST, alongside the action parameters. The session cookie returned by the panel is held in memory and replayed on subsequent requests, as the panel's own demo does.
aaPanel has two API generations and they answer differently. v1 returns the
payload directly; v2 wraps it in {status, timestamp, message} where status: 0
means success. The server detects the envelope by shape and unwraps it, so tool
handlers and resources always see the payload. A non-zero status is raised as
an error carrying the panel's own message.
Development
npm run build # compile to dist/
npm run typecheck # types only, no emit
npm test # build, then run unit + end-to-end tests
npm run dev # run from source via tsxThe test suite covers the signature algorithm against a hand-computed MD5, the
v1/v2 envelope handling, secret redaction, parameter shaping for the endpoints
whose wire format differs from their natural shape, and a full MCP session
(initialize, tools/list, tool calls, read-only refusal, resource read)
against an in-process fake panel that validates every signature.
Adding an operation
Add one entry to OPERATIONS in src/operations.ts. It needs a route, an
action, a zod params shape, and a risk. Anything not marked read is
gated automatically, so a new operation is safe by default. Use query for
parameters the panel reads from the URL, and mapParams when the panel's
parameter name differs from the one an agent would guess.
Available Tools
59 toolsaapanel_capabilitiesList available operationsARead-onlyIdempotent
Every operation this server exposes, with its risk level. Use it to discover what is possible and which operations are currently blocked by the server mode.
Inputs: no named parameters.
aapanel_statusConnection and mode statusARead-onlyIdempotent
Report the panel address, whether the connection works, the panel version, and which modes are active (read-only, dangerous operations). Safe to call at any time; it reveals no secrets.
Inputs: no named parameters.
danger_mysql_reset_root_passwordReset the MySQL root passwordADestructive
Set a new MySQL root password. Every existing root login, cron job and monitoring agent that used the old password will stop working.
Inputs: password (required).
danger_mysql_root_passwordGet or reset the MySQL root passwordADestructive
Read the MySQL root password, or set a new one when password is supplied. This is the highest-privilege credential on the box: the server refuses to expose it unless AAPANEL_ALLOW_DANGEROUS is set.
Inputs: id, key, table.
danger_read_fileRead an arbitrary panel fileADestructive
Read any file readable by the panel user, including /www/server/panel/config.json and database files. Refused unless AAPANEL_ALLOW_DANGEROUS is set.
Inputs: path (required).
danger_update_panelUpdate the panel itselfADestructive
Install a panel update. Refused unless AAPANEL_ALLOW_DANGEROUS is set.
Inputs: force.
danger_write_fileWrite an arbitrary panel fileADestructive
Write any file the panel user can write, including vhost and nginx configs. This bypasses every validation in the site tools, so the server refuses it unless AAPANEL_ALLOW_DANGEROUS is set.
Inputs: data (required), path (required), encoding.
db_access_getDatabase access rulesCRead-onlyIdempotent
Hosts a database user is allowed to connect from, plus its SSL mode.
Inputs: name (required).
db_backupBack up a databaseB
Start a database backup. The result lands in the panel backup directory.
Inputs: id (required).
db_backupsList database backupsCRead-onlyIdempotent
Backup files recorded for a database, newest first.
Inputs: search (required), p, type, limit.
db_createCreate a databaseB
Create a MySQL database and user. Pass 127.0.0.1 as the access host unless the app connects from another machine, in which case pass that machine ip or % for any host.
Inputs: name (required), db_user (required), password (required), ps, +7 more.
db_deleteDelete a databaseADestructive
Delete a database. The panel moves it to the recycle bin rather than dropping it immediately, but treat it as destructive and confirm with db_delete_check first.
Inputs: id (required), name (required).
db_delete_checkPreview a database deletionCRead-onlyIdempotent
The record the panel would remove, so a deletion can be confirmed against the right database.
Inputs: id (required).
db_import_sqlImport a SQL dumpA
Import a .sql file that already exists on the panel host into a database. The file must be on the panel machine, not uploaded by this server.
Inputs: file (required), name (required).
db_listList databasesBRead-onlyIdempotent
All MySQL databases known to the panel, with user, access host and size.
Inputs: p, limit, search.
db_optimize_tableOptimize tablesC
Run OPTIMIZE TABLE on one or more tables of a database.
Inputs: tables (required), db_name (required).
db_recycle_binDatabase recycle binARead-onlyIdempotent
Databases that were deleted and can still be restored. Use db_delete_check first: the panel keeps them recoverable.
Inputs: no named parameters.
db_repair_tableRepair tablesA
Run REPAIR TABLE on one or more tables of a database, for recovering from a crash.
Inputs: tables (required), db_name (required).
db_restoreRestore a database from recycle binA
Restore a deleted database using the rname shown by db_recycle_bin.
Inputs: path (required).
db_set_accessSet database accessC
Change which hosts a database user may connect from.
Inputs: name (required), access (required), ssl, dataAccess.
db_set_passwordChange database passwordA
Set a new password for an existing database user. Update the application config in the same change, or the app will lose the database.
Inputs: id (required), password (required), name.
db_sync_from_serverImport server databases into the panelA
Pull databases that exist in MySQL but are not tracked by the panel into the panel inventory. Safe and non-destructive to existing records.
Inputs: sid.
db_tablesTables in a databaseARead-onlyIdempotent
Table names, engines, row counts and total size for a database. Use this to confirm a schema landed before pointing an app at it.
Inputs: db_name (required).
panel_check_updateCheck for panel updateCRead-onlyIdempotent
Report whether a newer panel release is available. Read-only when called without force.
Inputs: check.
panel_disk_infoDisk partitionsARead-onlyIdempotent
Capacity and inode usage for every mounted partition. Use before any operation that writes large files, uploads a certificate, or imports a database dump.
Inputs: no named parameters.
panel_install_task_countPending install tasksARead-onlyIdempotent
Number of install/compile tasks still running. Poll this after asking the panel to install software instead of guessing when a long operation finished.
Inputs: no named parameters.
panel_mysql_statusMySQL service statusARead-onlyIdempotent
Installed MySQL version and whether the service is running.
Inputs: no named parameters.
panel_network_statusLive network and loadBRead-onlyIdempotent
Realtime CPU, memory, load average and cumulative network traffic counters.
Inputs: no named parameters.
panel_system_totalSystem totalsARead-onlyIdempotent
Panel version, OS, CPU cores, CPU usage and physical memory totals. Use this first to confirm connectivity and see what the box looks like.
Inputs: no named parameters.
site_add_domainAdd a domainA
Bind an extra domain to an existing site. Newline-separated values add several at once. The site name must also be added to DNS.
Inputs: id (required), domain (required), webname (required).
site_backupBack up a websiteA
Start a site backup. Poll panel_install_task_count or site_backups to see when it finishes.
Inputs: id (required).
site_createCreate a websiteA
Create a PHP site, optionally with an FTP account and a MySQL database in one call. The panel generates passwords; the response returns them once, so capture them for the user rather than logging them.
Inputs: path (required), version (required), webname (required), ps, +13 more.
site_deleteDelete a websiteADestructive
Delete a site. Run site_delete_check first and show the user what would be lost. The panel keeps a recycle bin for some resources, but do not rely on it.
Inputs: id (required), webname (required).
site_delete_checkPreview a site deletionARead-onlyIdempotent
What a site deletion would take with it: associated domains, databases, FTP accounts and root directory. Always call this before site_delete so the user can see the blast radius.
Inputs: id (required).
site_dir_useriniAnti-cross-site settingsCRead-onlyIdempotent
The .user.ini anti-cross-site protection flag, access-log flag and the current run directory of a site.
Inputs: id (required), path (required).
site_getGet one websiteARead-onlyIdempotent
Fetch a single site record by id. Cheaper and more reliable than paging the whole list when the id is already known.
Inputs: id (required).
site_get_configRead vhost configBRead-onlyIdempotent
Raw nginx or apache vhost file for a site. Useful for debugging a 502 or a rewrite that is not taking effect.
Inputs: path (required).
site_get_rewriteRead a rewrite templateARead-onlyIdempotent
Contents of one rewrite template, so a rule can be reviewed before it is applied to a live site.
Inputs: path (required).
site_get_rootWebsite root pathBRead-onlyIdempotent
Absolute root directory of a site, without listing every site.
Inputs: id (required), key, table.
site_get_sslSSL status of a siteBRead-onlyIdempotent
Whether SSL is deployed for a site, plus certificate subject and expiry when present.
Inputs: siteName (required).
site_listList websitesARead-onlyIdempotent
All PHP sites with id, domain, root path, remark, expiry and backup count. This is the entry point for any site operation, since most actions need a numeric site id.
Inputs: p, type, limit, search.
site_list_backupsList website backupsBRead-onlyIdempotent
Backup records for a site, newest first.
Inputs: search (required), p, type, limit.
site_list_domainsList domains of a siteARead-onlyIdempotent
Every domain bound to a site, including the port each one answers on.
Inputs: id (required).
site_php_versionPHP version of a siteBRead-onlyIdempotent
Which PHP version a specific site currently runs.
Inputs: siteName (required).
site_php_versionsInstalled PHP versionsARead-onlyIdempotent
Every PHP version installed on the panel, with the "00" pseudo-version meaning pure static. Pass one of these versions when creating a site.
Inputs: no named parameters.
site_remove_domainRemove a domainADestructive
Unbind one domain from a site, leaving the site itself intact.
Inputs: id (required), domain (required), webname (required), port.
site_rewrite_templatesRewrite templatesBRead-onlyIdempotent
Named rewrite rule templates shipped with the panel (wordpress, laravel5, thinkphp, ...).
Inputs: siteName (required).
site_set_dir_useriniToggle anti-cross-site protectionC
Toggle the .user.ini cross-site protection for a site.
Inputs: id (required), path (required).
site_set_indexSet default documentsB
Change which filenames nginx treats as directory indexes, comma separated.
Inputs: id (required), Index (required).
site_set_php_versionChange PHP versionA
Switch a site to another installed PHP version. Extensions available in one version may be missing in another, so verify afterwards.
Inputs: version (required), siteName (required).
site_set_rewriteApply a rewrite ruleA
Write the rewrite config for a site and reload nginx. Overwrites the current rule, so read the existing one first when changing something live.
Inputs: data (required), path (required), encoding.
site_set_run_pathSet run directoryA
Change the directory nginx resolves requests against, for apps whose entry point lives in a subdirectory such as /public. The directory must already exist inside the site root.
Inputs: id (required), runPath (required).
site_startStart a websiteA
Bring a stopped site back online.
Inputs: id (required), name (required).
site_stopStop a websiteB
Take a site offline without deleting it.
Inputs: id (required), name (required).
site_typesSite groupsBRead-onlyIdempotent
Available site groups/classification ids, with id 0 being the default group.
Inputs: no named parameters.
ssl_deployDeploy a certificate to sitesA
Bind a stored certificate to one or more sites, replacing their current SSL configuration.
Inputs: hash (required), domains (required).
ssl_disableDisable SSL on a siteBDestructive
Remove the SSL configuration from a site, returning it to plain HTTP.
Inputs: siteName (required), updateOf.
ssl_listList stored certificatesARead-onlyIdempotent
All SSL certificates uploaded to the panel, with the hash needed to deploy one to a site.
Inputs: p, limit.
ssl_uploadUpload a certificateA
Store a PEM certificate and private key in the panel. Returns the hash used by ssl_deploy.
Inputs: key (required), cert (required).
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 59 tools
Most tools target clearly distinct resources and actions across sites, databases, SSL, panel status, and dangerous operations. However, danger_mysql_root_password and danger_mysql_reset_root_password overlap in setting the MySQL root password, and aapanel_status partially overlaps panel_system_total and panel_check_update, creating minor ambiguity.
Tool names consistently use snake_case with predictable domain prefixes such as site_, db_, ssl_, panel_, danger_, and aapanel_. The few prefix choices are intentional and readable, so an agent can reliably infer the tool family from the name.
59 tools is far above the practical range for an MCP server and exceeds the 25+ threshold for being too many. Although aaPanel is a broad administration surface, many granular read-only status tools could be consolidated without losing functionality.
The surface covers most core lifecycle operations for sites, databases, SSL, panel status, and dangerous operations, including delete checks, backups, restores, and imports. Some adjacent aaPanel areas are missing, such as standalone FTP account management, cron jobs, firewall, DNS management, and a generic site update operation.
Maintenance
Related MCP Connectors
29 DNS, SEO, SSL, security, WHOIS & mail tools for AI agents. Pay per call (x402) or card API key.
Manage Vozora VPS servers, SSH keys, firewalls, DNS and usage from an AI agent.
Backend for AI agents: one batched tool over ~668 actions (hosting, storage, auth, payments).
Backend platform for AI agents: one agentstack.execute tool runs batched steps over +700 actions (hosting, storage, auth, payments, CRM, app builder).
Related MCP Servers
- AlicenseCqualityDmaintenanceEnables AI agents to manage server infrastructure through the 1Panel API, including Docker containers, databases, and system monitoring. It provides tools for website management, file operations, and application deployment via natural language commands.159 npmMIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to manage Plesk hosting environments through a set of standardized tools for security, health monitoring, DNS, email, backups, and service management.MIT
- AlicenseNot gradedqualityDmaintenanceProvides 50 tools to manage a CloudPanel VPS through AI assistants, covering sites, databases, Docker, server software, firewall, DNS, and one-shot deployments.30 npm4MIT
- AlicenseCqualityCmaintenanceEnables AI clients to drive the full Remnawave panel API, exposing one tool per method+path operation (users, nodes, hosts, subscriptions, inbound, bulk actions) plus search, describe, status, audit and metrics helpers. Read-only/read-write gating, deny rules, confirm-preview and dry-run, response secret redaction and an audit journal keep mutations controlled.2229 npmMIT