243 lines
7.1 KiB
Markdown
243 lines
7.1 KiB
Markdown
# Projektspezifikation: mcp-synology-container
|
||
|
||
## Ziel
|
||
|
||
Ein MCP-Server (Model Context Protocol) für die Verwaltung von Docker-Projekten auf einer
|
||
Synology DiskStation via Container Manager. Der Server ermöglicht es Claude Desktop,
|
||
Container-Projekte direkt zu verwalten – inklusive Lesen und Bearbeiten von
|
||
`docker-compose.yml`-Dateien sowie Lifecycle-Management der Projekte und Container.
|
||
|
||
---
|
||
|
||
## Technologie-Stack
|
||
|
||
| Komponente | Entscheidung |
|
||
|---|---|
|
||
| Sprache | Python 3.12+ |
|
||
| Package Manager | `uv` |
|
||
| MCP Framework | `mcp` (Anthropic MCP SDK) |
|
||
| HTTP-Client | `httpx` |
|
||
| Credential Storage | OS-Keyring (`keyring` library) |
|
||
| Config Format | YAML |
|
||
| Logging | stderr only (kein File-Logging) |
|
||
|
||
---
|
||
|
||
## Projektstruktur
|
||
|
||
```
|
||
mcp-synology-container/
|
||
├── src/
|
||
│ └── mcp_synology_container/
|
||
│ ├── __init__.py
|
||
│ ├── cli.py # CLI-Einstiegspunkt: setup, check, serve
|
||
│ ├── config.py # Config laden/speichern (YAML)
|
||
│ ├── auth.py # Keyring-Integration, 2FA-Device-Token-Flow
|
||
│ ├── dsm_client.py # HTTP-Client gegen Synology DSM API
|
||
│ └── modules/
|
||
│ ├── __init__.py
|
||
│ ├── projects.py # SYNO.Docker.Project
|
||
│ ├── containers.py # SYNO.Docker.Container
|
||
│ ├── compose.py # Compose-Datei lesen/schreiben via FileStation API
|
||
│ └── images.py # SYNO.Docker.Image
|
||
├── tests/
|
||
│ ├── __init__.py
|
||
│ ├── test_config.py
|
||
│ ├── test_auth.py
|
||
│ └── test_modules/
|
||
│ ├── test_projects.py
|
||
│ ├── test_containers.py
|
||
│ ├── test_compose.py
|
||
│ └── test_images.py
|
||
├── docs/
|
||
│ ├── setup.md
|
||
│ └── tools.md
|
||
├── pyproject.toml
|
||
├── README.md
|
||
└── CHANGELOG.md
|
||
```
|
||
|
||
---
|
||
|
||
## pyproject.toml
|
||
|
||
```toml
|
||
[project]
|
||
name = "mcp-synology-container"
|
||
version = "0.1.0"
|
||
description = "MCP server for Synology Container Manager"
|
||
requires-python = ">=3.12"
|
||
dependencies = [
|
||
"mcp>=1.0.0",
|
||
"httpx>=0.27.0",
|
||
"pyyaml>=6.0",
|
||
"keyring>=25.0.0",
|
||
"click>=8.1.0",
|
||
"rich>=13.0.0",
|
||
]
|
||
|
||
[project.scripts]
|
||
mcp-synology-container = "mcp_synology_container.cli:main"
|
||
|
||
[build-system]
|
||
requires = ["hatchling"]
|
||
build-backend = "hatchling.build"
|
||
```
|
||
|
||
---
|
||
|
||
## Konfigurationsdatei
|
||
|
||
Pfad: `~/.config/mcp-synology-container/config.yaml`
|
||
|
||
```yaml
|
||
schema_version: 1
|
||
alias: HomeNAS # optionaler Anzeigename in Claude Desktop
|
||
connection:
|
||
host: dsm.gecheckt.de
|
||
port: 443
|
||
https: true
|
||
verify_ssl: true
|
||
compose_base_path: /volume1/docker # Basis-Pfad für alle Compose-Projekte auf der NAS
|
||
```
|
||
|
||
Credentials (Host, Username, Password, optional Device-Token für 2FA) werden
|
||
**nicht** in der Config-Datei gespeichert, sondern ausschließlich im OS-Keyring.
|
||
|
||
**Credential-Auflösungsreihenfolge:**
|
||
1. Umgebungsvariablen (`SYNOLOGY_HOST`, `SYNOLOGY_USERNAME`, `SYNOLOGY_PASSWORD`)
|
||
2. Config-Datei (nur nicht-sensitive Werte)
|
||
3. OS-Keyring (Credentials)
|
||
|
||
---
|
||
|
||
## CLI-Befehle
|
||
|
||
### `mcp-synology-container setup`
|
||
|
||
Interaktiver Setup-Wizard:
|
||
1. Fragt Host, Port, HTTPS, Benutzername, Passwort ab
|
||
2. Prüft ob 2FA aktiv ist – wenn ja: OTP abfragen, Device-Token speichern
|
||
3. Speichert Credentials im OS-Keyring
|
||
4. Schreibt `config.yaml`
|
||
5. Gibt fertiges Claude-Desktop-Config-Snippet aus:
|
||
|
||
```json
|
||
{
|
||
"mcpServers": {
|
||
"synology-container": {
|
||
"command": "mcp-synology-container",
|
||
"args": ["serve"]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### `mcp-synology-container check`
|
||
|
||
- Lädt Config und Credentials
|
||
- Stellt Testverbindung zur DSM API her
|
||
- Gibt Verbindungsstatus, DSM-Version und verfügbare APIs aus
|
||
- Exit-Code 0 = OK, 1 = Fehler
|
||
|
||
### `mcp-synology-container serve`
|
||
|
||
- Startet den MCP-Server im stdio-Modus
|
||
- Registriert alle Tools
|
||
- Läuft bis SIGTERM/SIGINT
|
||
|
||
---
|
||
|
||
## MCP-Tools
|
||
|
||
### Projekte (`projects.py`)
|
||
|
||
| Tool | Beschreibung | Confirmation required |
|
||
|---|---|---|
|
||
| `list_projects` | Alle Container-Manager-Projekte mit Status auflisten | nein |
|
||
| `get_project_status` | Detaillierten Status eines Projekts abrufen | nein |
|
||
| `start_project` | Projekt starten | nein |
|
||
| `stop_project` | Projekt stoppen | **ja** |
|
||
| `redeploy_project` | Projekt neu deployen (pull + down + up) | **ja** |
|
||
|
||
**Redeploy-Ablauf:**
|
||
1. Compose-Datei lesen
|
||
2. `docker compose pull` (neues Image ziehen)
|
||
3. `docker compose down`
|
||
4. `docker compose up -d`
|
||
5. Deploy-Output streamen und zurückgeben
|
||
|
||
### Container (`containers.py`)
|
||
|
||
| Tool | Beschreibung | Confirmation required |
|
||
|---|---|---|
|
||
| `list_containers` | Alle Container eines Projekts auflisten | nein |
|
||
| `get_container_status` | Status, Uptime, Ressourcennutzung eines Containers | nein |
|
||
| `get_container_logs` | Log-Ausgabe abrufen (mit optionalem `tail`-Parameter) | nein |
|
||
| `exec_in_container` | Befehl in laufendem Container ausführen | **ja** |
|
||
|
||
### Compose-Datei (`compose.py`)
|
||
|
||
Compose-Dateien liegen unter `{compose_base_path}/{projektname}/docker-compose.yml`
|
||
(oder `compose.yml` – beide Varianten werden erkannt).
|
||
|
||
| Tool | Beschreibung | Confirmation required |
|
||
|---|---|---|
|
||
| `read_compose` | Compose-Datei eines Projekts lesen | nein |
|
||
| `update_image_tag` | Image-Tag eines Services aktualisieren | **ja** |
|
||
| `update_env_var` | Umgebungsvariable eines Services hinzufügen oder ändern | **ja** |
|
||
| `update_compose` | Beliebige Änderung an der Compose-Datei (vollständiger neuer Inhalt) | **ja** |
|
||
|
||
**Wichtig:** Nach Änderungen an der Compose-Datei schlägt der Server automatisch vor,
|
||
das Projekt neu zu deployen (`redeploy_project`).
|
||
|
||
### Images (`images.py`)
|
||
|
||
| Tool | Beschreibung | Confirmation required |
|
||
|---|---|---|
|
||
| `check_image_updates` | Verfügbare Updates für alle Images eines Projekts prüfen | nein |
|
||
|
||
---
|
||
|
||
## Authentifizierung & Session-Management
|
||
|
||
- Login via `SYNO.API.Auth` (DSM Web API)
|
||
- Session-Token wird in-memory gehalten (kein persistentes Speichern)
|
||
- Automatischer Re-Login bei abgelaufener Session (401-Response)
|
||
- 2FA: Device-Token-Flow
|
||
- Device-Token wird im OS-Keyring gespeichert
|
||
- Kein OTP-Prompt im laufenden Betrieb
|
||
- Re-Bootstrap via `setup` wenn Token revoked
|
||
|
||
---
|
||
|
||
## DSM API-Endpunkte
|
||
|
||
| Funktion | API |
|
||
|---|---|
|
||
| Auth | `SYNO.API.Auth` |
|
||
| Projekte | `SYNO.Docker.Project` (list, start, stop, start_stream) |
|
||
| Container | `SYNO.Docker.Container` (list, start, stop, logs) |
|
||
| Container exec | `SYNO.Docker.Container` (exec) |
|
||
| Images | `SYNO.Docker.Image` (list) |
|
||
| Compose-Dateien lesen | `SYNO.FileStation.Download` |
|
||
| Compose-Dateien schreiben | `SYNO.FileStation.Upload` |
|
||
|
||
---
|
||
|
||
## Sicherheitsregeln
|
||
|
||
- Credentials niemals in Config-Datei, nur im OS-Keyring
|
||
- Confirmation-Pflicht für alle destruktiven Operationen (stop, redeploy, exec, compose-update)
|
||
- HTTPS mit Zertifikatsvalidierung standardmäßig aktiv (`verify_ssl: true`)
|
||
- Keine Secrets in stderr-Ausgaben
|
||
|
||
---
|
||
|
||
## Referenzprojekte (zur Orientierung bei der Implementierung)
|
||
|
||
| Projekt | Zweck |
|
||
|---|---|
|
||
| `cmeans/mcp-synology` (GitHub) | Referenz für Auth-Flow, Keyring-Integration, CLI-Struktur, Config-System |
|
||
| `N4S4/synology-api` `docker_api.py` (GitHub) | Referenz für DSM API-Calls (SYNO.Docker.*) |
|