# MUA — Mikes Unraid Agent MCP-Server für Unraid: Docker-Container, Netzwerk und System-Tools. Kompiliertes Bun-Binary (TypeScript), läuft als SysVinit-Service auf Unraid. - **MCP-Endpunkt:** `http://UNRAID-IP:3002/mcp` (Streamable HTTP, POST-only, JSON-RPC 2.0) - **Health-Check:** `http://UNRAID-IP:3002/health` (offen, ohne Auth) - **Config-Server:** `http://127.0.0.1:3013/config` (localhost + separater Admin-Token) - **Auth:** API-Key (Bearer-Token) für `/mcp` - **Tools:** 35 (Docker, Community Applications, Netzwerk, Unraid-System und optionale Toolbox) --- ## Für Hermes und andere KI-Agenten Dieses Repository enthält bereits den fertigen MUA-MCP. Ein Agent soll keinen zweiten Unraid-MCP entwickeln, sondern zuerst [`AGENTS.md`](AGENTS.md) und die kompakte [`Hermes-Anleitung`](docs/HERMES.md) lesen. Darin stehen Erkennung, direkte Registrierung, Secret-Behandlung, Tests und Rückbau vollständig. Kurzform für Hermes: ```bash hermes mcp add unraid \ --url http://UNRAID-IP:3002/mcp \ --auth header \ --connect-timeout 30 hermes mcp test unraid ``` Hermes fragt den MUA-API-Key verdeckt ab und speichert ihn außerhalb des Repositories. Läuft `/health` bereits erfolgreich, ist kein Build und keine erneute MUA-Installation nötig. --- ## Architektur ``` ┌─────────────────────────────────────────────────────────┐ │ Unraid (UNRAID-IP) │ │ │ │ /usr/local/bin/mua (kompiliertes Bun-Binary) │ │ ├── MCP-Server 0.0.0.0:3002 (Bearer-Auth) │ │ └── Config-Server 127.0.0.1:3013 (nur localhost) │ │ │ │ /etc/rc.d/rc.mua (SysVinit-Service) │ │ /boot/config/plugins/mua/mua.conf (API-Key + Tools) │ │ /usr/local/emhttp/plugins/mua/mua.page (WebGUI-Tab) │ └─────────────────────────────────────────────────────────┘ ▲ ▲ │ HTTP + Bearer-Token │ HTTP (localhost) │ │ ┌────────┴─────────┐ ┌────────┴─────────┐ │ MCP-Client │ │ Unraid WebGUI │ │ (Hermes, etc.) │ │ User Utilities → MUA │ └──────────────────┘ └──────────────────┘ ``` **Wichtig:** Der MCP-Endpunkt (Port 3002) ist **extern** erreichbar und braucht einen Bearer-Token. Der Config-Server (Port 3013) läuft **nur auf localhost** und verlangt zusätzlich einen bei jedem Start neu erzeugten Admin-Token. Die WebGUI schützt schreibende Formulare außerdem mit einem CSRF-Token. ## Sicherheitsmodell - Neuinstallationen starten im Profil **Nur Lesen**. Container-Steuerung, aktive Netzwerktests, Container-Umbauten und die Root-Shell sind aus. - Für Diagnosen steht `unraid_system_shell_readonly` bereit. Es startet nur fest freigegebene Leseprogramme als direkte Argumentliste, niemals über `/bin/sh`; Verkettungen, Pipes, Umleitungen und schreibende Optionen werden dadurch verhindert. Die freie Root-Shell bleibt separat und kritisch. - `none` bedeutet tatsächlich **keine Tools aktiv**; `all` ist ein expliziter Vollzugriff und wird in der GUI deutlich gewarnt. - Container-Umgebungswerte werden nie ausgegeben, nur ihre Variablennamen. - Häufige Secret-Formate in Logs werden zusätzlich redigiert. Logs können trotzdem Nutzdaten enthalten und sollten gezielt abgefragt werden. - Der API-Key erscheint nur unmittelbar nach seiner Erzeugung vollständig. - Tool-Aufrufe werden ohne Argumente oder Ausgaben in `/var/log/plugins/mua-audit.log` protokolliert. - Community-Applications-Installationen laufen immer über Suche, Vorschau und ein exakt an diese Änderung gebundenes, zehn Minuten gültiges Freigabeticket. Das Ergebnis bleibt über ein reguläres Unraid- Benutzertemplate vollständig in der Docker-GUI verwaltbar. - CORS ist standardmäßig aus. Requests sind auf 1 MiB, 120 pro Minute je Client und vier gleichzeitig laufende Werkzeuge begrenzt. Diese Grenzen lassen sich per Umgebungsvariable anpassen. --- ## Installation ### 1. Plugin installieren Über die Unraid-WebGUI: **Settings → Plugins → Community Plugins** → `MUA (Mikes Unraid Agent)` suchen und installieren. Oder manuell: ```bash # .txz von Gitea laden curl -O https://git.casaderoll.de/michael/MUA-Mikes-Unraid-Agent/raw/branch/main/dist/mua-2026.08.29.r027-x86_64-1.txz # Installieren upgradepkg --install-new mua-2026.08.29.r027-x86_64-1.txz ``` ### 2. Service starten ```bash /etc/rc.d/rc.mua start ``` Der Service startet automatisch bei jedem Boot (SysVinit). ### 3. Health-Check ```bash curl http://UNRAID-IP:3002/health # → {"status":"ok","version":"2026.08.24.r022","auth":"required"} ``` --- ## API-Key generieren (WebGUI) 1. **Settings → User Utilities → MUA** in der Unraid-WebGUI öffnen 2. Unter **„API-Key (Authentifizierung)"** auf **„Neuen API-Key generieren"** klicken 3. Den einmalig angezeigten Key kopieren (64-stellige Hex-Zeichenfolge) Der Key wird in `/boot/config/plugins/mua/mua.conf` gespeichert (chmod 600). > **Hinweis:** Der Key wird nur einmal angezeigt. Wenn du ihn verlierst, > generiere einen neuen — der alte funktioniert dann nicht mehr. --- ## MCP-Client konfigurieren MUA ist ein **Standard-MCP-Server** (Streamable HTTP, POST-only, JSON-RPC 2.0). Jeder MCP-Client kann es nutzen — URL + Bearer-Token reichen: ``` URL: http://UNRAID-IP:3002/mcp Auth: Authorization: Bearer ``` MUA läuft direkt auf Unraid und spricht **Streamable HTTP**. Ein SSH-Wrapper ist weder erforderlich noch empfohlen. Dadurch bleiben Verbindungen kompakt und routinemäßige Tool-Aufrufe erzeugen keine SSH-Anmeldungen im Unraid-Syslog. ### Beispiel: Hermes Agent Hermes bindet MUA direkt per HTTP an. Wenn MCPHub eingesetzt wird, zeigt Hermes stattdessen auf die vom Hub veröffentlichte Route; MCPHub verbindet sich dann direkt mit diesem MUA-Endpunkt. ```yaml # Direkte Anbindung ohne MCPHub mcp_servers: unraid: url: http://UNRAID-IP:3002/mcp headers: Authorization: Bearer timeout: 1800 connect_timeout: 30 enabled: true ``` Bei einer zentralen MCPHub-Installation wird dieselbe URL einmalig im Hub registriert. Alle Clients verwenden anschließend die Hub-Route und benötigen keine eigene SSH- oder MUA-Konfiguration. ### Beispiel: Direkter HTTP-Test (curl) ```bash # Health-Check (ohne Auth) curl http://UNRAID-IP:3002/health # MCP-Initialisierung (mit Auth) curl -X POST http://UNRAID-IP:3002/mcp \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-03-26","capabilities":{},"clientInfo":{"name":"test","version":"1.0"}}}' # Tool-Liste curl -X POST http://UNRAID-IP:3002/mcp \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}' # Tool aufrufen curl -X POST http://UNRAID-IP:3002/mcp \ -H "Authorization: Bearer " \ -H "Content-Type: application/json" \ -H "Accept: application/json, text/event-stream" \ -d '{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"unraid_docker_list","arguments":{}}}' ``` ### Ohne API-Key → 401 ```bash curl -X POST http://UNRAID-IP:3002/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{}}' # → 401 Unauthorized ``` --- ## Tools aktivieren/deaktivieren (WebGUI) In **Settings → User Utilities → MUA** stehen vier Sicherheitsprofile bereit: - **Nur Lesen (empfohlen):** Status, Diagnose, Logs und Inventar - **Betrieb + Diagnose:** zusätzlich aktive Prüfungen und Start/Stop/Restart - **Alles sperren:** MCP bleibt erreichbar, bietet aber keine Werkzeuge an - **Vollzugriff:** einschließlich Container-Umbau und uneingeschränkter Root-Shell Zusätzlich kann jedes Werkzeug einzeln nach Risikostufe freigegeben werden: | Gruppe | Tools | |--------|-------| | **Docker (16)** | `unraid_docker_list`, `unraid_docker_inspect`, `unraid_docker_logs`, `unraid_docker_analyze_logs`, `unraid_docker_processes`, `unraid_docker_stats`, `unraid_docker_info`, `unraid_docker_update_status`, `unraid_docker_start`, `unraid_docker_stop`, `unraid_docker_restart`, `unraid_docker_create`, `unraid_docker_modify`, `unraid_docker_update`, `unraid_docker_update_verified_batch`, `unraid_docker_rebuild` | | **Community Applications (3)** | `unraid_ca_search`, `unraid_ca_install_preview`, `unraid_ca_install` | | **Netzwerk (6)** | `unraid_network_inventory`, `unraid_network_list`, `unraid_network_inspect`, `unraid_network_host_state`, `unraid_network_audit_tcp`, `unraid_network_lan_probe` | | **System (13)** | `unraid_system_health`, `unraid_storage_status`, `unraid_disk_health`, `unraid_notifications_list`, `unraid_shares_list`, `unraid_share_inspect`, `unraid_files_inventory`, `unraid_system_connection_test`, `unraid_system_shell_readonly`, `unraid_system_shell`, `unraid_system_job_start`, `unraid_system_job_status`, `unraid_system_job_cleanup` | Deaktivierte Tools werden vom MCP-Server gefiltert — sie erscheinen nicht in `tools/list` und können nicht aufgerufen werden (→ `ERROR: Tool disabled`). ### Optionaler Agent-Werkzeugcontainer MUA kann einen allgemeinen Werkzeugcontainer dynamisch über das Docker-Label `mike.ai.role=toolbox` erkennen. Sobald mindestens ein solcher Container existiert, wird in der WebGUI der Schalter **„Werkzeugcontainer für KI-Agenten bekanntgeben“** verfügbar. Fehlt das Label, bleibt er ausgegraut. Bei aktiviertem Schalter stellt MUA zwei eigene, dynamisch sichtbare Werkzeuge bereit: - `unraid_toolbox_status` erkennt den Container und prüft angefragte Programme wie `ffmpeg`, `ffprobe`, `yt-dlp` oder `mediainfo`. - `unraid_toolbox_exec` führt Befehle direkt darin aus und kann auf ausdrücklichen Auftrag fehlende Pakete dort installieren. Der Containername ist nicht fest in MUA eingebaut. Wird der Container ersetzt, genügt dasselbe Label am Nachfolger. Die Toolbox-Werkzeuge erscheinen in keinem MCP-Client, solange der Schalter aus ist oder kein passender Container existiert. Beispiel für Docker beziehungsweise DockerMan `ExtraParams`: ```text --label=mike.ai.role=toolbox ``` Bei freigegebenem Vollzugriff ist `unraid_system_shell` das direkte Terminal auf dem Unraid-Host. Agenten sollen es für normale Docker-, Datei- und Administrationsaufträge unmittelbar verwenden und weder den MUA-Quellcode untersuchen noch Befehle über ein lokales Client-Terminal weiterreichen. Das Werkzeug akzeptiert mehrzeilige Skripte bis 256 KiB und Laufzeiten bis 30 Minuten. Nur noch längere Arbeiten gehören in `unraid_system_job_start`. --- ## Service-Verwaltung | Aktion | Befehl | |--------|--------| | Starten | `/etc/rc.d/rc.mua start` | | Stoppen | `/etc/rc.d/rc.mua stop` | | Neu starten | `/etc/rc.d/rc.mua restart` | | Status | `/etc/rc.d/rc.mua status` | | Logs | `tail -f /var/log/plugins/mua.log` | ### Auto-Restart bei Update Das Binary prüft alle 30 s, ob sich das Binary auf Platte geändert hat (mtime + size). Wenn ja → `rc.mua restart` + sauber beenden. Der neue Prozess startet automatisch. Zusätzlich führt der POST-INSTALL-Hook im `.plg` nach jedem Update `rc.mua restart` aus. --- ## Konfiguration | Datei | Zweck | |-------|-------| | `/boot/config/plugins/mua/mua.conf` | API-Key + Tool-Filter (chmod 600) | | `/usr/local/emhttp/plugins/mua/mua.page` | WebGUI-Tab (PHP) | | `/etc/rc.d/rc.mua` | SysVinit-Service-Script | | `/usr/local/bin/mua` | Kompiliertes Bun-Binary | ### Config-Datei-Format (`mua.conf`) ```ini MUA_API_KEY=a1b2c3d4... MUA_ENABLED_TOOLS=unraid_docker_list,unraid_docker_inspect,unraid_network_list MUA_TOOLBOX_ENABLED=false ``` Sonderwerte: `all` aktiviert ausdrücklich alles, `none` deaktiviert alles. --- ## Entwicklung ### Voraussetzungen - [Bun](https://bun.sh) (Runtime + Build-Tool) - `xz` (für `.txz`-Packing) - `xmllint` (für `.plg`-Validierung) ### Build ```bash # TypeScript-Check bunx tsc --noEmit # Linux-Binary (für Unraid) bun build src/index.ts --compile --target=bun-linux-x64 --outfile dist/mua # macOS-Binary (für lokalen Test) bun build src/index.ts --compile --target=bun-darwin-arm64 --outfile dist/mua-mac # .txz packen (Version wird aus package.json gelesen) bash scripts/package.sh ``` ### Lokaler Test ```bash # Test-Setup (ohne Unraid) MUA_CONFIG_DIR=/tmp/mua-test MUA_PORT=3999 MUA_CONFIG_PORT=3998 ./dist/mua-mac # Health-Check curl http://127.0.0.1:3999/health # Config-Server curl http://127.0.0.1:3998/config ``` ### Versionierung Format: `YYYY.MM.DD.rNNN` (Release-Counter hinter Datum). Version in **allen** Dateien aktualisieren: - `package.json` - `src/helpers.ts` (`MUA_VERSION`) - `plugin/plugin.json` - `plugin/mua.plg` (Version + txzURL + CHANGES) - `mcp/server.php` - `mcp/helpers.php` Nach Build: **SHA256** im `.plg` aktualisieren: ```bash shasum -a 256 dist/mua-*.txz ``` ### Release-Prozess 1. Version erhöhen (alle Dateien) 2. `bunx tsc --noEmit` 3. `bun build src/index.ts --compile --target=bun-linux-x64 --outfile dist/mua` 4. `bash scripts/package.sh` 5. SHA256 im `.plg` aktualisieren 6. `xmllint --noout plugin/mua.plg` 7. `git add -A && git commit -m "rNNN: ..." && git push` 8. Auf Unraid: **Plugins → MUA → Update**