diff --git a/.claudeignore b/.claudeignore new file mode 100644 index 0000000..10e83c6 --- /dev/null +++ b/.claudeignore @@ -0,0 +1 @@ +reference/ \ No newline at end of file diff --git a/CLAUDE.md b/CLAUDE.md index 718aac1..d0ff391 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,92 +1,246 @@ -# CLAUDE.md – Arbeitsanweisung für mcp-synology-container +# mcp-synology-container -## Deine Aufgabe +## Kontext -Implementiere das Projekt `mcp-synology-container` vollständig gemäß `SPEC.md`. - -Lies `SPEC.md` jetzt vollständig, bevor du anfängst. +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. --- -## Referenzmaterial +## Infrastruktur -Im Ordner `reference/` findest du zwei Referenzprojekte. Nutze sie aktiv: - -### `reference/cmeans/` -Geklontes Repo von `cmeans/mcp-synology` (GitHub). -Übernimm daraus die Implementierungsmuster für: -- Auth-Flow und 2FA-Device-Token-Flow (`auth.py`) -- OS-Keyring-Integration (`keyring` library) -- CLI-Struktur mit `click` (`cli.py`) -- Config laden/speichern mit YAML (`config.py`) -- Credential-Auflösungsreihenfolge (env vars → config → keyring) -- `setup`-Wizard mit `rich` für formatierte Ausgabe -- Generierung des Claude-Desktop-Config-Snippets - -Passe alle übernommenen Muster an unseren Use-Case an. -Kopiere keinen Code blind – verstehe ihn und adaptiere ihn. - -### `reference/n4s4/docker_api.py` -Einzelne Datei aus `N4S4/synology-api` (GitHub). -Nutze sie als Referenz für die konkreten DSM API-Calls: -- Wie `SYNO.Docker.Project` aufgerufen wird (list, start, stop) -- Wie `SYNO.Docker.Container` aufgerufen wird (list, logs, exec) -- Wie `SYNO.Docker.Image` aufgerufen wird (list) -- Welche Parameter und Response-Strukturen die APIs erwarten - -Implementiere **keinen** eigenen Wrapper um `synology-api` – -baue einen eigenen schlanken HTTP-Client in `dsm_client.py` mit `httpx`. +| | | +|---|---| +| **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` | --- -## Reihenfolge der Implementierung +## Deploy-Workflow (nach jeder Code-Änderung) -Arbeite in dieser Reihenfolge. Schließe jeden Schritt vollständig ab bevor du weitermachst: - -1. **Projektstruktur anlegen** – alle Ordner und leere `__init__.py`-Dateien, `pyproject.toml` -2. **`config.py`** – Config laden, speichern, validieren -3. **`auth.py`** – Keyring-Integration, Login gegen DSM API, 2FA-Device-Token-Flow -4. **`dsm_client.py`** – HTTP-Client mit Session-Management, Auto-Re-Login -5. **`cli.py`** – `setup`, `check`, `serve` Befehle -6. **`modules/projects.py`** – SYNO.Docker.Project Tools -7. **`modules/containers.py`** – SYNO.Docker.Container Tools -8. **`modules/compose.py`** – Compose-Datei lesen/schreiben via FileStation API -9. **`modules/images.py`** – SYNO.Docker.Image Tools -10. **Tests** – für jeden Schritt -11. **`README.md`** – Installationsanleitung und Tool-Übersicht -12. **`docs/setup.md`** und **`docs/tools.md`** +``` +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) +``` --- -## Wichtige Implementierungsregeln +## Aktueller Stand -- **Confirmation vor destruktiven Operationen:** `stop_project`, `redeploy_project`, - `exec_in_container`, `update_image_tag`, `update_env_var`, `update_compose` müssen - eine Bestätigung vom Nutzer einholen bevor sie ausgeführt werden. Nutze dafür den - MCP-eigenen `confirm`-Mechanismus. +### Implementierte Tools (14) -- **Nach Compose-Änderungen:** Immer automatisch `redeploy_project` vorschlagen. +| 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` | -- **Fehlerbehandlung:** Alle DSM API-Fehler sauber abfangen und als verständliche - Fehlermeldung zurückgeben. Keine Python-Stacktraces zum Nutzer. +### Bekannte Bugs -- **Keine Secrets in Logs:** Passwörter, Tokens und Session-IDs niemals in - stderr-Ausgaben schreiben. - -- **HTTPS:** `verify_ssl: true` ist der Standard. Nur auf expliziten Wunsch deaktivierbar. - -- **Compose-Pfade:** Beide Varianten erkennen – `docker-compose.yml` und `compose.yml`. - -- **Type Hints:** Konsequent in allen Funktionen verwenden. - -- **Docstrings:** Für alle öffentlichen Funktionen und Klassen. +- 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 --- -## Projekt-Konventionen +## Roadmap (geplante Erweiterungen) -- Sprache: Python 3.12+ -- Formatter: `ruff format` -- Linter: `ruff check` -- Tests: `pytest` +### 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`). \ No newline at end of file