backrest-mcp
This is a read-only MCP server for inspecting a Backrest (restic backup orchestrator) instance — checking health, configuration, snapshots, stats, operations, and logs — with write/destructive tools available only via explicit opt-in.
Check health —
get_healthreports whether Backrest is reachable and credentials are valid (ok/auth_failed/unreachable), with repo/plan counts when healthy; poll-safe.Read configuration —
get_configreturns a secret-free projection of repos, plans, policies, and auth (passwords, env values, hook tokens, flags are never exposed).Browse snapshots —
list_snapshotslists snapshots across all repos or filtered byrepo_id/plan_id;list_snapshot_filesbrowses files inside a snapshot at any path.Get dashboard stats —
get_summaryreturns 30-day per-repo and per-plan backup counts, bytes, snapshot totals, and next scheduled backup.Review operations —
get_operationslists recent backup operations (optionally filtered by plan/repo, with a limit) andget_logsfetches an operation's log output, tail-truncated to a byte cap.Download restored files —
get_download_urlprovides a signed URL for a file produced by a restore operation.Opt-in write tools (when
BACKREST_READONLY=false):trigger_backup,do_repo_task(index/prune/check/stats/unlock/forget),cancel_operation.Opt-in destructive tools (when
BACKREST_ALLOW_DESTRUCTIVE=true):forget_snapshot(requires aFORGET:<id>confirmation token) andrestore_snapshot(guarded to a realpath-validated staging prefix).Never exposed:
RunCommand,SetConfig,AddRepo,RemoveRepo,ClearHistory— and in this default read-only deployment only the 8 read tools above are registered.
Provides optional InfluxDB metrics integration, emitting tool call metrics (measurement 'backrest_tool' with 'tool' tag and 'duration_ms' field) to InfluxDB for monitoring.
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., "@backrest-mcp list my recent snapshots"
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.
backrest-mcp
MCP server for Backrest — a web UI and orchestrator for restic backups.
Python/FastMCP rewrite of backrest-mcp-server. Covers the full useful surface of the Backrest REST API with layered safety controls to protect backup data.
Tools
Tool | Description | Key params | Returns | Requires |
| Check reachability + credential health (poll-safe) | none |
| none |
| Read a secret-free projection of the Backrest configuration (see get_config output) | none |
| none |
| Each plan's paths, excludes, repo, schedule and retention (secret-free) | none |
| none |
| Which plans cover an absolute path, and which exclude pattern drops it (approximate restic matching) |
|
| none |
| Per plan: last good backup, age, latest status, stale / ok / unscheduled |
|
| none |
| List snapshots; no args → all repos merged |
|
| none |
| Browse files within a snapshot |
|
| none |
| 30-day dashboard stats per repo and plan | none | Per-repo and per-plan backup counts, bytes, snapshot totals, next backup time | none |
| Recent operation history with status icons + log refs |
|
| none |
| Read an operation's log output |
|
| none |
| Signed download URL for a restored file |
|
| none |
| Trigger a backup plan |
| Backrest's response |
|
| Run maintenance on a repo |
| Backrest's response |
|
| Cancel a running operation |
| Backrest's response |
|
| Permanently forget a snapshot |
| Backrest's response, or an error on a wrong token |
|
| Restore a snapshot to a staging path |
| Backrest's response, or an error on a refused prefix or target |
|
A failed call returns {"error": "tool call failed — check server logs for details"}
rather than raising; the detail goes to the server log only. ID arguments (repo_id,
plan_id, snapshot_id, operation_id, ref) must match ^[a-zA-Z0-9_.-]{1,256}$ and
are checked before Backrest is called.
Default state: read-only — only the 11 read tools are registered. No write calls are
possible without explicit opt-in. RunCommand, SetConfig, AddRepo, RemoveRepo, and
ClearHistory are intentionally never exposed.
For "is this path backed up?" use find_plan_for_path; for "is anything stale?" use
get_backup_freshness. Both read the same secret-free projection as get_config, so they
never see a repo password.
API field names target the deployed Backrest v1.13.0 connect-rpc API, which upstream
mainhas since diverged from. SeeCHANGELOG.md(0.3.0) for the reconciliation notes.
Related MCP server: Keepit MCP
get_config output
Backrest's GetConfig returns the restic repository password, env values and hook tokens
in cleartext. get_config does not pass that response through. It builds a new object from
named keys only (src/backrest_mcp/redact.py), so any field not listed below is dropped,
including a field a future Backrest version adds. list_plans, find_plan_for_path and
get_backup_freshness read the same projection.
Level | Fields returned |
Top level |
|
|
|
|
|
|
|
|
|
The nested policy messages have their own allowlists of v1.13.0 field names, so they are not copied whole either:
Message | Fields returned |
|
|
|
|
|
|
|
|
|
|
|
|
A scalar field is kept only if its value is a string, number or boolean.
Repo URI redaction:
user:password@userinfo is removed. This covers plain URLs and restic'sbackend:scheme://forms such asrest:https://…ands3:https://….A query string or fragment is replaced with
?[REDACTED].If the userinfo boundary is ambiguous, everything after
://becomes[REDACTED]. That happens when the text before the last@contains/,?or#: for example a password with an unencoded/, or an@in the path.A URI without
://that contains=, such as anrclone:backend with an inline connection string, is redacted after its backend prefix.Local paths and the short
sftp:user@host:/pathform are returned unchanged. Theuserthere is an SSH login name, not a secret.
Never returned:
repo passwords (only
hasPassword)env variable values (only the names, in
envKeys)restic
flagsand plan backup flags (only counts)hook commands, targets and tokens: webhook URLs, Gotify, Shoutrrr and Telegram credentials, and every other field of a hook action
user password hashes (
passwordBcrypt)the multihost
syncblock (instance identity, pairing secrets)any field not named in the tables above
Security note for users of versions before 0.4.1. Earlier versions returned Backrest's raw config, including each repo's restic password, env values and hook tokens. If you called
get_configon one of those versions, treat the repo password as disclosed to that session's transcript and to any LLM tracing that captured it.
Safety Controls
Backups are critical data. Five controls gate write and destructive operations:
1. Read-only mode (default: on)
BACKREST_READONLY=true # no write tools registered (default)
BACKREST_READONLY=false # enables trigger_backup, do_repo_task, cancel_operation2. Destructive gate (default: off)
BACKREST_ALLOW_DESTRUCTIVE=false # forget/restore never registered (default)
BACKREST_ALLOW_DESTRUCTIVE=true # enables forget_snapshot, restore_snapshot
# requires BACKREST_READONLY=false3. Forget confirmation token
forget_snapshot requires confirm=f"FORGET:{snapshot_id}". The caller must name the exact snapshot being deleted.
4. Restore path guard
restore_snapshot validates the target path against BACKREST_RESTORE_ALLOWED_PREFIX (default: ~/backrest-restore/) using os.path.realpath(). Path traversal attempts are blocked. The prefix itself must be a real directory (not a symlink) owned by the server user, with mode 0700; otherwise the restore is refused. Create it with mkdir -m 0700 ~/backrest-restore. After verifying restored files, move them manually.
5. Audit log
Set BACKREST_AUDIT_LOG=/path/to/audit.jsonl to log all write operations. Credential values are never included.
Configuration
Env var | Required | Default | Purpose |
| no |
| Backrest base URL |
| if Backrest auth is on | — | Basic Auth username |
| if Backrest auth is on | — | Basic Auth password |
| no |
| Disable all write tools |
| no |
| Enable forget/restore (requires |
| no |
| Restore target path guard (see above) |
| no | — | JSONL audit log for write ops |
| no |
|
|
| no |
| Bind host for http mode (non-loopback refused) |
| no |
| Bind port for http mode |
| in http mode | — | Bearer token (≥16 chars); the server refuses to start in http mode without it |
| no | unset |
|
| no |
| Logging verbosity |
| no | stderr | Log file path |
Telemetry variables (INFLUXDB_*, NATS_*) are listed under Observability.
Install
Requires Python 3.11+ and a reachable Backrest instance (the API targets v1.13.0).
python3 -m venv .venv
source .venv/bin/activate
pip install -e .Optional extras: .[influxdb] and .[nats] (see Observability). For a
long-lived deployment, install from the lock instead (see Deployment).
For development/testing, install the locked set CI uses:
uv sync --frozen --extra dev
uv run --frozen --no-sync pytest --cov=backrest_mcpThe live conformance tests run against a real Backrest. scripts/run_live_conformance.py
reads the BACKREST_* credentials it needs from the file named by BACKREST_LIVE_ENV_FILE (default
~/.secrets/forge.env) inside the process, so no credential is ever on a command line. Only
BACKREST_URL, BACKREST_USERNAME, BACKREST_PASSWORD and BACKREST_REPO_PASSWORD are
taken from that file; BACKREST_REPO_PASSWORD enables the check that get_config never
returns the repo password.
.venv/bin/python scripts/run_live_conformance.pyExit | Meaning |
0 | The live tests ran and passed |
1 | A live test failed or errored |
2 | The env file could not be read |
3 | Every test skipped, which is not a pass |
Deployment (PM2)
An ecosystem.config.js is included for PM2-managed deployment. It reads credentials from
~/.secrets/forge.env itself when PM2 loads it (PM2 6.x has no --env-file flag), so none
are stored in the config file:
cd /path/to/backrest-mcp
pm2 start ecosystem.config.jsInstall and update from the lock, so production runs the dependency set CI audits.
pip install -e . leaves already-installed dependencies where they are, however old:
cd /path/to/backrest-mcp
git pull
UV_PROJECT_ENVIRONMENT=.venv uv sync --frozen --extra dev # dev: the live runner uses pytest
.venv/bin/python -c "import backrest_mcp.server"
uv tool run --from "pip-audit==2.10.1" pip-audit --skip-editable \
--path "$(.venv/bin/python -c 'import sysconfig; print(sysconfig.get_path("purelib"))')"
pm2 restart backrest-mcpThe audit should report nothing except, possibly, pip itself: pip is venv tooling outside
uv.lock, not a dependency of the server.
The env file must contain BACKREST_USERNAME, BACKREST_PASSWORD, and (for http mode)
BACKREST_MCP_AUTH_TOKEN. Only those three keys are copied from it; any other setting,
including INFLUXDB_* and NATS_*, goes in the env block of ecosystem.config.js. That
block defaults safely (BACKREST_READONLY=true, BACKREST_ALLOW_DESTRUCTIVE=false).
Before the first start, edit the host-specific values in ecosystem.config.js: cwd (the
checkout), BACKREST_AUDIT_LOG and LOG_FILE. If you enable restore_snapshot, create the
restore prefix first: mkdir -m 0700 ~/backrest-restore.
HTTP transport
ecosystem.config.js defaults to BACKREST_MCP_TRANSPORT=http, running a long-lived
streamable-http service on 127.0.0.1:8626/mcp. HTTP mode fails closed:
binds loopback only (non-loopback bind refused unless
BACKREST_MCP_ALLOW_NONLOOPBACK=1);requires a
BACKREST_MCP_AUTH_TOKENbearer token of ≥16 chars (generate withpython3 -c "import secrets; print(secrets.token_hex(32))").
Clients authenticate with Authorization: Bearer <token>. Set BACKREST_MCP_TRANSPORT=stdio
(or unset it) to fall back to per-turn stdio via the backrest-mcp entry point.
scoped-mcp wiring
The PM2 process is a single shared instance in front of one Backrest. Register it in each
agent's scoped-mcp manifest as an HTTP server (type: http) at
http://127.0.0.1:8626/mcp, sending the BACKREST_MCP_AUTH_TOKEN value as the bearer
token. With the PM2 defaults only the 11 read tools are registered; the write and
destructive tools do not exist on the server, so no manifest can reach them.
Claude Desktop Config
{
"mcpServers": {
"backrest": {
"command": "/path/to/backrest-mcp/.venv/bin/python",
"args": ["-m", "backrest_mcp.server"],
"env": {
"BACKREST_URL": "http://localhost:9898",
"BACKREST_USERNAME": "your-username",
"BACKREST_PASSWORD": "your-password",
"BACKREST_READONLY": "true"
}
}
}
}Omit BACKREST_USERNAME and BACKREST_PASSWORD if Backrest auth is disabled.
TLS
If connecting to an HTTPS endpoint with a private or self-signed CA:
REQUESTS_CA_BUNDLE=/path/to/ca.crthttpx respects this env var. Do not disable TLS verification.
Observability
Structured JSON logs via structlog. LOG_LEVEL controls verbosity (default: INFO). Set
LOG_FILE to write to a file instead of stderr — exactly one sink is attached, so under
PM2 the same line is not also duplicated into error_file. If LOG_FILE cannot be created
the server falls back to stderr and says so on stderr rather than failing to start.
LOG_LEVEL applies to this server's own loggers. httpx, httpcore, mcp and nats are
held at WARNING regardless, so their wire trace cannot drown the server's own lines.
Metrics backends are optional extras. With the lock-based deploy, add them to the sync
(uv sync --frozen --extra dev --extra influxdb --extra nats); with pip, use
pip install -e ".[influxdb]" or ".[nats]".
Optional InfluxDB metrics (influxdb extra):
Env var | Purpose |
| InfluxDB write URL. Unset = disabled. |
| Auth token |
| Bucket/database (default: |
Optional NATS publishing (nats extra):
Env var | Purpose |
| NATS server URL. Unset = disabled. |
| Subject prefix (default: |
|
|
| Per-agent username and password. Set both, or neither. |
Userinfo in NATS_URL (nats://user:pass@host) also works. Setting only one of
NATS_USER / NATS_PASSWORD logs nats_auth_incomplete (variable names only) and connects
without credentials.
Each tool call emits a backrest_tool measurement with a tool tag and a duration_ms
field; list-style tools add count, and get_logs adds bytes. On NATS the message body is
JSON: {"measurement", "tags", "fields"}.
There is no OpenTelemetry tracing. An otel extra is declared in pyproject.toml, but the
server reads no OTEL_* variables.
Failure behaviour
Telemetry is best-effort and never fails a tool call, but it is not silent. An unset env var is the intended disabled state and logs nothing. A backend that is configured and failing warns exactly once per process and is then not retried:
Event | Meaning |
|
|
| The client built but a write failed — the usual symptom of a wrong or unreachable URL, since |
| Only one of |
|
|
| First NATS transport error, in place of nats-py's per-attempt ERROR reporting. |
| The connection succeeded but a publish failed. Publishes keep being attempted. |
The failure events carry the exception class only, never the URL or token — a NATS URL embeds its credentials.
NATS connects fail fast (allow_reconnect=False, two attempts, 2 s connect timeout, 5 s
overall deadline) so an unreachable broker delays a tool call by well under a second rather
than the ~120 s the library defaults produce.
Auth Architecture
Credentials flow: env vars → BackrestClient.__init__ → httpx Basic Auth tuple → Authorization header.
Credentials are never written to logs, audit entries, or MCP tool responses.
Available Tools
11 toolsfind_plan_for_pathA
Find which backup plans cover an absolute path, and whether an exclude drops it.
Inputs: path (required). Returns: object
get_backup_freshnessB
Report, per plan, when it last backed up successfully and whether that is stale.
Inputs: max_age_hours. Returns: object
get_configA
Read a secret-free view of the Backrest configuration (repos, plans, auth).
Returns an allowlist projection, not the raw config:
top level: modno, version, instance
repos: id, guid, uri (user:password@ and query removed; fully redacted if ambiguous), autoUnlock, autoInitialize, shared, originInstanceId, prune/check/forget policies, commandPrefix, envKeys (variable names only), hasPassword (bool), flagCount (int), hooks
plans: id, repo, paths, excludes, iexcludes, schedule, retention, skipIfUnchanged, backupFlagCount (int), hooks
hooks: conditions, onError, and action (the action type name only)
auth: disabled, and user names
Never included: repo passwords, env values, restic flags, hook commands and targets (webhook URLs, tokens), user password hashes, the multihost sync block (identity, pairing secrets), or any field not listed above.
Inputs: no named parameters. Returns: object
get_download_urlA
Get a signed download URL for a file produced by a restore operation.
Companion to restore_snapshot: after a restore, fetch a URL to download a specific restored file.
Inputs: file_path (required), operation_id (required). Returns: object
get_healthA
Check that Backrest is reachable and credentials are valid.
Wraps GetConfig — the call that returns 200 with valid credentials and 401 when they drift. Returns status "ok", "auth_failed", or "unreachable", plus the configured URL and a repo/plan count when healthy. Read-only; safe to poll.
Inputs: no named parameters. Returns: object
get_logsC
Fetch the log output for an operation.
Inputs: ref (required), max_bytes. Returns: object
get_operationsA
List recent backup operations, optionally filtered by plan or repo.
Inputs: limit, plan_id, repo_id. Returns: object
get_summaryA
Get the Backrest dashboard summary — 30-day stats per repo and plan.
Returns per-repo and per-plan success/warning/failed backup counts, bytes scanned/added, total snapshots, and the next scheduled backup time.
Inputs: no named parameters. Returns: object
list_plansA
List the backup plans: which paths each backs up, to which repo, and when.
Returns the same secret-free projection of each plan as get_config: id, repo, paths, excludes, iexcludes, schedule, retention, skipIfUnchanged, backupFlagCount and hooks (action type names only). Prefer this to get_config when you only need plans.
Inputs: no named parameters. Returns: object
list_snapshot_filesC
Browse files within a specific snapshot.
Inputs: repo_id (required), snapshot_id (required), path. Returns: object
list_snapshotsB
List snapshots in a Backrest repo, optionally filtered by repo or plan.
Inputs: plan_id, repo_id. Returns: object
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 11 tools
Each tool targets a distinct resource or question (health, dashboard stats, config, plans, snapshots, files, operations, logs, freshness, download URLs), and descriptions actively steer between near-duplicates like get_config vs list_plans. The main soft overlap is between get_summary, get_backup_freshness, and get_operations, which all touch backup recency/success and could be confused by an agent skimming names.
All tools follow a strict snake_case verb_noun pattern using a small, predictable verb set (get_, list_, find_). No camelCase mixing or vague one-word names.
11 tools is well within the ideal range and each covers a distinct inspection need within a backup orchestrator. No obviously redundant or filler tools; the surface is scoped to read/inspect operations.
The read-only inspection surface is decent (health, config, plans, snapshots, files, operations, logs, freshness), but there are no action tools: no trigger backup, restore, plan/repo create-update, or prune/check/forget. get_download_url explicitly describes itself as a companion to restore_snapshot, a tool that does not exist here, creating a dead end for that workflow.
Maintenance
Related MCP Connectors
Hosted remote MCP for protected account access, permissions, activity history and supported undo.
MCP server for mandates, delegation, policy-gated execution, credential grants, and audit.
Governed MCP gateway: one endpoint for your tools, with credential custody and audit log.
Guarded MCP server for agent-readable business truth, provenance, readiness, and discovery.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceAn MCP server that enables AI assistants to manage restic backups, including listing snapshots, browsing files, and creating new backups. It provides tools for repository maintenance, data restoration, and applying retention policies through the Model Context Protocol.2-

Keepit MCPofficial
AlicenseNot gradedqualityBmaintenanceMCP server for interacting with Keepit backup and data protection services. Enables monitoring, management, and security operations through natural language.5MIT- AlicenseNot gradedqualityDmaintenanceEnterprise-grade MCP server for Kubernetes operations, supporting local kubeconfig and AWS EKS authentication, with read, write, and destructive operations protected by multi-layer safety guards.MIT
- AlicenseNot gradedqualityBmaintenanceA typed MCP server for curated backup administration of DBackup via its API, exposing tools for backup jobs, execution history, notifications, storage, and bounded restore workflows.MIT