Read-only by default
Write tools aren't registered until you start the server in another mode. The mode is an env var and changes only on restart, so the agent can't promote itself.
CAPROVER_MCP_MODE
better-caprover-mcp is an unofficial MCP server that lets Claude, Cursor and Codex deploy and manage apps on a self-hosted CapRover. It starts read-only: write tools aren't registered until you raise the mode, and deletes need a single-use token.
Read 7
get_overviewlist_appsget_appget_app_runtimeget_app_logsget_build_logslist_one_click_appsChange apps 6
create_appdeploy_imageset_env_varsscale_appadd_custom_domainenable_sslDestructive 1
delete_appWrite tools aren't registered. The model can't call what it never sees.
A CapRover password is full access. Asking the model to be careful is a hope. Here the server enforces it before anything reaches CapRover.
Write tools aren't registered until you start the server in another mode. The mode is an env var and changes only on restart, so the agent can't promote itself.
CAPROVER_MCP_MODE
Any change accepts a dry run. You get what would happen, and no write call goes to CapRover.
dry_run
delete_app first returns a preview and a single-use token. It lasts 5 minutes and is tied to that exact call.
delete_app
Env var values are never returned, only whether they're set. The password is masked in logs and errors, and log lines show [REDACTED].
isSet · [REDACTED]
The first delete_app call deletes nothing. The agent has to bring you the preview, get your answer, and call again with the token.
→ delete_app staging-old→ delete_app staging-old · user_confirmed · token→ delete_app · same token again→ set_env_vars api · LOG_LEVEL=debug · dry_run→ set_env_vars api · LOG_LEVEL=debugThere is no raw-request tool, on purpose. Each operation has its own schema and risk level, and the mode decides which ones exist.
registered from readonly
get_overviewCapRover version, root domain, app count, and what this server can do.
Available from readonlylist_appsEvery app on the server.
Available from readonlyget_appDetails for one app.
Available from readonlyget_app_runtimeLive state of an app. Needs a CapRover version with that endpoint; 1.15.5 doesn't have it.
Available from readonlyget_app_logsLast lines of the running app. Secrets come back as [REDACTED].
Available from readonlyget_build_logsLast lines of the latest build, with the same redaction.
Available from readonlylist_one_click_appsThe one-click templates you can install.
Available from readonlyregistered from operate
create_appCreate an empty app.
Available from operatedeploy_imageDeploy a Docker image, in the background.
Available from operateset_env_varsSet and remove variables from KEY=value lines. The rest are kept.
Available from operatescale_appSet the instance count. 0 stops the app.
Available from operateadd_custom_domainAttach a custom domain to an app.
Available from operateenable_sslTurn on HTTPS for a domain.
Available from operateregistered in admin only
delete_appRemove an app, and its volumes only if you ask. Needs a confirmation token.
Available from adminCritical operations need one more switch: CAPROVER_MCP_ALLOW_CRITICAL=1 in admin mode. None of the 14 is classified as critical yet.
Start in readonly. Ask which apps run a latest tag. Raise the mode when you need writes.
claude mcp add caprover \ -e CAPROVER_URL=https://captain.your-domain.com \ -e CAPROVER_PASSWORD=your-password \ -- npx -y better-caprover-mcp
{
"mcpServers": {
"caprover": {
"command": "npx",
"args": ["-y", "better-caprover-mcp"],
"env": {
"CAPROVER_URL": "https://captain.your-domain.com",
"CAPROVER_PASSWORD": "your-password",
"CAPROVER_MCP_MODE": "readonly"
}
}
}
}
{
"mcpServers": {
"caprover": {
"command": "docker",
"args": ["run", "-i", "--rm",
"-e", "CAPROVER_URL",
"-e", "CAPROVER_PASSWORD",
"-e", "CAPROVER_MCP_MODE",
"ghcr.io/guilhermebkel/better-caprover-mcp:latest"],
"env": {
"CAPROVER_URL": "https://captain.your-domain.com",
"CAPROVER_PASSWORD": "your-password",
"CAPROVER_MCP_MODE": "readonly"
}
}
}
}
| Variable | Default | What it does |
|---|---|---|
| CAPROVER_URL | none | CapRover address with http:// or https://. Only the origin is used. |
| CAPROVER_PASSWORD | none | The CapRover password. |
| CAPROVER_MCP_MODE | readonly | readonly, operate or admin. Changes only when the server restarts. |
| CAPROVER_MCP_ALLOW_CRITICAL | off | Set to 1 to unlock critical operations in admin mode. |
Is this operation registered in the current mode?
Arguments are validated against the operation's schema.
A dry run, or a confirmation token for deletes.
One adapter makes the API call.
Secrets are masked before the answer leaves.
The only network traffic goes to your CAPROVER_URL. There is no telemetry.
The server doesn't run commands on your machine or read files. It only reads environment variables.
TypeScript on Node. One class per operation, each with its schema, risk level and description, and a single manifest feeds every interface and the policy.
The official caprover-api SDK is experimental, so only one adapter imports it. Integration tests run against a real, disposable CapRover.
No. It's unofficial and has no affiliation with CapRover.
No. The mode comes from an env var read when the server starts. Changing it means restarting the server, and the agent has no tool for that.
A raw request would walk around the mode, preview and redaction layers. The project records this decision as ADR 0003.
Not yet. Servers with two-factor authentication aren't supported (ADR 0010).
It needs a CapRover version that exposes that endpoint. CapRover 1.15.5 doesn't have it.
Raise the mode when you trust it. The install is one command.