Anpassungen

This commit is contained in:
2026-04-13 17:55:08 +02:00
parent 24c3059e83
commit 0b48190f99
2 changed files with 225 additions and 70 deletions
+1
View File
@@ -0,0 +1 @@
reference/
+224 -70
View File
@@ -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/<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` |
---
## 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`).