383 lines
14 KiB
Markdown
383 lines
14 KiB
Markdown
# 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.09.21.r029-x86_64-1.txz
|
|
|
|
# Installieren
|
|
upgradepkg --install-new mua-2026.09.21.r029-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 <dein-api-key>
|
|
```
|
|
|
|
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 <dein-api-key>
|
|
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 <dein-api-key>" \
|
|
-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 <dein-api-key>" \
|
|
-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 <dein-api-key>" \
|
|
-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
|
|
|
|
Die PHP-Statushelper lassen sich unabhängig vom laufenden MUA-Dienst testen
|
|
(PHP 8 erforderlich):
|
|
|
|
```bash
|
|
php scripts/test-notifications.php
|
|
php scripts/test-docker-update-status.php
|
|
```
|
|
|
|
Der Benachrichtigungsparser liest auch mehrzeilige URBM-Meldungen und erhält
|
|
Text wörtlich, ohne INI-Variablen wie `${HOME}` auszuwerten.
|
|
|
|
```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**
|