ClusterControl MCP
The ClusterControl MCP Server is a bridge between your AI assistant and your databases. You type what you need in plain English or other languages, and it figures out the rest. No dashboards to click through, no commands to memorize. It works with AI tools like Claude Desktop, Claude Code, and OpenAI Codex, and supports 72 actions and counting, covering backups, cluster management, user accounts, and performance monitoring. It works with MySQL, MariaDB, PostgreSQL, MongoDB, SQL Server, and TimescaleDB.
How It Works
The diagram below shows how everything connects. Your AI tool sits at the top. When you type a request, it goes through the MCP Server, which translates it into the right action and passes it to the CMON Controller. The controller then talks to whichever database cluster you are working with.
Before you get started, make sure you have the following in place:
- A running ClusterControl installation with CMON Controller accessible over the network (CMON controller reachable on port 9501)
- A CMON user account with access to the clusters you want to query
- An MCP-compatible AI client such as Claude Desktop, Claude Code, or OpenAI Codex
Once you have confirmed all the requirements above are in place, you are ready to install and configure the ClusterControl MCP Server. Packages are published to the Severalnines repository alongside other ClusterControl components.
The binary installs to /usr/bin/cmon-mcp. A systemd service unit and default configuration file are also installed:
/etc/systemd/system/cmon-mcp.service: service unit/etc/default/cmon-mcp: environment file for credentials and transport options
Tool Annotations
Every tool the MCP Server exposes advertises the standard MCP annotations readOnlyHint and destructiveHint alongside its name and description. Of the 72 tools, 43 are pure reads, 26 change state on the CMON Controller, and 3 write files on the local filesystem of the MCP Server host; 22 tools carry destructiveHint: true. The annotations are generated at tool registration from a committed, human-reviewed manifest, so the hints a client sees cannot drift from what was reviewed.
MCP clients can use these annotations to auto-approve read-only tools and to require explicit confirmation before state-changing or destructive ones. Keep in mind that annotations are advisory metadata for the client: the server does not enforce them, and the dry-run preview for write operations is likewise a client-side safeguard, not server-side enforcement.
If you need the server itself to refuse an action rather than rely on the client, see Access Control below.
Configuration
The ClusterControl MCP Server is configured through the /etc/default/cmon-mcp file on your CMON host. Open the file and edit the values to match your environment:
Configuration Parameters
CMON Controller Connection
| Parameter | Description | Example |
|---|---|---|
CMON_ENDPOINT |
The URL of your CMON Controller API | https://127.0.0.1:9501 |
CMON_USERNAME |
The ClusterControl username | admin |
CMON_PASSWORD |
Password for the user (leave empty if using key auth) | severalNINES999 |
CMON_KEY_FILE |
Path to RSA private key (alternative to password) | /etc/clustercontrol/id_rsa |
You can authenticate using either a password or an RSA key file, not both at the same time. If CMON_PASSWORD is set, leave CMON_KEY_FILE empty, and vice versa.
The CMON user you specify here is the identity the MCP Server uses for every action it performs. We recommend creating a dedicated CMON user with only the privileges your team actually needs and please avoid reusing your main admin account.
MCP Server
| Parameter | Description | Example |
|---|---|---|
MCP_BIND_ADDRESS |
Address and port the MCP Server listens on | 0.0.0.0:3000 |
MCP_BASE_URL |
Public URL that AI clients use to connect | http://your-cc-host:3000 |
MCP_AUTH_TOKEN |
Bearer token to secure all incoming connections | your-strong-random-token |
For MCP_BIND_ADDRESS, use 127.0.0.1:3000 if you only need local access, or 0.0.0.0:3000 to allow remote AI clients to connect.
MCP Transport Endpoints
The MCP Server exposes two transports on the same port:
/sse and /message is SSE transport, used by Claude Desktop and Claude Code. /mcp is Streamable HTTP transport, used by OpenAI Codex
Access Control
These settings are enforced by the server, not by the AI client. Unlike tool annotations and
dry_run previews, a refusal here cannot be overridden by the client.
| Parameter | Description | Example |
|---|---|---|
MCP_READ_ONLY |
Refuses all 29 state-changing tools for the lifetime of the process | 1 |
MCP_TOOL_ALLOW |
Comma-separated list of the only tools to expose | list_clusters,list_alarms |
MCP_TOOL_DENY |
Comma-separated list of tools to refuse; wins over MCP_TOOL_ALLOW |
create_job,restore_backup |
Read-only mode both hides the write tools from the client's tool list and refuses a direct call on one, so a client that calls a tool it was never shown is still refused. Scoping works the same way, and the resource surfaces follow their tools automatically — a surface is served only when every tool it maps to is in scope.
A name that matches no tool stops the server
An unknown entry in either list is a startup error naming every offender, and the service exits non-zero. This is deliberate: a silently ignored deny entry would leave a tool you meant to remove fully exposed.
Prefer MCP_TOOL_ALLOW when the requirement is only these
A deny list names what to remove, so a tool added in a later release is exposed by default. An allow list names what to keep, so a new tool is out of scope until you add it.
Read the startup warnings. Scoping is by tool name, and a tool name is not a data class.
Several tools read the same data from the CMON Controller, so denying one can leave a sibling serving
the same rows. The server names every such case at startup as tool scope: WARNING: …. If you denied
a tool for a security reason, that line tells you whether you actually removed the data.
One case deserves singling out: create_job takes a free-form command, which reaches CMON job
commands that have no tool of their own and that no deny list can name — including drop_cluster,
remove_node and failover. If create_job is in scope, treat the assistant as able to run any
CMON job.
Auditing
| Parameter | Description | Example |
|---|---|---|
MCP_AUDIT_LOG |
Path to the JSONL audit log; off disables auditing |
/var/log/cmon-mcp/audit.jsonl |
MCP_DIGEST_HMAC_KEY_FILE |
Key file the argument digests are computed under | /etc/cmon-mcp/digest.key |
Every tool call and resource read is recorded twice — an intent record before the action runs
and a completion record after, correlated by call_id. Background tasks add a third, acceptance,
correlated by task_id. Two records rather than one, because a single record written at the end
cannot be told apart from an action that never happened, and the actions that matter most are the
ones that did not return.
Raw arguments are never written. What is recorded is a keyed digest of them, so that someone who can read the log cannot work backwards to a low-entropy argument such as a password.
A fresh install is audited by default; an upgrade changes nothing
A first install provisions /etc/cmon-mcp/digest.key and /etc/cmon-mcp/governed.env, and that
second file switches auditing on — so a newly installed host records from its first call. An
upgrade enables nothing, because a host that has never been audited has no key, and a server
that is told to audit without one refuses to start. To turn auditing off on a fresh install, set
MCP_AUDIT_LOG=off in /etc/default/cmon-mcp, which is read after the package's file and wins.
Auditing is fail-closed
If the intent record cannot be written, the call is refused with AUDIT_UNAVAILABLE and the
action never runs. This is the intended behaviour: an unauditable server does not act.
It also means the log's permissions matter. The server refuses any log file whose mode is wider
than 0600, on every record, so a rotation policy that recreated it world-readable would refuse
every later call. The shipped /etc/logrotate.d/cmon-mcp already handles this correctly — do not
loosen its create 0600 root root line.
To find failed actions you need both fields, because they mean different things:
outcome covers transport and task-level failure; tool_is_error covers a tool that ran and
returned an error. The absence of tool_is_error is not evidence that the tool succeeded.
File Exports
| Parameter | Description | Example |
|---|---|---|
MCP_EXPORT_DIR |
The one directory local file writes are confined to; off refuses them all |
/srv/cc-exports |
Three tools write to the MCP Server host's own filesystem: download_error_report,
export_cluster_log and unpack_error_report. Each takes a destination path from the client, and
the service runs as root, so without a boundary, granting an assistant export_cluster_log alone is
not meaningfully different from granting it root write access to the host. Every path the client
supplies is resolved inside this directory and may not leave it.
The default is /var/lib/cmon-mcp/exports, created at mode 0700 on start.
This can change behaviour on an existing host
The boundary is on by default, so a server whose configuration you never touched will begin
refusing paths such as output_path=/tmp/report.tar.gz that previously worked. Point
MCP_EXPORT_DIR at the directory those callers already use to keep their existing paths valid.
The boundary is only as strong as the directory's own permissions. If it is a symlink, group- or
world-writable, or owned by another user, the server says so at startup as export dir: WARNING: …
rather than refusing — a link onto a larger volume is a legitimate thing to want.
Documentation Search
| Parameter | Description | Example |
|---|---|---|
MCP_DOCS_DIR |
Installed ClusterControl documentation bundle used by search_docs |
/usr/share/cmon-mcp/docs |
The package ships a documentation bundle and the search_docs tool answers from it locally, with no
network calls, so it works in an air-gapped installation. The bundle is read once at startup; if it
cannot be loaded, only search_docs is disabled and the reason is written to the journal, leaving
every other tool working. Restart the service after repairing or upgrading it.
Complete Configuration Example
The following shows the ClusterControl MCP Server example configuration after it has been set up through the /etc/default/cmon-mcp file on your CMON host.
# CMON Controller connection
CMON_ENDPOINT=https://127.0.0.1:9501
CMON_USERNAME=admin
CMON_PASSWORD='severalNINES999'
# RSA key auth alternative (leave CMON_PASSWORD empty if using this):
# CMON_KEY_FILE=/etc/clustercontrol/id_rsa
# MCP Server
MCP_BIND_ADDRESS=0.0.0.0:3000
MCP_BASE_URL=http://your-cc-host:3000
MCP_AUTH_TOKEN=
# Access control — enforced by the server, not the AI client.
# Start here if you are connecting an assistant to a production controller.
MCP_READ_ONLY=1
# MCP_TOOL_ALLOW=list_clusters,get_cluster,list_alarms,search_docs
# MCP_TOOL_DENY=create_job
# Auditing — set automatically on a fresh install; shown here for reference.
# MCP_AUDIT_LOG=/var/log/cmon-mcp/audit.jsonl
# MCP_DIGEST_HMAC_KEY_FILE=/etc/cmon-mcp/digest.key
# File exports — defaults to /var/lib/cmon-mcp/exports. Set this if callers
# already rely on a different directory.
# MCP_EXPORT_DIR=/srv/cc-exports
Start read-only
MCP_READ_ONLY=1 is the setting to reach for first when pointing an assistant at a production
controller. All 43 read tools keep working, so the assistant can still investigate, explain and
report — it simply cannot change anything. Turn it off deliberately, once you know which write
actions you actually want to allow.
Generating a Secure Token
It is strongly recommended to protect your MCP Server with a bearer token, especially when MCP_BIND_ADDRESS is set to 0.0.0.0. Generate one with:
Copy the output and set it as the value of MCP_AUTH_TOKEN.
Starting the Service
Save the configuration file, then restart the service:
Confirm it started successfully:
You should see output confirming the MCP Server is running and listening on the address defined in MCP_BIND_ADDRESS.
Connecting to AI Clients
Once the MCP Server is running, you need to register it with your AI client. The steps differ slightly depending on which client you use.
Claude Desktop
Open your Claude Desktop configuration file:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%APPDATA%\Claude\claude_desktop_config.json
Add the following entry under mcpServers so that it looks like this :
{
"mcpServers": {
"clustercontrol": {
"type": "sse",
"url": "http://your-cc-host:3000/sse",
"headers": {
"Authorization": "Bearer your-auth-token"
}
}
}
}
Alternatively, you can use mcp-remote with Node.js installed on your environment with the following JSON configuration:
{
"mcpServers": {
"clustercontrol": {
"command": "npx",
"args": [
"mcp-remote",
"http://your-cc-host:3000/sse",
"--allow-http",
"--header",
"Authorization: Bearer your-auth-token"
]
}
}
}
Save the file and restart Claude Desktop. You should see clustercontrol appear in the File → Settings → developer → Local MCP servers panel like this after restart Claude Desktop.
Claude Code
Run the following command in your terminal:
claude mcp add clustercontrol -- cmon-mcp \
-endpoint https://your-cc-host:9501 \
-username admin \
-password your-password
To verify it was added:
OpenAI Codex
Add the MCP Server to your Codex tool configuration using the /mcp endpoint:
{
"tools": [
{
"type": "mcp",
"server_label": "clustercontrol",
"server_url": "http://your-cc-host:3000/mcp",
"headers": {
"Authorization": "Bearer your-auth-token"
},
"require_approval": "never"
}
]
}
Verifying the Connection
Once connected, ask your AI assistant the following to confirm everything is working:
If the setup is correct, it will return the list of clusters managed by your ClusterControl instance.


