Skip to main content
Glama

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-mcp

Point 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-mcp

The 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 build

Configure the panel

Two things must be true in the aaPanel UI before any client can connect:

  1. Settings → API Interface → Modify — enable the API and generate a key.

  2. 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

AAPANEL_PANEL_URL

http://127.0.0.1:8888

Must include the port.

API key

AAPANEL_API_KEY

—

Required.

Read-only

AAPANEL_READ_ONLY

true

Refuses every state-changing tool.

Timeout

AAPANEL_TIMEOUT_MS

60000

Per-request timeout.

Self-signed TLS

AAPANEL_ALLOW_SELF_SIGNED

false

Accept an unverifiable panel certificate.

Dangerous ops

AAPANEL_ALLOW_DANGEROUS

false

Unlocks root credentials and raw file access.

Config path

AAPANEL_CONFIG

—

Override the config file location.

Safety model

The server starts read-only. Two independent gates protect the panel:

  • readOnly (default on) refuses every write operation. 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_password

    Reads the MySQL root password from panel config.

    danger_mysql_reset_root_password

    Replaces it, breaking every existing root login.

    danger_read_file

    Reads any file the panel user can read.

    danger_write_file

    Writes any such file, bypassing all site-tool validation.

    danger_update_panel

    Replaces 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_capabilities tool 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

aapanel://panel/overview

OS, panel version, CPU, memory, disks, live network.

aapanel://sites/{id}

One site record, listed by resources/list.

aapanel://databases

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 tsx

The 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 tools
aapanel_capabilitiesList available operationsA
Read-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 statusA
Read-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 passwordA
Destructive

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 passwordA
Destructive

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 fileA
Destructive

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 itselfA
Destructive

Install a panel update. Refused unless AAPANEL_ALLOW_DANGEROUS is set.

Inputs: force.

danger_write_fileWrite an arbitrary panel fileA
Destructive

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 rulesC
Read-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 backupsC
Read-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 databaseA
Destructive

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 deletionC
Read-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 databasesB
Read-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 binA
Read-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 databaseA
Read-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 updateC
Read-onlyIdempotent

Report whether a newer panel release is available. Read-only when called without force.

Inputs: check.

panel_disk_infoDisk partitionsA
Read-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 tasksA
Read-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 statusA
Read-onlyIdempotent

Installed MySQL version and whether the service is running.

Inputs: no named parameters.

panel_network_statusLive network and loadB
Read-onlyIdempotent

Realtime CPU, memory, load average and cumulative network traffic counters.

Inputs: no named parameters.

panel_system_totalSystem totalsA
Read-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 websiteA
Destructive

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 deletionA
Read-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 settingsC
Read-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 websiteA
Read-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 configB
Read-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 templateA
Read-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 pathB
Read-onlyIdempotent

Absolute root directory of a site, without listing every site.

Inputs: id (required), key, table.

site_get_sslSSL status of a siteB
Read-onlyIdempotent

Whether SSL is deployed for a site, plus certificate subject and expiry when present.

Inputs: siteName (required).

site_listList websitesA
Read-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 backupsB
Read-onlyIdempotent

Backup records for a site, newest first.

Inputs: search (required), p, type, limit.

site_list_domainsList domains of a siteA
Read-onlyIdempotent

Every domain bound to a site, including the port each one answers on.

Inputs: id (required).

site_php_versionPHP version of a siteB
Read-onlyIdempotent

Which PHP version a specific site currently runs.

Inputs: siteName (required).

site_php_versionsInstalled PHP versionsA
Read-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 domainA
Destructive

Unbind one domain from a site, leaving the site itself intact.

Inputs: id (required), domain (required), webname (required), port.

site_rewrite_templatesRewrite templatesB
Read-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 groupsB
Read-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 siteB
Destructive

Remove the SSL configuration from a site, returning it to plain HTTP.

Inputs: siteName (required), updateOf.

ssl_listList stored certificatesA
Read-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

    B3.4/5.0

    Scored across 59 tools

    Disambiguation4/5

    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.

    Naming Consistency5/5

    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.

    Tool Count2/5

    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.

    Completeness4/5

    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

    ActivityNo data
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      C
      quality
      D
      maintenance
      Enables 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.
      15
      9 npm
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Enables AI agents to manage Plesk hosting environments through a set of standardized tools for security, health monitoring, DNS, email, backups, and service management.
      MIT
    • A
      license
      Not graded
      quality
      D
      maintenance
      Provides 50 tools to manage a CloudPanel VPS through AI assistants, covering sites, databases, Docker, server software, firewall, DNS, and one-shot deployments.
      30 npm
      4
      MIT
    • A
      license
      C
      quality
      C
      maintenance
      Enables 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.
      222
      9 npm
      MIT