Skip to main content

Typed sync + async Python client for Radarr v3 and Sonarr v3 APIs

Project description

arr-py-client

Typed Python client + MCP server + declarative config sync + workflow primitives for Radarr, Sonarr, and Prowlarr.

CI PyPI Python Coverage License

What's in the box

  • Typed sync + async client — pydantic v2 models, httpx transport, full Radarr v3 + Sonarr v3 + Prowlarr v1 endpoint coverage, ships py.typed.
  • MCP server (arr-py-mcp) — 56 tools exposing the client as LLM-callable operations, with uniform _meta.action_hints so chains self-suggest.
  • Composed workflowsconfig_sync (plan/apply against a YAML desired-state), queue.janitor(...) (policy-based cleanup with named bundles), library.backfill(...) (rate-limited missing-content search with .estimate()), releases.explain(...) (grading + plain-English .advice()).
  • Webhook receivers — parse typed events and dispatch via WSGI or FastAPI handlers.
  • Testing utilitiesmake_fake_radarr() / make_fake_sonarr() fakes + @replay(...) fixture decorator for record-on-miss / replay-on-hit.
  • Zero-dep CLI (arr-py) — status + basic add only; workflows live in Python and MCP on purpose.
  • Python 3.11–3.14.

Install

pip install arr-py-client              # core SDK
pip install arr-py-client[mcp]         # + MCP server
pip install arr-py-client[config]      # + YAML loader for config_sync
pip install arr-py-client[webhooks]    # + FastAPI receiver helper

Quickstart (SDK)

from arr_py_client import RadarrClient

with RadarrClient(base_url="http://radarr:7878", api_key="YOUR_KEY") as client:
    movies = client.movies.list()
    for m in movies[:5]:
        print(m.id, m.title, m.year)

Or via env / .env (RADARR_BASE_URL, RADARR_API_KEY):

from arr_py_client import RadarrClient
with RadarrClient() as client:
    print(len(client.movies.list()))

Async mirrors the sync API via AsyncRadarrClient / AsyncSonarrClient.

Quickstart (MCP)

pip install arr-py-client[mcp]
export RADARR_BASE_URL=http://radarr:7878 RADARR_API_KEY=...
export SONARR_BASE_URL=http://sonarr:8989 SONARR_API_KEY=...
arr-py-mcp  # stdio MCP server; register with Claude, Cursor, etc.

Every list/get tool returns a projected envelope with _meta.action_hints — the LLM client can read the suggested next tool calls directly from the response.

Quickstart (config sync)

Put this in config.yaml (see docs/examples/config-sync/ for the full schema):

tags: [4k, anime, kids]
custom_formats:
  - name: x265
    specifications:
      - name: x265
        implementation: ReleaseTitleSpecification
        required: true
        fields: [{ name: value, value: "(h|x).?265" }]
quality_profiles:
  - name: HD-Bluray
    upgradeAllowed: true
    cutoff: 7
    formatItems:
      - { name: x265, score: -10000 }

Apply it:

from arr_py_client import RadarrClient
from arr_py_client.config_sync import load, plan, apply

with RadarrClient() as client:
    desired = load("config.yaml")
    plan_ = plan(client, desired)
    print(plan_.summary())
    report = apply(client, plan_, dry_run=False)

Quickstart (queue janitor)

Named policy bundles for common opinions:

from arr_py_client import RadarrClient, POLICIES

with RadarrClient() as client:
    report = client.queue.janitor(
        policies=POLICIES.default,       # or .conservative / .aggressive / .ratio_preserving
        protected_trackers=("private-tracker.example",),
        dry_run=False,
    )
    print(report.total_matches)

Quickstart (webhook receiver)

Parse-only:

from arr_py_client.webhooks import parse_event, OnGrab

event = parse_event(request.json())
if isinstance(event, OnGrab):
    notify(f"Grabbed {event.movie.title if event.movie else '?'}")

With FastAPI:

from fastapi import FastAPI
from arr_py_client.webhooks import fastapi_router

app = FastAPI()
app.include_router(fastapi_router(on_event), prefix="/webhooks/arr")

Or zero-dep WSGI:

from wsgiref.simple_server import make_server
from arr_py_client.webhooks import wsgi_app

make_server("0.0.0.0", 9000, wsgi_app(on_event)).serve_forever()  # noqa: S104

Comparison

arr-py-client pyarr Recyclarr
Pydantic v2 models yes no (dicts) n/a
Async yes no n/a
Radarr / Sonarr v3 coverage yes yes partial (config only)
Prowlarr v1 coverage yes yes yes
Lidarr / Readarr planned yes yes
MCP server yes (56 tools) no no
Declarative config sync yes (YAML/JSON/TOML) no yes
Queue janitor / backfill / release explain yes no no
Webhook receiver helper yes no no
Ships py.typed yes no n/a

Documentation

Development

git clone https://github.com/allada-homelab/arr-py-client
cd arr-py-client
uv sync --all-extras --all-groups
just test

Integration tests (require Docker):

just test-int

Regenerate clients from upstream specs:

just gen-radarr <radarr-tag>
just gen-sonarr <sonarr-tag>

License

MIT. See LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

arr_py_client-0.7.0.tar.gz (271.8 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

arr_py_client-0.7.0-py3-none-any.whl (400.9 kB view details)

Uploaded Python 3

File details

Details for the file arr_py_client-0.7.0.tar.gz.

File metadata

  • Download URL: arr_py_client-0.7.0.tar.gz
  • Upload date:
  • Size: 271.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for arr_py_client-0.7.0.tar.gz
Algorithm Hash digest
SHA256 6b24df4ed26f286f82ed27017c635ff5c21771429be6a3605b16061398916f47
MD5 106ccbaf24c59e6d3aaab19bda05e404
BLAKE2b-256 45f944490b82728641b7cd73740d0ca071ec6f5b1c2ab28c7af3b43c1f3f9d6f

See more details on using hashes here.

Provenance

The following attestation bundles were made for arr_py_client-0.7.0.tar.gz:

Publisher: release.yml on allada-homelab/arr-py-client

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file arr_py_client-0.7.0-py3-none-any.whl.

File metadata

  • Download URL: arr_py_client-0.7.0-py3-none-any.whl
  • Upload date:
  • Size: 400.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for arr_py_client-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 54d103b0409a60b3a9785aec476fcce72446d7edf455200213f993cc0ddf2152
MD5 2b1106910407c308f90347efe98e7a47
BLAKE2b-256 9b72d6eef2b4f1b3f0664b56dc45780b41c325fffbe13778e62ae658799927f5

See more details on using hashes here.

Provenance

The following attestation bundles were made for arr_py_client-0.7.0-py3-none-any.whl:

Publisher: release.yml on allada-homelab/arr-py-client

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page