{
  "markdown": "# Duplicati MCP Server\n\nMCP (Model Context Protocol) server for managing Duplicati backups from an LLM.\n\n[Version française / French version](README_fr.md)\n\n## Architecture\n\nThe server wraps the Duplicati REST API and exposes it via the MCP protocol. Two transports are supported:\n\n- **stdio** — for local use via Claude Code (no network, no port)\n- **Streamable HTTP** — for Docker deployment, accessible over the network\n\n## Getting Started\n\n### Local use with Claude Code (stdio)\n\nThe simplest way to get started. The `.mcp.json` at the project root handles everything:\n\n```bash\n# Install uv if needed\nbrew install uv\n\n# Claude Code will auto-detect .mcp.json and launch the server\n```\n\nSet your Duplicati URL and password in `.mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"duplicati\": {\n      \"type\": \"stdio\",\n      \"command\": \"uv\",\n      \"args\": [\"run\", \"duplicati-mcp\"],\n      \"env\": {\n        \"DUPLICATI_URL\": \"http://localhost:8200\",\n        \"DUPLICATI_PASSWORD\": \"your-password\",\n        \"DUPLICATI_READONLY\": \"\"\n      }\n    }\n  }\n}\n```\n\n### With Docker Compose (Docker Hub image)\n\n```bash\n# Edit DUPLICATI_URL and DUPLICATI_PASSWORD in docker-compose.yml, then:\ndocker compose up -d\n```\n\n### With Docker Compose (local build)\n\n```bash\n# Edit docker-compose.yml: comment out `image:` and uncomment `build: .`\ndocker compose up -d --build\n```\n\n### Direct Docker usage\n\n```bash\ndocker run -d \\\n  --name duplicati-mcp-server \\\n  -p 3000:3000 \\\n  -e DUPLICATI_URL=http://your-duplicati-host:8200 \\\n  -e DUPLICATI_PASSWORD=your-password \\\n  kcofoni/duplicati-mcp:latest\n```\n\n### Verification\n\n```bash\n# Check that the server is running\ndocker logs duplicati-mcp-server\n\n# Test the MCP endpoint\ncurl -X POST http://localhost:3000/mcp \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\"jsonrpc\":\"2.0\",\"id\":1,\"method\":\"initialize\",\"params\":{\"protocolVersion\":\"2025-03-26\",\"capabilities\":{},\"clientInfo\":{\"name\":\"test\",\"version\":\"1.0\"}}}'\n```\n\n## Client Configuration\n\n### Claude Code — local (stdio)\n\nFor local use without Docker, add to your project `.mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"duplicati\": {\n      \"type\": \"stdio\",\n      \"command\": \"uv\",\n      \"args\": [\"run\", \"duplicati-mcp\"],\n      \"env\": {\n        \"DUPLICATI_URL\": \"http://localhost:8200\",\n        \"DUPLICATI_READONLY\": \"\"\n      }\n    }\n  }\n}\n```\n\nCredentials are loaded from the `.env` file at the project root (see [Getting Started](#getting-started)).\n\n### Claude Code — Docker/remote (HTTP)\n\nAdd to your `.mcp.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"duplicati\": {\n      \"type\": \"http\",\n      \"url\": \"http://your-host:3000/mcp\"\n    }\n  }\n}\n```\n\n### Claude Desktop\n\nClaude Desktop requires `mcp-proxy` as a bridge to HTTP servers. Add to your configuration file:\n\n**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`\n**Windows**: `%APPDATA%\\Claude\\claude_desktop_config.json`\n\n```json\n{\n  \"mcpServers\": {\n    \"duplicati\": {\n      \"command\": \"uvx\",\n      \"args\": [\"mcp-proxy\", \"--transport\", \"streamablehttp\", \"http://your-host:3000/mcp\"]\n    }\n  }\n}\n```\n\n## Available Tools\n\nOnce connected, the LLM has access to:\n\n### Backup Jobs\n1. **list_backups** — List all configured jobs with ID, name, last run date and result\n2. **get_backup** — Get detailed information about a specific job\n3. **run_backup** — Trigger a backup job immediately\n4. **abort_backup** — Abort the currently running backup for a job\n\n### Status & Progress\n5. **get_progress** — Live progress of the active backup task (phase, %, file counts)\n6. **get_server_status** — Duplicati server state, version and active task\n\n### Configuration\n7. **export_backup_config** — Export a job configuration as JSON\n8. **update_backup_config** — Update an existing job configuration in place (use with `export_backup_config` to modify sources, settings, schedule, etc.)\n9. **import_backup_config** — Import a job configuration from JSON (creates a new job)\n\n### History & Diagnostics (SQLite — requires `DUPLICATI_DB_PATH`)\n10. **db_get_backup_metadata** — Rich metadata from the local database: last run date, duration, file counts, quota usage, last error\n11. **db_get_backup_schedule** — Schedule configuration for a backup job\n12. **db_list_errors** — Recent error log entries, optionally filtered by job\n13. **db_list_notifications** — System notifications (update alerts, etc.)\n14. **db_get_backup_options** — Configuration options for a job (compression, retention policy, etc.) — passphrases excluded\n15. **db_list_operations** — Operation history for a job (Backup, Restore, List, etc.) with timestamps\n16. **db_get_operation_log** — Full result and statistics for a specific operation\n17. **db_list_filesets** — Available restore points (backup versions) for a job\n\n## Example Prompts\n\nOnce the server is connected to your LLM, here are prompts you can use:\n\n**General status**\n- \"What backup jobs are configured on my Duplicati?\"\n- \"What was the last backup that ran and what was the result?\"\n- \"Is a backup currently running?\"\n\n**History & statistics** _(requires `DUPLICATI_DB_PATH`)_\n- \"Show me the last 10 operations for backup job 2\"\n- \"What is the average duration of recent backups?\"\n- \"Have there been any errors on my backups in the past few weeks?\"\n- \"How many files are backed up and what is the total size on the destination?\"\n\n**Restore points** _(requires `DUPLICATI_DB_PATH`)_\n- \"What restore points are available for my backup job?\"\n- \"What is the oldest backup available for a restore?\"\n\n**Configuration** _(requires `DUPLICATI_DB_PATH`)_\n- \"What retention policy is configured on my backup job?\"\n- \"What compression and encryption options are in use?\"\n\n**Diagnostics** _(requires `DUPLICATI_DB_PATH`)_\n- \"Are there any pending system notifications on Duplicati?\"\n- \"Has my Duplicati encountered any errors recently? Which ones?\"\n- \"Analyse the last backup and tell me if everything went well\"\n\n**Open-ended** _(combines multiple tools)_\n- \"Give me a full health report on my Duplicati backups\"\n\n## Environment Variables\n\n| Variable | Default | Description |\n|---|---|---|\n| `DUPLICATI_URL` | `http://localhost:8200` | URL of the Duplicati instance |\n| `DUPLICATI_PASSWORD` | _(empty)_ | Duplicati web interface password (leave empty if none set) |\n| `DUPLICATI_READONLY` | _(empty)_ | Set to `true`, `1` or `yes` to disable write operations |\n| `DUPLICATI_DB_PATH` | _(empty)_ | Path to `Duplicati-server.sqlite` — enables SQLite-backed history tools |\n| `MCP_TRANSPORT` | `stdio` | Transport: `stdio` or `streamable-http` |\n| `MCP_PORT` | `3000` | Port for Streamable HTTP transport |\n\n### Read-only Mode\n\n`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.\n\n### SQLite Access\n\nSetting `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.\n\n**Local use** — point to the server database on your machine:\n```\nDUPLICATI_DB_PATH=/path/to/duplicati/config/Duplicati-server.sqlite\n```\n\n**Docker** — share the Duplicati config directory as a read-only volume. In `docker-compose.yml`:\n\n```yaml\nservices:\n  duplicati-mcp:\n    # ...\n    volumes:\n      - duplicati_config:/duplicati-config:ro   # named volume (recommended)\n      # or: - /srv/duplicati/config:/duplicati-config:ro  # bind mount\n    environment:\n      - DUPLICATI_DB_PATH=/duplicati-config/Duplicati-server.sqlite\n\nvolumes:\n  duplicati_config:   # must be the same volume used by the Duplicati container\n```\n\n## Docker Hub\n\n- **Repository**: [kcofoni/duplicati-mcp](https://hub.docker.com/r/kcofoni/duplicati-mcp)\n- **Latest tag**: `kcofoni/duplicati-mcp:latest`\n\n```bash\ndocker pull kcofoni/duplicati-mcp:latest\n```\n\n## Development\n\n### File Structure\n\n```\nduplicati-mcp/\n├── src/\n│   └── duplicati_mcp/\n│       ├── __init__.py\n│       ├── __main__.py\n│       ├── client.py        # Duplicati REST API client\n│       ├── db.py            # Read-only SQLite access (server DB + per-backup DBs)\n│       └── server.py        # FastMCP server and tools\n├── mcp-publication/         # MCP registry publication files\n├── requirements.txt         # Python dependencies\n├── pyproject.toml           # Project metadata\n├── Dockerfile\n├── docker-compose.yml\n├── .mcp.json                # Claude Code local config (stdio)\n├── test_server.sh           # Docker container smoke test\n├── test_mcp.py              # MCP protocol test\n├── README.md                # This file (English)\n└── README_fr.md             # French documentation\n```\n\n### Running Tests\n\n```bash\n# Smoke test (requires running Docker container)\n./test_server.sh\n\n# MCP protocol test (requires running server)\npython test_mcp.py\npython test_mcp.py localhost:3000\n```\n\n### Interactive Tool Testing (local)\n\n```bash\nuv run mcp dev src/duplicati_mcp/server.py\n```\n\n## Troubleshooting\n\n### Cannot connect to Duplicati\n\nCheck 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.\n\n### Authentication failed\n\nVerify `DUPLICATI_PASSWORD` matches the password set in Duplicati's web interface. Leave empty if no password is configured.\n\n### MCP endpoint not responding\n\n```bash\ndocker ps | grep duplicati-mcp-server\ndocker logs duplicati-mcp-server\n```\n\n## License\n\nThis project is licensed under the MIT License — see the [LICENSE](LICENSE) file for details.\n",
  "bytes": 9684,
  "sha": "adbe93c6a1796db9da6288a62d631bacd30959af60656a184e9b2c913b6188b2",
  "repo_slug": "kcofoni/duplicati-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_kcofoni_duplicati_mcp_64cd9388/readme"
}