profilarr-mcp
Part of the arr-mcps collection.MCP server exposing Profilarr'sv1 REST API (/api/v1, OpenAPI 3.1) as tools, so anLLM can inspect and manage your Profilarr instance: linked databases, connectedRadarr/Sonarr instances, backups, jobs, announcements, and system status.
Built with FastMCP.
Scope
Profilarr's programmatic API is deliberately small. This server wraps thedocumented /api/v1 JSON surface only:
- System — health, status, OpenAPI spec
- Arr — list connected instances (read-only; sync state via status)
- Databases — link/get/update/unlink, trigger PCD sync
- Jobs — poll job status
- Backups — list/create/download/upload/delete/settings
- Announcements — list/get
Many of Profilarr's headline features (custom formats, quality profiles,regular expressions, delay profiles, media management, upgrades, rename,notifications, and triggering an Arr sync) are not exposed by the v1 RESTAPI — they live behind SvelteKit form actions that require a browser session andCSRF token, so they are intentionally not wrapped here. Use the web UI for those.
Getting the API key
Profilarr accepts X-Api-Key on every /api/v1 request. The active key iseither the PROFILARR_API_KEY environment variable set on the Profilarr server(≥ 32 characters, takes precedence), or the key generated underSettings > Security in the web UI (bcrypt-stored, shown once). /health isthe only endpoint that works without a key.
Install
Download a wheel from the latest releaseand install it as a uv tool (no repo checkout needed):
uv tool install profilarr_mcp-*.whl
This puts a profilarr-mcp command on your PATH. Register it with Claude Code:
claude mcp add profilarr \
--env PROFILARR_URL=https://your-profilarr-host \
--env PROFILARR_API_KEY=<key> \
-- profilarr-mcp
From source
uv sync
cp .env.example .env # fill in PROFILARR_URL and PROFILARR_API_KEY
claude mcp add profilarr \
--env PROFILARR_URL=https://your-profilarr-host \
--env PROFILARR_API_KEY=<key> \
-- uv run --directory /path/to/profilarr-mcp profilarr-mcp
Config
| Env var | Required | Default |
|---|---|---|
PROFILARR_URL |
yes | - |
PROFILARR_API_KEY |
yes* | none (no auth header sent) |
PROFILARR_TEMP_DIR |
no | system temp dir |
*Required for every tool except profilarr_health, which is public.
Tools
4 resource-scoped tools, each covering multiple Profilarr v1 endpoints(20 total) via an operation parameter. Call a tool with operation set toone of its listed operations and an arguments dict matching thatoperation's parameters — the tool's own description (visible to your MCPclient) lists every operation, its signature, and a one-line doc.
| Tool | Operations | Covers |
|---|---|---|
profilarr_databases |
6 | List/create/get/update/delete/sync databases |
profilarr_backups |
7 | List/create/download/delete/upload backups, backup settings |
profilarr_jobs_arr |
2 | Job polling, Arr instance list |
profilarr_meta |
5 | Health, status, OpenAPI spec, announcements |
Example: profilarr_databases(operation="profilarr_sync_database", arguments={"id": 3}).Endpoint-level naming (profilarr_<verb>_<resource>) is preserved as theoperation value:
| Operation | Endpoint |
|---|---|
profilarr_health |
GET /health |
profilarr_status |
GET /status |
profilarr_get_openapi_spec |
GET /openapi.json |
profilarr_list_arr_instances |
GET /arr |
profilarr_list_databases |
GET /databases |
profilarr_create_database |
POST /databases |
profilarr_get_database |
GET /databases/{id} |
profilarr_update_database |
PATCH /databases/{id} |
profilarr_delete_database |
DELETE /databases/{id} |
profilarr_sync_database |
POST /databases/{id}/sync |
profilarr_get_job |
GET /jobs/{id} |
profilarr_list_backups |
GET /backups |
profilarr_create_backup |
POST /backups |
profilarr_download_backup |
GET /backups/{filename} |
profilarr_delete_backup |
DELETE /backups/{filename} |
profilarr_upload_backup |
POST /backups/upload |
profilarr_get_backup_settings |
GET /backups/settings |
profilarr_update_backup_settings |
PATCH /backups/settings |
profilarr_list_announcements |
GET /announcements |
profilarr_get_announcement |
GET /announcements/{id} |
Async jobs
profilarr_create_backup and profilarr_sync_database return {jobId} withHTTP 202. Poll the result with profilarr_jobs_arr(operation="profilarr_get_job", arguments={"id": jobId}).Note profilarr_sync_database pulls the linked database repo, not an Arr sync.
Binary endpoints
profilarr_download_backup streams the sanitized archive to a local temp file(PROFILARR_TEMP_DIR or the system temp dir) and returns {path, filename, size}.profilarr_upload_backup takes a local file path and POSTs it as multipart formdata. Bytes never enter the LLM context.
Development
make help # list all commands
| Command | Does |
|---|---|
make sync |
uv sync |
make test |
Offline tests - one per endpoint, mocked HTTP |
make test-integration |
Tests against the live instance (needs PROFILARR_URL/PROFILARR_API_KEY) |
make build |
Build wheel + sdist into dist/ |
make bump-patch / bump-minor / bump-major |
Bump the version in pyproject.toml + uv.lock |
make clean |
Remove build artifacts |
The release workflow (.github/workflows/release.yml) builds and publishes toReleases whenever a v*tag is pushed — so the usual flow is make bump-patch, commit, then tag and push.
The integration suite is read-only (health/status/arr/databases/announcements)plus a self-cleaning backup lifecycle (create → poll → download → delete).Database create/delete is intentionally not exercised against a live instance,since linking a database clones a real repository.