A read-only MCP server for BorgBackup operational status.
borg-mcp lets AI agents (Claude, and other MCP clients) answer questions like "is my backup fresh?", "how big is the repo?", "what would prune remove?" — without any ability to modify or destroy backups.
It is a companion project to borg, born from borg#9955. It is intentionally not part of borg core: the safety boundary for untrusted AI agents lives in this small, auditable project.
Status: pre-alpha, under development. Requires borg2 (no borg 1.x support).
The MCP client (the agent) is treated as untrusted input — it may be prompt-injected or simply wrong. Therefore:
- Command allowlist, not passthrough. Only a fixed set of borg subcommands with fixed argument templates is ever executed. No agent-supplied flags, no shell.
- Repository allowlist. Repositories are configured server-side with
aliases; the agent refers to
"home", never to a raw path or URL. - No secrets over MCP. Passphrases come from configured passcommands on the server side and never appear in tool results or logs.
- Sanitized, size-capped output. Raw file listings are off by default (explicit config opt-in); all listings are paginated. borg's stderr is sanitized before an error reaches the agent: tracebacks are withheld (logged server-side instead), the passcommand line is redacted, and control characters are stripped.
- Read-only by construction — and by enforcement. borg-mcp never runs
prune/delete/compact/repair/restore. For defense in depth, run it against
repositories accessed via an SSH key that is restricted server-side to
read-only
borg serve, and run borg-mcp itself as an unprivileged user. - Audit log. Every tool invocation is logged.
Never in scope: executing destructive operations, key export, passphrase handling over MCP, arbitrary borg commands.
- Python >= 3.11
- borg2, installed from the
master branch (borg-mcp drives the
borgCLI; it does not import borg internals)
There is no PyPI release; install from git:
pip install git+https://github.com/borgbackup/borg-mcp.git
or from a checkout: pip install .
TOML, at ~/.config/borg-mcp/config.toml (or /etc/borg-mcp.toml).
The config file holds all security-relevant settings and must not be
writable by the agent's account — there are deliberately no CLI overrides.
[server]
allow_file_listing = false # raw archive contents listing, off by default
timeout = 300
max_items = 1000 # pagination cap for listings
[repos.home]
location = "ssh://backup@host/./home"
description = "workstation home dirs, nightly"
passcommand = "cat /path/to/passphrase-file"The passcommand must read the passphrase from somewhere safe: a file only
readable by the borg-mcp user, or a keyring/secret-service CLI. Never put
the passphrase inline (as in passcommand = "echo secret"): the command
line is visible in ps output while it runs.
borg-mcp serve [--config PATH] # run the stdio MCP server
borg-mcp check [--config PATH] [ALIAS ...]
# validate config; with aliases, test
# repository access
MCP client configuration (e.g. Claude Code .mcp.json):
{
"mcpServers": {
"borg": {
"command": "borg-mcp",
"args": ["serve", "--config", "/path/to/config.toml"]
}
}
}| tool | answers |
|---|---|
list_repositories |
which repositories can I ask about? |
repo_info |
repository ID, size, encryption mode |
list_archives |
which archives exist? (paginated, filterable) |
archive_info |
stats, duration, hostname for one archive |
latest_archive |
is my backup fresh? |
prune_preview |
what would a prune with these keep rules remove? |
prune_preview never deletes anything: --dry-run is part of the command
template and cannot be influenced by the client, and the test suite asserts
that every prune command borg-mcp can construct contains it.
These tools exist only when allow_file_listing = true, because they
disclose the names of the backed up files:
| tool | answers |
|---|---|
list_archive_contents |
which files are in this archive? |
diff_archives |
which files changed between two archives? |