container_stats(container_name) calls SYNO.Docker.Container/stats, locates the entry by name (stripping the DSM-added leading slash), and reports: - CPU % (standard Docker formula: cpu_delta / system_delta * cpus * 100) - Memory used / limit (human-readable) - Network I/O rx / tx (summed across all interfaces) - Block I/O read / write (from io_service_bytes_recursive) Gracefully handles first-poll (precpu system_cpu_usage absent → 0%). 7 unit tests covering: found, CPU formula, memory format, slash-strip, not-found, API error, no-precpu fallback. rename_container removed: DSM Container Manager offers no rename API. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
7.9 KiB
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/<projektname>/ |
| 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 (17)
| 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, container_stats |
| Compose | read_compose, update_compose, update_image_tag, update_env_var |
| Images | check_image_updates, list_images, delete_image |
Bekannte Bugs
- Container-Name wird manchmal mit Hash-Präfix zurückgegeben (z.B.
f93cb8b504f7_jenkins) → Tritt auf wenn Service-Name in compose.yaml voncontainer_nameabweicht redeploy_projectschlägt mit DSM 2101/1202 fehl bei falschem Projektstatus → Workaround:stop_project+start_projectseparat oderdocker composeper SSH
Roadmap (geplante Erweiterungen)
Images
list_images– alle lokalen Images mit Größe, Tag, Erstellungsdatumdelete_image– nicht mehr benötigte Images löschenpull_image– Image manuell aus Registry ziehen
Container
– implementiertcontainer_stats– entfällt (DSM bietet kein Container-Umbenennen)rename_container
Netzwerke
list_networks– alle Docker-Netzwerke auflistencreate_network– neues Netzwerk anlegendelete_network– Netzwerk löschen
Volumes
list_volumes– alle Docker-Volumes auflistendelete_volume– verwaiste Volumes löscheninspect_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_projectvorschlagen - 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, methodlist - 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_idakzeptiertname:tagund Image-Hash- DSM API:
SYNO.Docker.Image, methoddelete - 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 ✅ erledigt
container_stats ✅
- Signatur:
container_stats(container_name: str) -> str - Ausgabe: CPU %, RAM verwendet/limit, Netzwerk I/O, Block I/O
- Confirmation: nein
rename_container – entfällt (DSM bietet kein Container-Umbenennen)
Gruppe 3 – System modules/system.py (neu) ✦ Prio: hoch
system_df
- DSM API:
SYNO.Docker.Systemoder 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, methodlist - 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, methodlist - 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, methodcreateoder 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, methodlist - Ausgabe: Name, URL, ob authentifiziert
- Confirmation: nein
Referenz für DSM API-Calls
cmeans/mcp-synology(GitHub) – Auth, Keyring, CLI-StrukturN4S4/synology-apidocker_api.py(GitHub) – SYNO.Docker.* API-Calls
Start
Beginne mit Gruppe 1 (list_images + delete_image).