# mcp-synology-container ## Kontext Dieses Projekt entwickelt und betreibt `mcp-synology-container` – einen MCP-Server für die vollständige Verwaltung von Docker-Projekten auf einer Synology DiskStation via Container Manager. Der MCP-Server ist in Claude Desktop aktiv verbunden. --- ## Infrastruktur | | | |---|---| | **NAS** | `https://dsm.gecheckt.de` (Split-DNS, intern direkt aufgelöst) | | **Compose-Pfade** | `/volume1/docker//` | | **Gitea** | `https://gitea.gecheckt.de/marcus/mcp-synology-container` | | **Lokaler Code** | `D:\Dev\Projects\mcp-synology-container` | | **Sprache** | Python 3.12+, `uv`, MCP SDK, `httpx`, `keyring`, `click`, `rich` | --- ## Deploy-Workflow (nach jeder Code-Änderung) ``` 1. Claude Code committet und pusht 2. uv tool install --reinstall git+https://gitea.gecheckt.de/marcus/mcp-synology-container.git 3. Claude Desktop neu starten (Tray-Icon → Quit → neu starten) ``` --- ## Aktueller Stand ### Implementierte Tools (14) | Kategorie | Tools | |---|---| | Projekte | `list_projects`, `get_project_status`, `start_project`, `stop_project`, `redeploy_project` | | Container | `list_containers`, `get_container_status`, `get_container_logs`, `exec_in_container` | | Compose | `read_compose`, `update_compose`, `update_image_tag`, `update_env_var` | | Images | `check_image_updates` | ### Bekannte Bugs - Container-Name wird manchmal mit Hash-Präfix zurückgegeben (z.B. `f93cb8b504f7_jenkins`) → Tritt auf wenn Service-Name in compose.yaml von `container_name` abweicht - `redeploy_project` schlägt mit DSM 2101/1202 fehl bei falschem Projektstatus → Workaround: `stop_project` + `start_project` separat oder `docker compose` per SSH --- ## Roadmap (geplante Erweiterungen) ### Images - `list_images` – alle lokalen Images mit Größe, Tag, Erstellungsdatum - `delete_image` – nicht mehr benötigte Images löschen - `pull_image` – Image manuell aus Registry ziehen ### Container - `container_stats` – Live CPU/RAM-Verbrauch pro Container - `rename_container` – Container umbenennen ### Netzwerke - `list_networks` – alle Docker-Netzwerke auflisten - `create_network` – neues Netzwerk anlegen - `delete_network` – Netzwerk löschen ### Volumes - `list_volumes` – alle Docker-Volumes auflisten - `delete_volume` – verwaiste Volumes löschen - `inspect_volume` – Volume-Details anzeigen ### System - `system_df` – Docker Disk Usage (Images, Container, Volumes) - `system_prune` – Aufräumen (dangling Images, gestoppte Container) ### Registries - `list_registries` – konfigurierte Registries anzeigen --- ## NAS – Laufende Container (Stand April 2026) | Container | Image | Status | |---|---|---| | `jenkins` | `jenkins/jenkins:2.558-jdk21` | running | | `openwebui` | `ghcr.io/open-webui/open-webui:v0.8.10` | running | | `frostiq-gitea` | `gitea/gitea:1.25.4` | running | | `frostiq-wildfly` | `frostiq/wildfly:39.0.0.Final-jdk21-pg` | running | | `bookstack` | `linuxserver/bookstack:latest` | running | | `bookstack-mariadb` | `mariadb:11.8` | running | | `homeassistant` | `homeassistant/home-assistant:stable` | running | | `pgadmin` | `dpage/pgadmin4:latest` | running | | `postgres17` | `postgres:17.7` | running | | `synology_docviewer_1` | `synology/docviewer:1.3.0.0126` | stopped | | `synology_docviewer_2` | `synology/docviewer:1.3.0.0126` | stopped | --- ## Claude Code – Implementierungsregeln - Confirmation vor destruktiven Operationen: `stop_project`, `redeploy_project`, `exec_in_container`, `update_image_tag`, `update_env_var`, `update_compose` - Nach Compose-Änderungen: `redeploy_project` vorschlagen - Fehlerbehandlung: DSM-Fehler als verständliche Meldung zurückgeben, keine Stacktraces - Keine Secrets in stderr-Ausgaben - Type Hints und Docstrings konsequent verwenden - Formatter: `ruff format`, Linter: `ruff check`, Tests: `pytest` - Alle Texte (Docstrings, Kommentare, README): Englisch --- ## Hintergrund Marcus ist Senior Software Engineer (Java, Jakarta EE). FrostIQ ist eines seiner größeren Projekte (Jenkins, WildFly, Gitea). Präferenz: State-of-the-Art, Best Practices, saubere Architektur. Automatisierung spart Zeit für die Familie. 🌱 --- ## Aktueller Auftrag (Stand April 2026) ### Rollenteilung - **Claude Code** – Implementierung + Unit Tests (pytest, gemockter DSM-Client) - **Marcus** – Deploy-Workflow (commit → push → install → Desktop-Neustart) - **Claude Chat** – Produkttest live gegen die NAS nach jedem Deploy ### Implementierungsreihenfolge Implementiere **eine Gruppe nach der anderen**. Commit + Push nach jeder Gruppe, dann Marcus Bescheid geben. --- #### Gruppe 1 – Images `modules/images.py` ✦ Prio: hoch **`list_images`** - DSM API: `SYNO.Docker.Image`, method `list` - Ausgabe: Name:Tag, Größe (human-readable), Erstellungsdatum, ob aktuell von einem Container verwendet - Sortierung: Größe absteigend - Confirmation: nein **`delete_image`** - Signatur: `delete_image(image_id: str, confirmed: bool = False) -> str` - `image_id` akzeptiert `name:tag` und Image-Hash - DSM API: `SYNO.Docker.Image`, method `delete` - Ohne `confirmed=True`: nur Preview, nicht löschen - Fehler wenn Image von laufendem Container verwendet → klare Meldung, kein Stacktrace - Erfolg: `Deleted nouchka/sqlite3:latest – 76 MiB freed` - Confirmation: **ja** --- #### Gruppe 2 – Container `modules/containers.py` ✦ Prio: mittel **`rename_container`** - Signatur: `rename_container(container_name: str, new_name: str, confirmed: bool = False) -> str` - DSM API: `SYNO.Docker.Container` rename (oder Docker Engine API direkt) - Hinweis nach Erfolg: compose.yml ggf. manuell anpassen (`container_name`) - Confirmation: **ja** **`container_stats`** - Signatur: `container_stats(container_name: str) -> str` - Ausgabe: CPU %, RAM verwendet/limit, Netzwerk I/O, Block I/O - Confirmation: nein --- #### Gruppe 3 – System `modules/system.py` (neu) ✦ Prio: hoch **`system_df`** - DSM API: `SYNO.Docker.System` oder Docker Engine `/system/df` - Ausgabe: Images (Anzahl, Gesamtgröße, reclaimable), Container, Volumes – tabellarisch - Confirmation: nein **`system_prune`** - Signatur: `system_prune(confirmed: bool = False) -> str` - Löscht: dangling Images, gestoppte Container, ungenutzte Netzwerke - Ohne `confirmed=True`: zeigt was gelöscht würde - Ausgabe: freigegebener Speicher - Confirmation: **ja** --- #### Gruppe 4 – Netzwerke `modules/networks.py` (neu) ✦ Prio: mittel **`list_networks`** - DSM API: `SYNO.Docker.Network`, method `list` - Ausgabe: Name, Driver, Subnet, angebundene Container - Confirmation: nein **`create_network`** - Signatur: `create_network(name: str, driver: str = "bridge", confirmed: bool = False) -> str` - Confirmation: **ja** **`delete_network`** - Signatur: `delete_network(name: str, confirmed: bool = False) -> str` - Fehler wenn Container angebunden → klare Meldung - Confirmation: **ja** --- #### Gruppe 5 – Volumes `modules/volumes.py` (neu) ✦ Prio: niedrig **`list_volumes`** - DSM API: `SYNO.Docker.Volume`, method `list` - Ausgabe: Name, Mountpoint, Größe, ob in Verwendung - Confirmation: nein **`inspect_volume`** - Signatur: `inspect_volume(volume_name: str) -> str` - Confirmation: nein **`delete_volume`** - Signatur: `delete_volume(volume_name: str, confirmed: bool = False) -> str` - Fehler wenn Volume gemountet → klare Meldung - Confirmation: **ja** --- #### Gruppe 6 – Images Ergänzung `modules/images.py` ✦ Prio: niedrig **`pull_image`** - Signatur: `pull_image(image: str) -> str` (z.B. `"postgres:17.8"`) - DSM API: `SYNO.Docker.Image`, method `create` oder pull-Endpunkt - Fortschritt streamen wenn möglich, sonst polling - Confirmation: nein --- #### Gruppe 7 – Registries `modules/registries.py` (neu) ✦ Prio: niedrig **`list_registries`** - DSM API: `SYNO.Docker.Registry`, method `list` - Ausgabe: Name, URL, ob authentifiziert - Confirmation: nein --- ### Referenz für DSM API-Calls - `cmeans/mcp-synology` (GitHub) – Auth, Keyring, CLI-Struktur - `N4S4/synology-api` `docker_api.py` (GitHub) – SYNO.Docker.* API-Calls ### Start Beginne mit **Gruppe 1** (`list_images` + `delete_image`).