media-mcp
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@media-mcpSearch for the movie 'Inception' and add it to Radarr"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
media-mcp
Serveur MCP local (transport stdio) pour piloter un stack média self-hosted : Sonarr + Radarr, et qBittorrent via qui (autobrr).
Prérequis
Python 3.11+
uvinstallé
Related MCP server: MCP *arr Server
Installation
# Cloner / se placer dans le répertoire du projet
cd media-mcp
# Installer les dépendances
uv sync
# Copier et remplir les variables d'environnement
cp .env.example .env
# Éditer .env avec vos URLs et clés APILancement en développement
uv run python -m media_mcpLe serveur démarre en mode stdio et attend des messages MCP sur stdin/stdout.
Configuration Claude Desktop
Ajouter dans ~/Library/Application Support/Claude/claude_desktop_config.json
(macOS) ou %APPDATA%\Claude\claude_desktop_config.json (Windows) :
{
"mcpServers": {
"media-mcp": {
"command": "uv",
"args": ["--directory", "/chemin/absolu/media-mcp", "run", "python", "-m", "media_mcp"],
"env": {
"SONARR_URL": "http://localhost:8989",
"SONARR_API_KEY": "xxx",
"RADARR_URL": "http://localhost:7878",
"RADARR_API_KEY": "xxx",
"QUI_URL": "https://qui.example.com",
"QUI_API_KEY": "xxx",
"QUI_INSTANCE": "",
"PROWLARR_URL": "http://localhost:9696",
"PROWLARR_API_KEY": "xxx"
}
}
}
}Remplacer /chemin/absolu/media-mcp par le chemin réel du projet.
Variables d'environnement
Variable | Description | Défaut |
| URL de base Sonarr |
|
| Clé API Sonarr | (requis) |
| URL de base Radarr |
|
| Clé API Radarr | (requis) |
| URL de base de l'instance qui | (requis pour qBit) |
| Clé API qui (Settings > API Keys) | (requis pour qBit) |
| Instance qBit ciblée (id ou nom) ; vide = auto si une seule | (optionnel) |
| URL de base Prowlarr | (requis pour Prowlarr) |
| Clé API Prowlarr | (requis pour Prowlarr) |
Tools disponibles
Sonarr
Tool | Type | Description |
| read | Statut et version de Sonarr |
| read | Liste des séries suivies |
| read | Recherche une série (pour ajout) |
| read | Profils de qualité disponibles |
| read | Dossiers racine configurés |
| read | File de téléchargement + diagnostic des items bloqués (voir ci-dessous) |
| read | Espace disque par volume, le plus plein en premier |
| read | Avertissements de santé de l'instance |
| read | Événements récents (grab/import/…) avec downloadId ; filtre |
| write | Retire un item (par |
| read | Épisodes à venir via calendrier |
| read | Détail saison par saison d'une série |
| read | Liste les épisodes d'une saison (E-num, titre, hasFile ✓/✗, monitored ✓/✗, id, fileId) |
| write | Ajoute une série |
| write | (Dé)monitore une saison précise |
| write | Lance la recherche d'une saison |
| destructive | Supprime tous les fichiers d'une saison |
| destructive | Supprime un fichier d'épisode |
| destructive | Supprime une série |
Radarr
Tool | Type | Description |
| read | Statut et version de Radarr |
| read | Liste des films suivis |
| read | Recherche un film (pour ajout) |
| read | Profils de qualité disponibles |
| read | Dossiers racine configurés |
| read | File de téléchargement + diagnostic des items bloqués (voir Sonarr) |
| read | Espace disque par volume, le plus plein en premier |
| read | Avertissements de santé de l'instance |
| read | Événements récents (grab/import/…) avec downloadId ; filtre |
| write | Retire un item (par |
| read | Films à venir via calendrier |
| write | Ajoute un film |
| write | (Dé)monitore un film |
| write | Lance la recherche d'un film |
| destructive | Supprime le fichier d'un film (garde le film suivi) |
| destructive | Supprime un film |
qBittorrent (via qui)
Accès uniquement via qui (le gestionnaire web multi-instance d'autobrr), jamais via l'API qBittorrent directe. Auth par header
X-API-Key. Les tools ciblent l'instance résolue depuisQUI_INSTANCE(id ou nom) ; si vide et qu'une seule instance existe, elle est choisie automatiquement ; si plusieurs, une erreur liste les instances disponibles.
Tool | Type | Description |
| read | Instances qBittorrent gérées par qui (id + nom) |
| read | Torrents de l'instance (nom, hash complet, état, %, taille, ratio, catégorie) ; |
| read | Détail d'un torrent par hash ou préfixe unique (pont avec le |
| control | Met un torrent en pause (réversible, pas de confirm) |
| control | Reprend un torrent (réversible, pas de confirm) |
| destructive | Retire un torrent de qBittorrent, avec option suppression des fichiers |
Les tools prenant un hash acceptent le hash complet (40 car., copiable depuis
qbit_list_torrents) ou un préfixe unique ; un préfixe ambigu liste les candidats sans
agir.
Le hash qBittorrent est la clé de liaison : c'est la valeur renvoyée par le downloadId
de l'historique Sonarr/Radarr. La comparaison est insensible à la casse (qBit renvoie le
hash en minuscules, les *arr souvent en majuscules).
Prowlarr (indexeurs)
Gestionnaire d'indexeurs Servarr — API en /api/v1 (et non v3), auth X-Api-Key.
Orienté diagnostic des indexeurs.
Tool | Type | Description |
| read | Version de Prowlarr |
| read | Indexeurs configurés (id, nom, activé ✓/✗, protocole, privacy, catégories, tags), triés par nom |
| read | Indexeurs en échec / désactivés temporairement (+ |
| read | Avertissements globaux Prowlarr (type/source/message) |
| action | Teste la connectivité d'un indexeur → PASS/FAIL + message (pas de confirm) |
| action | Teste tous les indexeurs → résumé pass/fail, échecs mis en avant |
| read | Recherche cross-indexeurs (tout contenu) triée par seeders ; affiche |
| acquisition | Envoie une release au download client de Prowlarr (dry-run/confirm) |
prowlarr_indexer_statusne porte pas de message textuel de raison (l'API/indexerstatusn'expose queindexerId+ horodatages) : il croise la liste des indexeurs pour le nom et affiche la date de reprise (disabledTill). Pour le « pourquoi » global, voirprowlarr_health.
Recherche & grab (contenu hors-*arr : ebooks, manga, logiciels…)
prowlarr_search interroge tous les indexeurs et renvoie, par release, la référence de grab
(guid + indexerId) à passer à prowlarr_grab. Les résultats sont triés par seeders
décroissant (le limit de Prowlarr n'étant pas un vrai plafond, la coupe est faite côté client).
prowlarr_grab envoie la release au download client configuré dans Prowlarr (dry-run par
défaut ; confirm=True pour exécuter). Aucune catégorie n'est passée par le MCP : le
classement final dans qBittorrent (ebook / logiciel / autre) est décidé par les Mapped
Categories du download client, à configurer dans l'UI Prowlarr (Settings → Download
Clients). S'il n'y a aucun download client, le grab renvoie un message clair (à ajouter d'abord
dans l'UI). La recherche/le grab avec catégorie explicite restent gérés côté Prowlarr, pas ici.
Tools coordonnés — purge « partout »
Suppriment, en un geste avec aperçu et confirm, les fichiers bibliothèque (Sonarr/Radarr)
ET le(s) torrent(s) correspondants côté qBittorrent-via-qui, cross-seeds inclus.
Tool | Type | Description |
| destructive | Purge une saison partout (fichiers Sonarr + torrents + cross-seeds) |
| destructive | Purge un film partout (fichier Radarr + torrents + cross-seeds) |
Flux :
Lister les fichiers concernés côté *arr (saison / film) → nombre + taille.
Extraire les
downloadIddepuis l'historique *arr (/history/series,/history/movie) → ensemble des hash d'origine (dédupliqués ; un season pack partage un seuldownloadId).Côté qui, pour chaque origine : résoudre le torrent, puis
local-matches?strict=true→ cross-seeds (siblings).Ensemble à supprimer = origines présentes ∪ siblings, dédupliqué par hash.
include_loose_matches=Falseexclut les siblingsmatch_type ∈ {name, release}(garde les matchescontent_path) et indique combien ont été exclus.Dry-run (
confirm=False) : aperçu exhaustif des deux côtés, rien supprimé.confirm=True: suppression des fichiers *arr puis un seulbulk-action delete(avecdeleteFilesselondelete_torrent_files) sur tous les hash ; rapport combiné.
Cas limites gérés (sans planter) : aucun downloadId (historique purgé → suppression
biblio seule, torrents à gérer à la main) ; origine absente de qBit (ignorée, signalée) ;
saison/film sans fichier (torrents traités quand même) ; cross-seed indispo (repli sur les
origines seules).
Honnêteté sur l'espace disque : les tailles bibliothèque et torrents ne sont jamais additionnées — hardlinkées, ce sont généralement les mêmes octets. L'aperçu les montre séparément et rappelle que, comme on supprime les deux côtés (+ cross-seeds), l'espace de ce contenu sera cette fois réellement libéré (≈ la plus grande des deux tailles, pas la somme).
Pattern dry-run / confirm
Toutes les actions à effet de bord (add_*, delete_*, search_*) acceptent un paramètre confirm:
confirm=False(défaut) → aperçu sans exécution (dry-run)confirm=True→ exécution réelle
Note hardlink : les tools de suppression de fichiers (
sonarr_delete_season,sonarr_delete_episode_file,radarr_delete_movie_file) retirent les fichiers côté Sonarr/Radarr uniquement. Si les fichiers sont en hardlink avec un client torrent, l'espace disque n'est pas libéré tant que le torrent n'est pas aussi supprimé côté client. L'aperçu dry-run le rappelle.
Filtre event_type de *_history
L'API attend un entier pour son query param eventType, donc le filtrage est fait
côté client sur le champ texte eventType de chaque événement. event_type accepte :
Alias | Correspond à ( |
|
|
|
|
|
|
|
|
|
|
|
|
La chaîne canonique exacte est aussi acceptée (ex. event_type="downloadFolderImported").
Une valeur inconnue renvoie un message listant les valeurs valides, sans appel API.
Comme le filtrage est côté client sur une fenêtre élargie (une requête,
pageSize = max(limit*5, 100)), un résultat filtré partiel ajoute une note
showing N of up to {limit} (searched the {window} most recent events).
Diagnostic & regroupement de *_queue
sonarr_queue / radarr_queue surfacent, pour chaque item, pourquoi il est bloqué :
trackedDownloadStatus / trackedDownloadState (ex. warning / importBlocked), le texte
des statusMessages et l'errorMessage éventuel. Les messages par item sont bornés
((+N more)) pour rester lisibles ; un champ absent/null est géré sans erreur.
Les items partageant le même downloadId (un season pack = un torrent, N lignes) sont
regroupés en une entrée [×N] affichant le downloadId (le pont vers qBittorrent) et la
ligne ids: … (les queue IDs individuels du groupe, tronquée si trop longue). Les items sans
downloadId restent individuels et conservent taille/ETA.
*_delete_queue_item accepte exactement un de queue_id (un item) ou download_id
(tous les items du download, retirés en un seul DELETE /queue/bulk) ; en dry-run il liste
le nombre d'items, leur(s) titre(s) et les IDs ciblés avant toute suppression.
Développement
# Lint & format
uv run ruff check src tests
uv run ruff format src tests
# Tests
uv run pytestArchitecture
src/media_mcp/
config.py # pydantic-settings — lit les variables d'env
models.py # modèles pydantic pour les réponses simplifiées
coordinated.py # service d'orchestration purge (arr + qui), logique lourde
server.py # instancie FastMCP et enregistre tous les tools
__main__.py # entrypoint: python -m media_mcp
clients/
base.py # ArrClient: httpx async, gestion des erreurs
sonarr.py # SonarrClient(ArrClient)
radarr.py # RadarrClient(ArrClient)
prowlarr.py # ProwlarrClient(ArrClient) — /api/v1
qui.py # QuiClient: httpx async, header X-API-Key (NE dérive PAS d'ArrClient)
tools/
sonarr_tools.py # @mcp.tool pour Sonarr
radarr_tools.py # @mcp.tool pour Radarr
qbit_tools.py # @mcp.tool pour qBittorrent via qui
prowlarr_tools.py # @mcp.tool pour Prowlarr (indexeurs)
coordinated_tools.py # @mcp.tool purge saison/film "partout" (arr + qui)Ajouter un nouveau service (ex. Jellyseerr) : créer clients/jellyseerr.py et
tools/jellyseerr_tools.py, puis enregistrer dans server.py.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ava-hip/mcp-media-stack'
If you have feedback or need assistance with the MCP directory API, please join our Discord server