Files
mcp-familywall/CLAUDE.md
T
marcus 0e7c4da362 feat(wall-posts): add wall post reading/writing with comments (v1.3.0)
- Add get_wall_posts: read recent wall posts with like/comment counts
- Add create_wall_post: publish new status posts to the wall
- Add add_comment: add comments to wall posts and activities
- like_post already supports both wall posts and activities (v1.2.0)
- Update README.md with new Wall & Activities section
- Update CLAUDE.md with v1.3.0 and tool reorganization
- Update CHANGELOG.md with v1.3.0 release notes
- Add wallpublish and walladdComment documentation to SPEC.md

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
2026-04-17 23:19:37 +02:00

187 lines
9.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# mcp-familywall
**Note:** This file is intentionally written in German (developer preference).
Code, docstrings, and commit messages are in English.
## Kontext
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
| | |
|---|---|
| **Family Wall API** | `https://api.familywall.com/api` |
| **Gitea** | `https://gitea.gecheckt.de/marcus/mcp-familywall` |
| **Lokaler Code** | `D:\Dev\Projects\mcp-familywall` |
| **Sprache** | Python 3.12+, `uv`, MCP SDK, `httpx`, `keyring`, `click`, `rich` |
## 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
### Version: **v1.3.0** ← aktuell
### Implementierte Tools
| Kategorie | Tools |
|---|---|
| Wall & Aktivitäten | `get_wall_posts`, `create_wall_post`, `add_comment`, `like_post` |
| Kreise & Mitglieder | `get_circles`, `get_members`, `create_circle`, `update_circle`, `delete_circle`, `add_member_to_circle` |
| Listen & Tasks | `get_lists`, `get_tasks`, `get_categories`, `get_activities`, `create_list`, `update_list`, `delete_list`, `create_category`, `delete_category`, `create_task`, `update_task`, `toggle_task`, `delete_task`, `clear_list` |
| Rezeptbox | `get_recipe_categories`, `get_recipe_box`, `get_recipes`, `get_recipe`, `create_recipe`, `update_recipe`, `delete_recipe` |
| Essensplaner | `get_meal_plan`, `add_recipe_to_meal_plan`, `add_meal_to_meal_plan`, `add_meal_note`, `delete_meal_plan_entry` |
### Roadmap (Nächstes)
- v2.0: Weitere Wall-Post Features (Edits, Deletes, Emoji-Reactions beyond STAR)
### Historische Meilensteine (kompakt)
- v0.1v0.4: Lesen (Kreise, Listen, Tasks, Kategorien), Schreiben (Tasks, Kategorien)
- v0.5: Listen-Management (create/delete), emoji + color
- v0.6v0.8: Rezeptbox vollständig, Kreismanagement, Rezeptkategorien
- v0.9: Task-Wiederholungen + Erinnerungen (read-only)
- v0.10v0.11: Essensplaner (read + write)
- v1.0: Cleanup, Unified errors, Datumsvalidierung, Partial-Failure-Reporting (Details: CHANGELOG.md)
- v1.1: Task-Recurrency-Write (flat top-level params)
- v1.2: Task-Reminder-Write via Dot-Notation (`reminder.*`) — verifiziert 2026-04-17
## Architektur-Entscheidungen
### Session-Strategie
Kein Session-Caching. Jeder Tool-Call führt Login → API-Call → Logout durch.
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).
Der API-Parameter `scope=family/XXXX` schaltet den Server-Kontext um.
- `taskgettasklists` ohne scope → primärer Kreis; mit scope → angegebener Kreis
- `taskcreatelist` mit scope → neue Liste im angegebenen Kreis
- `taskdeletelist` mit scope → löscht Liste aus angegebenem Kreis
- `get_lists(scope="family/XXXX")` oder `get_lists(scope="Kreis-Name")` zur Filterung
- Die Listen-metaId kodiert den Kreis: `taskList/<FAMNUM>_<LISTNUM>``family/<FAMNUM>`
### Listen-Namen
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
- **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 (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 + 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
## Bekannte API-Eigenheiten und Fallstricke
### 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)
### 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
### 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` |
| `taskupdate2` | `recurrencyDescriptor` (flach!) | `recurrency, recurrencyInterval, rrule, byDay, byMonthDay, recurrencyEndDate, endOccurence` als Top-Level-Parameter; löschen: `recurrency="NONE"` |
| `taskupdate2` | Reminder (Dot-Notation!) | `reminder.reminderUnit` (`MINUTE`/`HOUR`/`DAY`), `reminder.reminderValue` (String-Integer), `reminder.reminderType` (`SNOOZE`=aktiv, `NONE`=entfernen), `reminder.localId` optional. Entfernen: vollständigen Block mit `reminderType=NONE, reminderValue="0", reminderUnit=MINUTE` senden. Partielle Updates → `task reminder invalid`. |
| `taskupdate2` | **⚠️ Encoding** | Recurrency flach top-level. Reminder **nur Dot-Notation** `reminder.*` — flache Keys, JSON-String, Brackets werden silent-ignored. |
| `taskmark` | `taskId`, `complete` | `"true"`/`"false"` |
| `metadelete` | `id` | metaId des Tasks / Rezepts |
| `wallmood` | `wall_message_id`, `add`, `remove`/`remove.0` | Like: `add="STAR", remove="$empty"`; Unlike: `add="$empty", remove.0="STAR"` (Array-Dot-Notation) |
| `taskcategoryput` | `name`, `emoji` | |
| `taskcategorydelete` | `id` | metaId der Kategorie |
| `taskcreatelist` | `name`, `taskListType`, `sharedToAll`, `color`, `emoji`, `scope` | `taskListType`: `SHOPPING_LIST`, `TODOS`, `OTHER`; `scope`: Kreis-metaId für nicht-primäre Kreise |
| `taskgettasklists` | `scope` | Kreis-metaId; ohne scope → primärer Kreis |
| `taskupdatelist` | `metaId`, `name`, `color`, `emoji`, `scope` | `metaId` ⚠️ nicht `id`!; `scope`: Kreis-metaId für sekundäre Kreise; Partial Update |
| `taskdeletelist` | `id`, `scope` | `scope`: Kreis-metaId für sekundäre Kreise |
| `mprecipeput` | `recipe.name`, `recipe.isRecipe="true"`, `recipe.description`, `recipe.ingredients`, `recipe.instructions`, `recipe.prepTime`, `recipe.cookTime`, `recipe.serves`, `recipe.url` | Alle mit `recipe.`-Prefix! |
| `mprecipeput` (Update) | zusätzlich `recipe.metaId` | Vorhandene ID → Update statt Create |
| `mprecipeput` (Kategorien) | `recipe.recipeCategoryIdList` | Mehrfach sendbar; leerer String `""` entfernt alle Kategorien |
| `metasync` (Rezepte lesen) | `id="recipe"` | liefert `a00.r.r.updatedCreated[]` |
| `acccreatefamily` | `name` | liefert numerische Kreis-ID als String in `a00.r.r` |
| `accinvite` | `familyId`, `identifier`, `role="Unknown"`, `firstname` | nur für neue FW-Accounts |
| `accupdatefamily` | `name`, `scope` | `scope`: Kreis-metaId; ohne scope → PRIMARY Kreis; erster Buchstabe wird kapitalisiert |
| `adminwipefamily` | `scope` | Kreis-metaId; löscht Kreis + alle Inhalte; `a00.r.r="true"` bei Erfolg |
### Self-Like-Restriction
Eigene Posts können nicht geliked werden. API antwortet 200, macht aber nichts.
### Unlike
Unlike via `remove.0=STAR` (Array-Dot-Notation). Verifiziert 2026-04-17 via Network-Interceptor.
### mpstar / Rezept-Favorit
Service Worker fängt `mpstar` ab. `metamood` funktioniert nur auf
fremde Inhalte (Self-Reaction-Restriction). Eigene Rezepte
können nicht als Favorit markiert werden. Siehe SPEC.md § Offene Punkte.
## Test-Credentials (nur für Entwicklung)
| | |
|---|---|
| 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. 🌱