Add isolated Navidrome MCP service

This commit is contained in:
Mikei386
2026-08-23 15:06:32 +02:00
parent fea4a83582
commit 9ccb23cc5e
9 changed files with 108 additions and 3 deletions
+1 -1
View File
@@ -747,7 +747,7 @@ services:
# Seed native MCP connections on a fresh Open WebUI database. Secrets
# stay inside the tool containers, so these internal URLs need no keys.
TOOL_SERVER_CONNECTIONS: >-
[{"url":"http://mike-ai-mcp-web:8000/mcp","path":"","type":"mcp","auth_type":"none","headers":null,"key":"","config":{"enable":true,"access_grants":[]},"info":{"id":"web-local","name":"Web (öffentlich, read-only)","description":"Für aktuelle öffentliche Internetdaten, Quellenprüfung, GitHub/Hugging Face und Produktsuche. Nicht für Home Assistant, Medienverwaltung oder NAS-Diagnose."}},{"url":"http://mike-ai-mcp-homeassistant:8000/mcp","path":"","type":"mcp","auth_type":"none","headers":null,"key":"","config":{"enable":true,"access_grants":[]},"info":{"id":"homeassistant-local","name":"Home Assistant (lokal)","description":"Für Home-Assistant-Entitäten, Zustände, Historie, Automationen, Dashboards, HA-Diagnose und freigegebene YAML-Dateien. YAML-Lesen ist begrenzt; Änderungen benötigen serverseitige Vorschau, explizite Freigabe, Sicherung und Validierung. Nicht für Unraid, Sonarr/Radarr oder allgemeine Websuche."}},{"url":"http://mike-ai-mcp-arr:8000/mcp","path":"","type":"mcp","auth_type":"none","headers":null,"key":"","config":{"enable":true,"access_grants":[]},"info":{"id":"arr-local","name":"Sonarr und Radarr (lokal)","description":"Nur für verwaltete Serien/Filme, fehlende Episoden, Queue und Suche über konfigurierte Indexer. Keine allgemeine Websuche; Schreibaktionen benötigen Vorschau und Freigabe."}},{"url":"http://mike-ai-mcp-unraid-official:8000/mcp","path":"","type":"mcp","auth_type":"none","headers":null,"key":"","config":{"enable":true,"access_grants":[]},"info":{"id":"unraid-readonly-local","name":"Unraid (Systemdiagnose)","description":"Nur für Unraid-Host, Array, Datenträger, Docker-Container, Shares, Netzwerk, UPS und Systemlogs. Nicht für Home Assistant oder Medieninhalte; Standardzugriff read-only."}}]
[{"url":"http://mike-ai-mcp-web:8000/mcp","path":"","type":"mcp","auth_type":"none","headers":null,"key":"","config":{"enable":true,"access_grants":[]},"info":{"id":"web-local","name":"Web (öffentlich, read-only)","description":"Für aktuelle öffentliche Internetdaten, Quellenprüfung, GitHub/Hugging Face und Produktsuche. Nicht für Home Assistant, Medienverwaltung oder NAS-Diagnose."}},{"url":"http://mike-ai-mcp-homeassistant:8000/mcp","path":"","type":"mcp","auth_type":"none","headers":null,"key":"","config":{"enable":true,"access_grants":[]},"info":{"id":"homeassistant-local","name":"Home Assistant (lokal)","description":"Für Home-Assistant-Entitäten, Zustände, Historie, Automationen, Dashboards, HA-Diagnose und freigegebene YAML-Dateien. YAML-Lesen ist begrenzt; Änderungen benötigen serverseitige Vorschau, explizite Freigabe, Sicherung und Validierung. Nicht für Unraid, Sonarr/Radarr oder allgemeine Websuche."}},{"url":"http://mike-ai-mcp-arr:8000/mcp","path":"","type":"mcp","auth_type":"none","headers":null,"key":"","config":{"enable":true,"access_grants":[]},"info":{"id":"arr-local","name":"Sonarr und Radarr (lokal)","description":"Nur für verwaltete Serien/Filme, fehlende Episoden, Queue und Suche über konfigurierte Indexer. Keine allgemeine Websuche; Schreibaktionen benötigen Vorschau und Freigabe."}},{"url":"http://mike-ai-mcp-navidrome:3000/mcp","path":"","type":"mcp","auth_type":"none","headers":null,"key":"","config":{"enable":true,"access_grants":[]},"info":{"id":"navidrome-local","name":"Navidrome (Musikbibliothek)","description":"Nur für die persönliche Navidrome-Musikbibliothek: Titel, Alben, Künstler, Playlists, Favoriten und Hörverlauf. Nicht für Sonarr/Radarr, allgemeine Websuche oder Audioausgabe auf dem KI-Host. Wegen des großen Werkzeugkatalogs nur bei Musikaufgaben aktivieren."}},{"url":"http://mike-ai-mcp-unraid-official:8000/mcp","path":"","type":"mcp","auth_type":"none","headers":null,"key":"","config":{"enable":true,"access_grants":[]},"info":{"id":"unraid-readonly-local","name":"Unraid (Systemdiagnose)","description":"Nur für Unraid-Host, Array, Datenträger, Docker-Container, Shares, Netzwerk, UPS und Systemlogs. Nicht für Home Assistant oder Medieninhalte; Standardzugriff read-only."}}]
DO_NOT_TRACK: "true"
SCARF_NO_ANALYTICS: "true"
dns: ["${AI_DNS:-1.1.1.1}"]
+5
View File
@@ -0,0 +1,5 @@
# Root-only deployment secret. Copy to /etc/mike-ai/navidrome-mcp.env,
# replace the two placeholders and chmod 600. Never commit the real file.
NAVIDROME_URL=http://192.168.1.2:4533
NAVIDROME_USERNAME=REPLACE_WITH_DEDICATED_USER
NAVIDROME_PASSWORD=REPLACE_WITH_DEDICATED_PASSWORD
+2
View File
@@ -145,6 +145,7 @@ Allzweck-MCP mit sämtlichen Zugangsdaten.
Open WebUI ── internes Netz ───────────┬── web-mcp
├── home-assistant-mcp
├── arr-mcp
├── navidrome-mcp
└── unraid-mcp-read
Hermes Agent ─ WireGuard ─┐
@@ -158,6 +159,7 @@ weitere MCP-Clients ──────┴── mcp-gateway (später) ── das
| `home-assistant-mcp-write` | kontrollierte HA-Änderungen | Preview/Approval |
| `arr-mcp-read` | Sonarr/Radarr-Status und Releasesuche | nur lesen |
| `arr-mcp-write` | Suche fehlender Episoden über Sonarr-Indexer | Preview/Approval; Monitoring unverändert |
| `navidrome-mcp` | Musikbibliothek, Suche, Playlists, Favoriten, Hörverlauf | eigener Navidrome-Benutzer; gezielt aktivieren |
| `unraid-mcp-read` | System-, Container- und begrenzte Logdiagnose | nur lesen |
| `unraid-mcp-admin` | eng definierte Verwaltungsaktionen | bewusst aktivieren |
| `sandbox-mcp` | temporäre Code- und Dateiarbeit | isolierter Arbeitsraum |
+1
View File
@@ -10,6 +10,7 @@
| Web-MCP-Fassade | `platform/web-search/web_search_mcp.py` | eigener Container | Kern |
| Home-Assistant-MCP | HA-Endpunkt plus lokaler Relay | eigener optionaler Container | optional |
| ARR-MCP | `arr-mcp` 1.0.1 plus dokumentierter Sonarr-Patch | eigener optionaler Container | optional |
| Navidrome-MCP | Blakeem/Navidrome-MCP 2.2.0, Image per OCI-Digest | eigener optionaler Container ohne mpv | optional |
| Unraid-MCP | lokales `runraid`-Binary | eigener optionaler Container | optional |
| Whisper | ggml-org/whisper.cpp | Service im Router-Deploy | optional |
| XTTS-v2 | Coqui, offizielles CUDA-12.1-Image per Digest | RTX-3060-Container, Stimme `Annmarie Nele`, CPML | Kern |
+1
View File
@@ -161,6 +161,7 @@ vorhanden ist:
```text
/etc/mike-ai/homeassistant-admin-mcp.env
/etc/mike-ai/arr-mcp.env
/etc/mike-ai/navidrome-mcp.env
/etc/mike-ai/runraid/.env
/usr/local/bin/runraid Version 0.4.2
```
+28
View File
@@ -13,6 +13,7 @@ Prompts heraus, verhindert den früher beobachteten Kontextverbrauch von über
| `mcp-web` | `http://mike-ai-mcp-web:8000/mcp` | kompakte Websuche und Quellenvergleich | an |
| `mcp-homeassistant` | `http://mike-ai-mcp-homeassistant:8000/mcp` | Relay zum nativen HA-MCP; Token bleibt serverseitig | Profil `homeassistant` |
| `mcp-arr` | `http://mike-ai-mcp-arr:8000/mcp` | Sonarr/Radarr/Prowlarr mit serverseitiger Policy | Profil `arr` |
| `mcp-navidrome` | `http://mike-ai-mcp-navidrome:3000/mcp` | Navidrome-Bibliothek, Suche, Playlists, Favoriten und Hörverlauf | Profil `navidrome` |
| `mcp-unraid-official` | `http://mike-ai-mcp-unraid-official:8000/mcp` | offizieller, read-only begrenzter Unraid-Zugang | Profil `unraid` |
| `mcp-unraid-ssh` | `http://mike-ai-mcp-unraid-ssh:8000/mcp` | erweiterte Diagnose über einen erzwungenen SSH-Befehl | optional (`extended`) |
@@ -55,6 +56,7 @@ passenden Server wählen:
| Aktuelle öffentliche Informationen, Quellen, GitHub/Hugging Face, Produkte | Web | HA, ARR, Unraid |
| Entitäten, Zustände, Historie, Automationen und Dashboards | Home Assistant | Web, Unraid |
| Serien, Filme, fehlende Episoden und Indexer-Releases | Sonarr und Radarr | Web |
| Persönliche Musikbibliothek, Titel, Alben, Künstler und Playlists | Navidrome | Web, ARR |
| Lesende NAS-, Docker-, Array-, Netzwerk- und Logdiagnose | Unraid (Systemdiagnose) | MUA |
| Ausdrücklich benötigte MUA-Verwaltungsaktion | MUA | Unraid-Diagnose nicht parallel |
@@ -95,6 +97,7 @@ Die lokale Installation benötigt die vorhandenen Secret-Dateien:
```text
/etc/mike-ai/homeassistant-admin-mcp.env
/etc/mike-ai/arr-mcp.env
/etc/mike-ai/navidrome-mcp.env
/etc/mike-ai/runraid/.env
```
@@ -106,6 +109,31 @@ TinySearch speichert sein lokales Embedding-Modell in einem Docker-Volume.
Nach einer Erstinstallation wird das Modell einmalig im Container mit
`tinysearch setup` geladen. Das Volume bleibt bei Containerupdates erhalten.
## Navidrome
Der Navidrome-MCP basiert auf `Blakeem/Navidrome-MCP` 2.2.0; das amd64-Image
ist per OCI-Digest festgeschrieben. Der Container veröffentlicht keinen
Host-Port, besitzt keinen Dateizugriff auf die Musikbibliothek und enthält
bewusst kein `mpv`. Er kann daher nicht auf Athena selbst Musik wiedergeben.
Navidrome sollte einen eigenen normalen Benutzer `mcp` erhalten. Dessen
Zugangsdaten liegen ausschließlich in der root-only Datei
`/etc/mike-ai/navidrome-mcp.env`; die Vorlage steht unter
`config/navidrome-mcp.env.example`. Anschließend genügt:
```bash
sudo install -m 0600 config/navidrome-mcp.env.example /etc/mike-ai/navidrome-mcp.env
sudoedit /etc/mike-ai/navidrome-mcp.env
sudo platform/mcp/install-tools.sh
sudo platform/openwebui/install-filters.sh
```
Der Upstream-Server stellt ohne Playback noch immer über 40 Werkzeuge bereit.
Darum wird Navidrome **nicht** als Standardwerkzeug an jedes Modellprofil
gehängt. Es wird in OpenWebUI nur für konkrete Musikaufgaben ausgewählt und
danach wieder ausgeschaltet. Schreibende Funktionen wie Playlist-Änderungen,
Favoriten und Bewertungen wirken unmittelbar im Konto des MCP-Benutzers.
## Client-Auswahl
Werkzeuge werden nicht pauschal an jedes Modell gehängt. Für Home-Assistant-
+23
View File
@@ -111,6 +111,29 @@ services:
- ${ARR_RADARR_PATCH:-./patches/mcp_radarr.py}:/usr/local/lib/python3.13/site-packages/arr_mcp/mcp/mcp_radarr.py:ro
networks: [tools, egress]
mcp-navidrome:
<<: *tool-common
# Version and amd64 manifest are pinned. The image contains no mpv, so it
# cannot play audio on the headless AI host and does not expose playback
# controls. It talks to Navidrome only through its authenticated API.
image: ghcr.io/blakeem/navidrome-mcp:2.2.0@sha256:047f911a5a8f7cc8f185bb4d6e7ca6c435542edefff4694a00c2f718ab0ee7f5
container_name: mike-ai-mcp-navidrome
profiles: [navidrome]
env_file:
- ${NAVIDROME_MCP_ENV_FILE:-/etc/mike-ai/navidrome-mcp.env}
environment:
MCP_TRANSPORT: http
MCP_HTTP_EXPOSE: "true"
MCP_HTTP_PORT: "3000"
# The endpoint is not published on the host. Host filtering still makes
# accidental access from any other Docker name fail closed.
MCP_HTTP_ALLOWED_HOSTS: "mike-ai-mcp-navidrome:3000,mike-ai-mcp-navidrome"
WEBUI_ENABLED: "false"
tmpfs:
- /tmp:rw,noexec,nosuid,nodev,size=64m
- /config:rw,noexec,nosuid,nodev,size=4m,mode=0700
networks: [tools, egress]
mcp-unraid-official:
<<: *tool-common
image: debian:13-slim
+5
View File
@@ -28,6 +28,11 @@ if [[ -s /etc/mike-ai/arr-mcp.env ]]; then
else
echo "ARR bleibt aus: Secret-Datei fehlt."
fi
if [[ -s /etc/mike-ai/navidrome-mcp.env ]]; then
profiles+=(--profile navidrome)
else
echo "Navidrome bleibt aus: Secret-Datei fehlt."
fi
if [[ -s /etc/mike-ai/runraid/.env && -x /usr/local/bin/runraid ]]; then
profiles+=(--profile unraid)
else
+42 -2
View File
@@ -35,14 +35,17 @@ backup=$volume_path/webui.db.before-filter-install-$stamp
cp -a "$db" "$backup"
rm -f "$volume_path/webui.db-wal" "$volume_path/webui.db-shm"
python3 - "$db" "$FILTER_DIR" "$ACTION_DIR" "${OPENWEBUI_FILTER_OWNER_ID:-}" <<'PY'
navidrome_enabled=false
[[ -s /etc/mike-ai/navidrome-mcp.env ]] && navidrome_enabled=true
python3 - "$db" "$FILTER_DIR" "$ACTION_DIR" "${OPENWEBUI_FILTER_OWNER_ID:-}" "$navidrome_enabled" <<'PY'
import json
import pathlib
import sqlite3
import sys
import time
db, filter_dir, action_dir, requested_owner = sys.argv[1:]
db, filter_dir, action_dir, requested_owner, navidrome_enabled_raw = sys.argv[1:]
navidrome_enabled = navidrome_enabled_raw.lower() == "true"
con = sqlite3.connect(db)
columns = {row[1] for row in con.execute("pragma table_info(function)")}
required = {
@@ -182,6 +185,13 @@ with con:
"Verwaltungsaktionen. Für reine Statusabfragen und Diagnosen stattdessen "
"Unraid (Systemdiagnose) verwenden; niemals beide parallel ausprobieren.",
),
"navidrome-local": (
"Navidrome (Musikbibliothek)",
"Nur für die persönliche Navidrome-Musikbibliothek: Titel, Alben, Künstler, "
"Playlists, Favoriten und Hörverlauf. Nicht für Sonarr/Radarr, allgemeine "
"Websuche oder Audioausgabe auf dem KI-Host. Wegen des großen Werkzeugkatalogs "
"nur bei Musikaufgaben aktivieren.",
),
}
changed = False
for connection in connections:
@@ -203,6 +213,8 @@ with con:
match = "homeassistant-local"
elif "mike-ai-mcp-arr" in url:
match = "arr-local"
elif "mike-ai-mcp-navidrome" in url:
match = "navidrome-local"
elif "mike-ai-mcp-unraid-official" in url:
match = "unraid-readonly-local"
else:
@@ -212,6 +224,34 @@ with con:
info["name"] = name
info["description"] = description
changed = True
if navidrome_enabled and not any(
isinstance(connection, dict)
and (
str(connection.get("url", "")).lower()
== "http://mike-ai-mcp-navidrome:3000/mcp"
or str((connection.get("info") or {}).get("id", "")).lower()
== "navidrome-local"
)
for connection in connections
):
name, description = descriptions["navidrome-local"]
connections.append(
{
"url": "http://mike-ai-mcp-navidrome:3000/mcp",
"path": "",
"type": "mcp",
"auth_type": "none",
"headers": None,
"key": "",
"config": {"enable": True, "access_grants": []},
"info": {
"id": "navidrome-local",
"name": name,
"description": description,
},
}
)
changed = True
if changed:
con.execute(
"""