duplicati-mcp
# Duplicati MCP Server
MCP (Model Context Protocol) server for managing Duplicati backups from an LLM.
[Version française / French version](README_fr.md)
## Architecture
The server wraps the Duplicati REST API and exposes it via the MCP protocol. Two transports are supported:
- **stdio** — for local use via Claude Code (no network, no port)
- **Streamable HTTP** — for Docker deployment, accessible over the network
## Getting Started
### Local use with Claude Code (stdio)
The simplest way to get started. The `.mcp.json` at the project root handles everything:
```bash
# Install uv if needed
brew install uv
# Claude Code will auto-detect .mcp.json and launch the server
```
Set your Duplicati URL and password in `.mcp.json`:
```json
{
"mcpServers": {
"duplicati": {
"type": "stdio",
"command": "uv",
"args": ["run", "duplicati-mcp"],
"env": {
"DUPLICATI_URL": "http://localhost:8200",
"DUPLICATI_PASSWORD": "your-password",
"DUPLICATI_READONLY": ""
}
}
}
}
```
### With Docker Compose (Docker Hub image)
```bash
# Edit DUPLICATI_URL and DUPLICATI_PASSWORD in docker-compose.yml, then:
docker compose up -d
```
### With Docker Compose (local build)
```bash
# Edit docker-compose.yml: comment out `image:` and uncomment `build: .`
docker compose up -d --build
```
### Direct Docker usage
```bash
docker run -d \
--name duplicati-mcp-server \
-p 3000:3000 \
-e DUPLICATI_URL=http://your-duplicati-host:8200 \
-e DUPLICATI_PASSWORD=your-password \
kcofoni/duplicati-mcp:latest
```
### Verification
```bash
# Check that the server is running
docker logs duplicati-mcp-server
# Test the MCP endpoint
curl -X POST http://localhost:3000/mcp \
-H "Content-Type: application/json" \
-d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}'
```
## Client Configuration
### Claude Code — local (stdio)
For local use without Docker, add to your project `.mcp.json`:
```json
{
"mcpServers": {
"duplicati": {
"type": "stdio",
"command": "uv",
"args": ["run", "duplicati-mcp"],
"env": {
"DUPLICATI_URL": "http://localhost:8200",
"DUPLICATI_READONLY": ""
}
}
}
}
```
Credentials are loaded from the `.env` file at the project root (see [Getting Started](#getting-started)).
### Claude Code — Docker/remote (HTTP)
Add to your `.mcp.json`:
```json
{
"mcpServers": {
"duplicati": {
"type": "http",
"url": "http://your-host:3000/mcp"
}
}
}
```
### Claude Desktop
Claude Desktop requires `mcp-proxy` as a bridge to HTTP servers. Add to your configuration file:
**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"duplicati": {
"command": "uvx",
"args": ["mcp-proxy", "--transport", "streamablehttp", "http://your-host:3000/mcp"]
}
}
}
```
## Available Tools
Once connected, the LLM has access to:
### Backup Jobs
1. **list_backups** — List all configured jobs with ID, name, last run date and result
2. **get_backup** — Get detailed information about a specific job
3. **run_backup** — Trigger a backup job immediately
4. **abort_backup** — Abort the currently running backup for a job
### Status & Progress
5. **get_progress** — Live progress of the active backup task (phase, %, file counts)
6. **get_server_status** — Duplicati server state, version and active task
### Configuration
7. **export_backup_config** — Export a job configuration as JSON
8. **update_backup_config** — Update an existing job configuration in place (use with `export_backup_config` to modify sources, settings, schedule, etc.)
9. **import_backup_config** — Import a job configuration from JSON (creates a new job)
### History & Diagnostics (SQLite — requires `DUPLICATI_DB_PATH`)
10. **db_get_backup_metadata** — Rich metadata from the local database: last run date, duration, file counts, quota usage, last error
11. **db_get_backup_schedule** — Schedule configuration for a backup job
12. **db_list_errors** — Recent error log entries, optionally filtered by job
13. **db_list_notifications** — System notifications (update alerts, etc.)
14. **db_get_backup_options** — Configuration options for a job (compression, retention policy, etc.) — passphrases excluded
15. **db_list_operations** — Operation history for a job (Backup, Restore, List, etc.) with timestamps
16. **db_get_operation_log** — Full result and statistics for a specific operation
17. **db_list_filesets** — Available restore points (backup versions) for a job
## Example Prompts
Once the server is connected to your LLM, here are prompts you can use:
**General status**
- "What backup jobs are configured on my Duplicati?"
- "What was the last backup that ran and what was the result?"
- "Is a backup currently running?"
**History & statistics** _(requires `DUPLICATI_DB_PATH`)_
- "Show me the last 10 operations for backup job 2"
- "What is the average duration of recent backups?"
- "Have there been any errors on my backups in the past few weeks?"
- "How many files are backed up and what is the total size on the destination?"
**Restore points** _(requires `DUPLICATI_DB_PATH`)_
- "What restore points are available for my backup job?"
- "What is the oldest backup available for a restore?"
**Configuration** _(requires `DUPLICATI_DB_PATH`)_
- "What retention policy is configured on my backup job?"
- "What compression and encryption options are in use?"
**Diagnostics** _(requires `DUPLICATI_DB_PATH`)_
- "Are there any pending system notifications on Duplicati?"
- "Has my Duplicati encountered any errors recently? Which ones?"
- "Analyse the last backup and tell me if everything went well"
**Open-ended** _(combines multiple tools)_
- "Give me a full health report on my Duplicati backups"
## Environment Variables
| Variable | Default | Description |
|---|---|---|
| `DUPLICATI_URL` | `http://localhost:8200` | URL of the Duplicati instance |
| `DUPLICATI_PASSWORD` | _(empty)_ | Duplicati web interface password (leave empty if none set) |
| `DUPLICATI_READONLY` | _(empty)_ | Set to `true`, `1` or `yes` to disable write operations |
| `DUPLICATI_DB_PATH` | _(empty)_ | Path to `Duplicati-server.sqlite` — enables SQLite-backed history tools |
| `MCP_TRANSPORT` | `stdio` | Transport: `stdio` or `streamable-http` |
| `MCP_PORT` | `3000` | Port for Streamable HTTP transport |
### Read-only Mode
`DUPLICATI_READONLY=true` disables `run_backup`, `abort_backup`, `update_backup_config` and `import_backup_config`. All read tools remain active. Useful for safely exploring and analysing backup configurations without any risk of modification.
### SQLite Access
Setting `DUPLICATI_DB_PATH` enables the `db_*` tools, which read directly from the Duplicati SQLite databases. Access is strictly read-only: databases are opened in read-only mode and copied to memory via the SQLite Online Backup API before any query — the live Duplicati databases are never locked or modified.
**Local use** — point to the server database on your machine:
```
DUPLICATI_DB_PATH=/path/to/duplicati/config/Duplicati-server.sqlite
```
**Docker** — share the Duplicati config directory as a read-only volume. In `docker-compose.yml`:
```yaml
services:
duplicati-mcp:
# ...
volumes:
- duplicati_config:/duplicati-config:ro # named volume (recommended)
# or: - /srv/duplicati/config:/duplicati-config:ro # bind mount
environment:
- DUPLICATI_DB_PATH=/duplicati-config/Duplicati-server.sqlite
volumes:
duplicati_config: # must be the same volume used by the Duplicati container
```
## Docker Hub
- **Repository**: [kcofoni/duplicati-mcp](https://hub.docker.com/r/kcofoni/duplicati-mcp)
- **Latest tag**: `kcofoni/duplicati-mcp:latest`
```bash
docker pull kcofoni/duplicati-mcp:latest
```
## Development
### File Structure
```
duplicati-mcp/
├── src/
│ └── duplicati_mcp/
│ ├── __init__.py
│ ├── __main__.py
│ ├── client.py # Duplicati REST API client
│ ├── db.py # Read-only SQLite access (server DB + per-backup DBs)
│ └── server.py # FastMCP server and tools
├── mcp-publication/ # MCP registry publication files
├── requirements.txt # Python dependencies
├── pyproject.toml # Project metadata
├── Dockerfile
├── docker-compose.yml
├── .mcp.json # Claude Code local config (stdio)
├── test_server.sh # Docker container smoke test
├── test_mcp.py # MCP protocol test
├── README.md # This file (English)
└── README_fr.md # French documentation
```
### Running Tests
```bash
# Smoke test (requires running Docker container)
./test_server.sh
# MCP protocol test (requires running server)
python test_mcp.py
python test_mcp.py localhost:3000
```
### Interactive Tool Testing (local)
```bash
uv run mcp dev src/duplicati_mcp/server.py
```
## Troubleshooting
### Cannot connect to Duplicati
Check that `DUPLICATI_URL` is reachable from the container. If both run in Docker, put them on the same network and use the service name as hostname.
### Authentication failed
Verify `DUPLICATI_PASSWORD` matches the password set in Duplicati's web interface. Leave empty if no password is configured.
### MCP endpoint not responding
```bash
docker ps | grep duplicati-mcp-server
docker logs duplicati-mcp-server
```
## License
This project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.
TDQS
Scored across 17 tools
Each tool has a clear and distinct purpose. The db_* tools are differentiated by the specific data they retrieve (metadata, options, schedule, logs, etc.), and actions like list_backups, run_backup, abort_backup are unambiguous. No two tools overlap significantly.
All tools use a consistent verb_noun pattern in snake_case. Database-specific tools are prefixed with 'db_', and other tools follow a similar style (e.g., 'list_backups', 'run_backup', 'get_progress'). No mixing of conventions.
17 tools is slightly above the typical 'sweet spot' of 3-15, but each tool addresses a specific need for managing Duplicati backups. The count is not excessive and serves the domain well.
The tool set covers core operations like listing, running, aborting, and configuring backups, but lacks direct restore and delete functionality. While import/export cover configuration migration, creating a new backup from scratch is only possible via import, not a dedicated 'create' tool.