# mcp-familywall ## 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 ### Implementierte Tools (v0.6.1) | Kategorie | Tools | |---|---| | Lesen | `get_circles`, `get_members`, `get_lists`, `get_tasks`, `get_categories`, `get_activities` | | Tasks | `create_task`, `update_task`, `toggle_task`, `delete_task` | | Listen | `create_list`, `delete_list` | | Kategorien | `create_category`, `delete_category` | | Aktivitäten | `like_post` | | Rezepte | `get_recipes`, `get_recipe`, `create_recipe`, `update_recipe`, `delete_recipe` | ## Roadmap - v0.4.x: Kategorie-Management, Task-Felder (due_date, assignee, list_id) ✓ - v0.5.x: Listen-Management (create_list, delete_list) ✓ - v0.5.1: emoji + color in get_lists / create_list ✓ - v0.5.2: Mengenkonvention im create_task Docstring ✓ - v0.6.0: Rezept-Box (get_recipes, get_recipe, create_recipe, delete_recipe) ✓ - v0.6.1: update_recipe + Bugfix Zeilenumbrüche in create_recipe ✓ ← aktuell - v0.6.2: mpadditemtolist (Zutaten → Einkaufsliste) - v0.5.3: update_list (Umbenennen, emoji/color ändern), Sharing-Verwaltung - v0.7.x: Erinnerungen + Wiederholungen (Premium-Account erforderlich) - v2.0: Schreibzugriff auf Wall-Posts (Erstellen, Kommentieren) ## 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). `get_lists` unterstützt optionalen `scope`-Parameter zur Filterung. Ohne `scope` werden alle Kreise zurückgegeben. ### 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` | | `taskmark` | `taskId`, `complete` | `"true"`/`"false"` | | `metadelete` | `id` | metaId des Tasks / Rezepts | | `wallmood` | `wall_message_id`, `moodType` | `"STAR"` für Like | | `taskcategoryput` | `name`, `emoji` | – | | `taskcategorydelete` | `id` | metaId der Kategorie | | `taskcreatelist` | `name`, `taskListType`, `sharedToAll`, `color`, `emoji` | `taskListType`: `"SHOPPING_LIST"`/`"TODOS"` | | `taskdeletelist` | `id` | metaId der Liste | | `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 | | `metasync` (Rezepte lesen) | `id="recipe"` | liefert `a00.r.r.updatedCreated[]` | ### Self-Like-Restriction Eigene Posts können nicht geliked werden. API antwortet 200, macht aber nichts. ### 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) | | | |---|---| | 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. 🌱