Harden ARR MCP tool surface and installer

This commit is contained in:
Mikei386
2026-08-28 13:05:21 +02:00
parent 0008dd3b3e
commit da6e762d72
9 changed files with 380 additions and 301 deletions
+6 -3
View File
@@ -1,4 +1,4 @@
FROM python:3.13-slim AS builder
FROM python:3.14-slim@sha256:cea0e6040540fb2b965b6e7fb5ffa00871e632eef63719f0ea54bca189ce14a6 AS builder
ARG ARR_MCP_VERSION=1.0.1
@@ -14,7 +14,7 @@ RUN site_packages="$(/opt/arr-mcp/venv/bin/python -c 'import site; print(site.ge
&& install -m 0644 /tmp/mcp_radarr.py "$site_packages/arr_mcp/mcp/mcp_radarr.py" \
&& /opt/arr-mcp/venv/bin/python -m compileall -q "$site_packages/arr_mcp/mcp"
FROM python:3.13-slim
FROM python:3.14-slim@sha256:cea0e6040540fb2b965b6e7fb5ffa00871e632eef63719f0ea54bca189ce14a6
RUN groupadd --system --gid 10001 arrmcp \
&& useradd --system --uid 10001 --gid 10001 --no-create-home arrmcp
@@ -23,6 +23,9 @@ COPY --from=builder /opt/arr-mcp /opt/arr-mcp
COPY services/arr-mcp/run.sh /usr/local/bin/run-arr-mcp
ENV PATH="/opt/arr-mcp/venv/bin:${PATH}" \
HOME=/tmp \
XDG_CONFIG_HOME=/tmp/.config \
XDG_CACHE_HOME=/tmp/.cache \
PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1
@@ -32,6 +35,6 @@ USER 10001:10001
EXPOSE 8000
HEALTHCHECK --interval=30s --timeout=5s --start-period=20s --retries=3 \
CMD python -c "import socket; s=socket.create_connection(('127.0.0.1',8000),3); s.close()"
CMD python -c "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3)"
ENTRYPOINT ["/usr/local/bin/run-arr-mcp"]
+74 -103
View File
@@ -1,91 +1,102 @@
# ARR-MCP auf Unraid
# Mikes ARR-MCP
Dieser Ordner baut **einen eigenständigen Container nur für Sonarr und Radarr**.
Hermes, Pi Coding und andere MCP-Clients erreichen ihn anschließend über
`http://<UNRAID-IP>:8207/mcp`.
Ein kleiner, eigenständiger Docker-Container für **Sonarr und Radarr**. Das
Dockerfile basiert bereits auf Debian Slim; ein leerer Debian-Container muss
nicht vorher angelegt oder nachträglich verändert werden.
## Warum dieser Fork bleibt
MCP-Endpunkt nach der Standardinstallation:
Geprüft am 27. August 2026:
```text
http://<UNRAID-IP>:8207/mcp
```
- [`Knuckles-Team/arr-mcp`](https://github.com/Knuckles-Team/arr-mcp) 2.1.0
ist der moderne Upstream unseres Pakets, stellt
in der kompakten Oberfläche aber weiterhin generische `*_action`-Werkzeuge
mit frei wählbaren API-Methoden bereit. Das führte bei lokalen Modellen zu
falschen Aktionen, unnötigen Schemaabfragen und großen Antworten.
- Andere öffentliche ARR-MCPs bieten teilweise mehr Dienste oder eine eigene
Weboberfläche, ersetzen aber nicht unser kompaktes Radarr-Codec-Inventar und
den an eine Vorschau gebundenen Sonarr-Freigabeablauf.
## Warum nicht einfach der unveränderte Knuckles-MCP?
Wir bleiben deshalb vorläufig bei `arr-mcp` 1.0.1 plus zwei kleinen,
versionierten Patches. Ein späterer Wechsel ist sinnvoll, sobald ein Upstream
diese Eigenschaften ohne lokale Anpassungen anbietet.
Stand 28. August 2026 wurde `Knuckles-Team/arr-mcp` 2.1.0 geprüft. Übernommen
werden dessen Python-3.14-Slim-Basis, `/health`-Check, Prozess-Init und begrenzte
Docker-Logs. Nicht übernommen wird die generische Oberfläche mit
`sonarr_action(action, params_json)` und `radarr_action(action, params_json)`.
Ein kleines Modell muss dabei Methodennamen und Parameter erraten und kann
versehentlich eine Schreibaktion wählen. Das Paket 2.1.0 selbst wird noch nicht
als Basis verwendet: Seine veröffentlichte PyPI-Version verlangt derzeit ein
nicht öffentlich verfügbares `agent-utilities >=2.0.0`. Die reproduzierbar
installierbare Basis bleibt deshalb vorläufig `arr-mcp[mcp]==1.0.1`.
## Besondere Werkzeuge
Dieser Fork bietet stattdessen eindeutige Werkzeuge mit festen Parametern:
- `radarr_movie_codec_inventory`: kompakte, paginierte Liste mit Codec,
Auflösung, Sprachen und Dateigröße; keine riesigen Radarr-Rohantworten.
- `sonarr_action`: begrenzte, kompakte Sonarr-Aktionen wie `find_series`,
`get_season_summary` und `search_releases`.
- Sonarr-Schreibaktionen sind standardmäßig abgeschaltet. Im Schreibmodus
benötigen `start_episode_search` und `grab_release` zuerst eine passende
Vorschau, danach eine ausdrückliche Freigabe und ein kurzlebiges Ticket.
```text
sonarr_find_series
sonarr_get_season_summary
sonarr_search_releases
sonarr_system_status
radarr_find_movie
radarr_movie_codec_inventory
radarr_search_releases
```
## Empfohlene Installation auf Unraid
Alle sieben sind rein lesend. Es gibt keinen Raw-Request und kein generisches
Action-Werkzeug. `sonarr_search_releases` ändert insbesondere kein Monitoring
und startet weder automatische Suche noch Download.
Im vollständigen Checkout des Repositories als root:
Nur mit `ARR_MCP_WRITE=1` erscheinen zusätzlich:
```text
sonarr_preview_release_grab
sonarr_grab_release
sonarr_preview_episode_search
sonarr_start_episode_search
```
Die beiden ausführenden Werkzeuge verlangen eine vorherige Vorschau, eine
ausdrückliche Bestätigung und ein kurzlebiges Ticket. Radarr-Schreibwerkzeuge
sind absichtlich nicht enthalten.
## Installation auf Unraid
Im vollständigen Checkout als root genau einen Befehl ausführen:
```bash
./services/arr-mcp/install-on-unraid.sh
```
Beim ersten Aufruf entsteht:
Beim ersten Lauf wird nur diese Datei angelegt:
```text
/mnt/nvme-storage/appdata/ARR-MCP/arr-mcp.env
```
Dort Sonarr- und Radarr-Schlüssel eintragen. Danach denselben Installationsbefehl
erneut ausführen. Das Skript:
1. baut das lokale Image `mike-ai/arr-mcp:1.0.0` aus `python:3.13-slim`,
2. startet ausschließlich den Container `ARR-MCP` im normalen Bridge-Netz,
3. wartet auf den Healthcheck und
4. installiert das DockerMan-Template für spätere Bedienung in der Unraid-GUI.
Es liest oder druckt keine Schlüssel. Eine vorhandene Konfiguration wird nie
überschrieben.
Dort `SONARR_TOKEN` und `RADARR_TOKEN` eintragen und denselben Befehl erneut
starten. Das Skript baut `mike-ai/arr-mcp:1.1.0`, startet ausschließlich
`ARR-MCP` und installiert die vorhandene Unraid-DockerMan-Vorlage. Eine
vorhandene Env-Datei wird weder angezeigt noch überschrieben.
### Kurzer Auftrag für Hermes/Qwen
```text
Klone auf Unraid das Repository
ssh://git@192.168.1.2:33/michael/AI-Profile-Router.git, lies vollständig
services/arr-mcp/README.md und installiere ausschließlich nach dem dort
dokumentierten Weg. Verwende services/arr-mcp/install-on-unraid.sh. Zeige keine
API-Schlüssel an und überschreibe keine vorhandene arr-mcp.env. Stoppe, falls
Werte fehlen, und sage mir nur, welche Variablennamen ich eintragen muss.
Entferne den bisherigen ARR-Endpunkt erst nach einem erfolgreichen Healthcheck
und MCP-Handshake des neuen Containers.
Installiere Mikes ARR-MCP aus
ssh://git@192.168.1.2:33/michael/AI-Profile-Router.git auf Unraid. Lies dazu
services/arr-mcp/README.md und führe ausschließlich
services/arr-mcp/install-on-unraid.sh aus. Erfinde keinen eigenen Container und
keine andere ARR-Konfiguration. Falls SONARR_TOKEN oder RADARR_TOKEN fehlen,
stoppe und nenne mir nur die fehlenden Variablennamen; zeige keine vorhandenen
Werte an. Melde am Ende nur Containerstatus, Healthcheck, MCP-URL und die
angebotenen Werkzeugnamen.
```
## Installation in einem vorhandenen Debian-Slim-Container
## Vorhandener nackter Debian-Slim-Container
Nur verwenden, wenn bereits bewusst ein nackter Debian-Slim-Container mit dem
kompletten Git-Checkout läuft:
Nur als Alternative, wenn bewusst bereits ein persistenter Debian-Slim-
Container mit dem kompletten Repository läuft:
```bash
./services/arr-mcp/install-in-debian-slim.sh
```
Danach startet `/usr/local/bin/run-arr-mcp` den Server. Dieser Weg funktioniert,
ist aber weniger reproduzierbar als der Dockerfile-Build: Eine Neuerstellung des
nackten Containers entfernt die Installation. Für den Produktivbetrieb deshalb
den ersten Weg verwenden.
Danach startet `/usr/local/bin/run-arr-mcp` den Server. Dieser Weg ist weniger
reproduzierbar; bei Neuerstellung des Containers geht die nachträgliche
Installation verloren. Der Dockerfile-Build oben ist deshalb empfohlen.
## Hermes oder anderer MCP-Client
Direkte Registrierung:
## MCP-Client eintragen
```yaml
mcp_servers:
@@ -94,62 +105,22 @@ mcp_servers:
timeout: 600
```
Nach dem Eintragen die MCP-Liste des Clients neu laden beziehungsweise einen
neuen Chat öffnen. Sonarr und Radarr erscheinen als Werkzeuge desselben
Fach-MCPs; sie sind nicht Bestandteil des Hermes-Containers.
Danach die Werkzeugliste neu laden oder einen neuen Chat öffnen.
## Schreiben aktivieren
## Test, Update und Entfernung
In `arr-mcp.env`:
```text
ARR_MCP_WRITE=1
```
Danach nur diesen Container neu starten. Selbst dann erlaubt der Sonarr-Patch
nur die dokumentierten, ticketgebundenen Aktionen. Radarr besitzt derzeit noch
keinen gleichwertigen Freigabeablauf; Änderungen dort nur auf einen eindeutigen
Benutzerauftrag ausführen.
## Update und Test
Nach einem Git-Update denselben Befehl erneut ausführen:
Offline-Tests:
```bash
./services/arr-mcp/install-on-unraid.sh
python3 -m unittest dev/test_sonarr_release_grab.py dev/test_radarr_patch.py
```
Status und Logs:
Update nach `git pull`: denselben Installationsbefehl erneut ausführen.
```bash
docker inspect --format '{{.State.Health.Status}}' ARR-MCP
docker logs --tail 100 ARR-MCP
```
Die Offline-Tests des Forks:
```bash
python3 dev/test_radarr_patch.py
python3 -m unittest dev/test_sonarr_release_grab.py
```
## Deinstallation
Entfernung:
```bash
./services/arr-mcp/install-on-unraid.sh uninstall
```
Der Container verschwindet, während die Appdata-Konfiguration als Rückfall
erhalten bleibt. Erst wenn sie wirklich nicht mehr benötigt wird, kann
`/mnt/nvme-storage/appdata/ARR-MCP` separat gelöscht werden.
## Regeln für Hermes/Qwen
1. Diese README vollständig lesen.
2. Keine eigene ARR-Implementierung und keinen zweiten Sonarr-/Radarr-Dienst
erstellen.
3. Ausschließlich `install-on-unraid.sh` verwenden; keine Befehle improvisieren.
4. Vorhandene `arr-mcp.env` weder anzeigen noch überschreiben.
5. Nach Installation Healthcheck und MCP-Handshake prüfen.
6. Den alten MCPHub-/Athena-Endpunkt erst entfernen, wenn der neue Endpunkt
nachweislich funktioniert.
Die Appdata-Konfiguration bleibt dabei als Rückfall erhalten.
+10 -2
View File
@@ -5,8 +5,9 @@ services:
dockerfile: services/arr-mcp/Dockerfile
args:
ARR_MCP_VERSION: "1.0.1"
image: mike-ai/arr-mcp:1.0.0
image: mike-ai/arr-mcp:1.1.0
container_name: ARR-MCP
init: true
restart: unless-stopped
network_mode: bridge
env_file:
@@ -21,8 +22,15 @@ services:
security_opt:
- no-new-privileges:true
pids_limit: 256
mem_limit: 1g
cpus: 1.0
logging:
driver: json-file
options:
max-size: "10m"
max-file: "3"
healthcheck:
test: ["CMD", "python", "-c", "import socket; s=socket.create_connection(('127.0.0.1',8000),3); s.close()"]
test: ["CMD", "python", "-c", "import urllib.request; urllib.request.urlopen('http://127.0.0.1:8000/health', timeout=3)"]
interval: 30s
timeout: 5s
start_period: 20s
+1 -1
View File
@@ -60,7 +60,7 @@ done
docker build \
--build-arg ARR_MCP_VERSION=1.0.1 \
-f "$SCRIPT_DIR/Dockerfile" \
-t mike-ai/arr-mcp:1.0.0 \
-t mike-ai/arr-mcp:1.1.0 \
"$REPO_ROOT"
ARR_MCP_ENV_FILE="$ENV_FILE" ARR_MCP_PUBLIC_PORT="$PUBLIC_PORT" \