Dokumente aktualisiert

This commit is contained in:
2026-04-16 11:11:48 +02:00
parent 0517241ee5
commit e76d80ece3
2 changed files with 255 additions and 485 deletions
+72 -75
View File
@@ -2,9 +2,9 @@
## Kontext
Dieses Projekt entwickelt `mcp-familywall` einen MCP-Server für den Lesezugriff
auf Family Wall (familywall.com). Der MCP-Server läuft lokal und wird in Claude Desktop
eingebunden.
Dieses Projekt entwickelt `mcp-familywall` einen MCP-Server für den
Zugriff auf Family Wall (familywall.com). Der MCP-Server läuft lokal
und wird in Claude Desktop eingebunden.
## Infrastruktur
@@ -20,48 +20,33 @@ eingebunden.
## Deploy-Workflow (nach jeder Code-Änderung)
1. Claude Code committet und pusht (bei Berechtigungsfehler: bis zu 2 Retries, je 1s warten)
2. Marcus installiert lokal und startet Claude Desktop neu
## Aktueller Stand
### Implementierte Tools (v0.4.16)
### Implementierte Tools (v0.4.x)
| Kategorie | Tools |
|---|---|
| Kreise | `get_circles`, `get_members` |
| Listen | `get_lists` |
| Tasks (Lesen) | `get_tasks` (inkl. `category_id`, `due_date`, `assignee_ids`), `get_categories` (inkl. `custom`-Flag) |
| Wall | `get_activities`, `like_post` |
| Tasks (Schreiben) | `create_task` (inkl. `category_id`, `due_date`, `assignee_ids`), `update_task` (inkl. `category_id`, `due_date`, `clear_due_date`, `assignee_ids`, `list_id`), `toggle_task`, `delete_task` |
| Kategorien (Schreiben) | `create_category` (inkl. `icon`), `delete_category` (System-Kategorien geschützt) |
| Lesen | `get_circles`, `get_members`, `get_lists`, `get_tasks`, `get_categories`, `get_activities` |
| Tasks | `create_task`, `update_task`, `toggle_task`, `delete_task` |
| Kategorien | `create_category`, `delete_category` |
| Aktivitäten | `like_post` |
## Roadmap
- v0.x: Erweiterter Lese- + Schreibzugriff ← aktuell
- Offen: Unlike (`like_post(like=False)`)
- v0.4.x: Kategorie-Management, Task-Felder (due_date, assignee, list_id) ← aktuell
- v0.5.x: Erinnerungen + Wiederholungen (Premium-Account erforderlich)
- v2.0: Schreibzugriff auf Wall-Posts (Erstellen, Kommentieren)
## Referenzprojekt
Im Ordner `reference/` liegen Dateien aus einem anderen MCP-Server-Projekt
als Orientierung für Struktur und Patterns:
| Datei | Zweck |
|---|---|
| `reference/pyproject.toml` | Projektstruktur, Dependencies, Entry-Points, Build-System |
| `reference/config.py` | Config-Pattern: YAML laden, validieren, speichern |
| `reference/auth.py` | Keyring-Integration, Credential-Resolution-Reihenfolge |
| `reference/cli.py` | Setup-Wizard, check, serve CLI-Struktur |
**Wichtig:** Diese Dateien sind Referenz, kein Copy-Paste. Alle
Synology/DSM-spezifischen Teile werden nicht übernommen.
Family Wall nutzt ein anderes Auth-Schema siehe SPEC.md.
## Architektur-Entscheidungen
### Session-Strategie
Kein Session-Caching. Jeder Tool-Call führt Login → API-Call → Logout durch.
Credentials liegen im OS Keyring (nur `email` + `password`), kein `session_id`.
Optimierung: Mehrere API-Calls in einer Session bündeln (login → call1 → call2 → logout)
um unnötige HTTP-Roundtrips zu vermeiden. Credentials liegen im OS Keyring
(nur `email` + `password`), kein `session_id`.
### Kreise (Scopes)
Family Wall kennt mehrere Kreise (z.B. Familie, erweiterter Familienkreis).
@@ -72,68 +57,77 @@ Ohne `scope` werden alle Kreise zurückgegeben.
Systembezeichnungen (z.B. `SYS-CAT-SHOPPINGLIST`) werden in deutsche
Klarnamen übersetzt. Mapping-Tabelle in `modules/lists.py`.
### Kategorien
- Kategorien sind family-wide, nicht list-spezifisch (`taskcategoryput` gilt für alle Listen)
- System-Kategorien: `rights.canDelete=null` → nicht löschbar
- Custom-Kategorien: `rights.canDelete="true"` → löschbar
- Locale-Filter: default `"de"` Custom-Kategorien haben kein locale-Feld
und werden immer angezeigt unabhängig vom Locale-Parameter
### Fehlerbehandlung
Die API gibt Fehler manchmal als `a00.un.un` zurück (nicht Top-Level).
`fw_client.py` prüft beides und wirft `FamilyWallError`. Nie silent-fail
als Erfolg werten immer `a00.un` und Top-Level `ex`/`un` prüfen.
### Service Worker
Die Family Wall Web-App nutzt einen Service Worker der bestimmte
HTTP-Requests abfängt und modifiziert. Browser-DevTools und JS-Interceptoren
können den echten Request-Body in diesen Fällen nicht sehen.
→ Immer `FW_DEBUG=1` für Traffic-Analyse nutzen, nicht Browser-DevTools.
## Claude Code Implementierungsregeln
- Keine destruktiven Operationen in v1.0 → kein Confirmation-Pattern erforderlich
- **Feature complete before next feature** jedes Feature vollständig
implementieren, testen und verifizieren bevor das nächste beginnt
- **Kein destruktives Probing** keine Probe-Calls auf System-Kategorien,
echte Listen oder echte Tasks; immer Test-Objekte anlegen und danach
sofort löschen
- Fehlerbehandlung: API-Fehler als verständliche Meldung zurückgeben, keine Stacktraces
- Keine Secrets in stderr-Ausgaben (Passwort bei Debug-Logging maskieren)
- Type Hints und Docstrings konsequent verwenden
- Type Hints und Docstrings konsequent verwenden (Englisch)
- Formatter: `ruff format`, Linter: `ruff check`, Tests: `pytest`
- Alle Texte (Docstrings, Kommentare, README): Englisch
- Debug-Logging via `FW_DEBUG=1` Umgebungsvariable
- Nach jeder Aufgabe: git commit + push. Bei Berechtigungsfehler: 1s warten, bis zu 2 Retries
- .gitignore eigenständig pflegen (Credentials, __pycache__, .venv, .env, *.pyc etc.)
- README.md im Projekt-Root pflegen und bei jedem Aufruf aktualisieren
- README.md + CLAUDE.md im Projekt-Root bei jedem Aufruf aktualisieren
- Confirmation-Pattern in Docstrings: `IMPORTANT: Ask the user for confirmation
before calling this tool.` für destruktive oder schreibende Operationen
## Implementierungsreihenfolge
## Bekannte API-Eigenheiten und Fallstricke
### Gruppe 1 Projektgerüst + Auth + CLI ✦ Prio: hoch
### Sentinel-Wert `$empty`
Das FiZ-Framework nutzt `$empty` als Sentinel um optionale Felder zu löschen.
Normale Werte wie `""`, `null`, `"null"`, `"0"` werden vom Server abgelehnt.
Aktuell genutzt für: `dueDate=$empty` (Fälligkeitsdatum entfernen)
- `pyproject.toml`: Package `mcp-familywall`, Entry-Point `mcp-familywall`
- `src/mcp_familywall/config.py`: `~/.config/mcp-familywall/config.yaml`,
schema_version 1
- `src/mcp_familywall/auth.py`: Keyring-Service `mcp-familywall`,
Keys: `email`, `password`. Credential-Resolution:
1. Umgebungsvariablen `FW_EMAIL`, `FW_PASSWORD`
2. OS Keyring
- `src/mcp_familywall/fw_client.py`: HTTP-Client mit `httpx`.
Methoden: `login()`, `logout()`, `call(endpoint, params)`.
Debug-Logging wenn `FW_DEBUG=1` (Passwort maskieren).
- `src/mcp_familywall/cli.py`:
- `setup`: fragt E-Mail + Passwort, führt Login/Logout durch,
speichert Credentials im Keyring, gibt Claude-Desktop-Snippet aus
- `check`: testet Auth und API-Erreichbarkeit
- `serve`: startet MCP-Server
Config-Datei enthält nur:
```yaml
schema_version: 1
### Silent-Fail via `a00.un.un`
Fehler bei falschen Parametern kommen nicht immer auf Top-Level:
```json
{"a00": {"un": {"un": {"message": "missing value in: taskId"}}}}
```
→ `fw_client` muss beide Ebenen prüfen
### Gruppe 2 MCP Tools ✦ Prio: hoch
### Bekannte Parameter-Namen (verifiziert)
| Endpoint | Parameter | Wert/Format |
|---|---|---|
| `taskcreate2` | `taskListId`, `text`, `description`, `taskCategoryId`, `dueDate`, `assignee` | |
| `taskupdate2` | `metaId`, `text`, `description`, `taskCategoryId`, `dueDate`, `assignee`, `taskListId` | |
| `taskupdate2` | `dueDate` löschen | `$empty` |
| `taskmark` | `taskId`, `complete` | `"true"`/`"false"` |
| `metadelete` | `id` | metaId des Tasks |
| `wallmood` | `wall_message_id`, `moodType` | `"STAR"` für Like |
| `taskcategoryput` | `name`, `emoji` | |
| `taskcategorydelete` | `id` | metaId der Kategorie |
`src/mcp_familywall/server.py` + `src/mcp_familywall/modules/lists.py`
### Self-Like-Restriction
Eigene Posts können nicht geliked werden. API antwortet 200, macht aber nichts.
**`get_circles`**
- Ruft `famlistfamily` auf
- Gibt alle Kreise zurück: `id`, `name`
- Confirmation: nein
**`get_lists`**
- Signatur: `get_lists(scope: str = None) -> str`
- Ruft `accgetallfamily` auf (Parameter: `a01call=taskcategorysync`, `a02call=tasksync`)
- Gibt zurück: `id` (metaId), `name` (übersetzt), `type`, offene Einträge,
Gesamteinträge, Kreis-Name
- Ohne `scope`: alle Kreise; mit `scope`: nur dieser Kreis
- Confirmation: nein
**`get_tasks`**
- Signatur: `get_tasks(list_id: str, only_open: bool = True) -> str`
- `list_id`: metaId aus `get_lists`
- Gibt zurück: `id`, `text`, `description`, `completed`
- Confirmation: nein
### Unlike nicht möglich
Service Worker verschlüsselt den Unlike-Request-Body.
Endpoint unbekannt. `like_post(like=False)` gibt Fehlermeldung zurück.
## Test-Credentials (nur für Entwicklung)
@@ -143,9 +137,12 @@ schema_version: 1
| E-Mail | `marcus@gecheckt.de` |
| Passwort | `Lasdas1234` |
Hinweis: Das ist ein kostenloser Test-Account ohne Premium-Features.
Der echte Account (Premium) hat andere Credentials die im Keyring gespeichert sind.
## Hintergrund
Marcus ist Senior Software Engineer (Java, Jakarta EE).
Präferenz: State-of-the-Art, Best Practices, saubere Architektur.
Automatisierung spart Zeit für die Familie. 🌱
Automatisierung spart Zeit für die Familie. 🌱