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.6.0.tar.gz (248.1 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.6.0-py3-none-any.whl (374.9 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: arr_py_client-0.6.0.tar.gz
  • Upload date:
  • Size: 248.1 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.6.0.tar.gz
Algorithm Hash digest
SHA256 8482688b58a02fd6dbfc2fe2625063d8d012a18c69c614abb8af8feffecf8d35
MD5 e261b57794d6661ffa5a5a54e7c9c355
BLAKE2b-256 dcaf242dc4483af546f41b1cbf711d801ab20b71134ecbc8274214975e649035

See more details on using hashes here.

Provenance

The following attestation bundles were made for arr_py_client-0.6.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.6.0-py3-none-any.whl.

File metadata

  • Download URL: arr_py_client-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 374.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.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 21f5025e91b54ca7f683047029cae252247859ccfcd190499d3d8ec4c6387f5c
MD5 e6bdb6711f2a54c21ad9913b5457ece5
BLAKE2b-256 e7aa74e26b3a549c1a26d667f60720c3300d77aa9669865eb71076ee032f9da2

See more details on using hashes here.

Provenance

The following attestation bundles were made for arr_py_client-0.6.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