From 4a3fe6be8769ab73d3b0332c3b76569e6b42dcd3 Mon Sep 17 00:00:00 2001 From: Marcus van Elst Date: Thu, 16 Apr 2026 13:50:36 +0200 Subject: [PATCH] feat(lists): expose emoji + color in get_lists + create_list (v0.5.1) get_lists now includes emoji and color fields per list entry. create_list response also returns emoji and color from the API. Field name verification (FW_DEBUG=1, 2026-04-16): - emoji: API returns "" when unset -> normalised to null - color: API omits key when unset -> normalised to null - Both fields present in taskgettasklists and taskcreatelist responses SPEC.md: taskgettasklists documented with full response structure and emoji/color normalisation notes. taskcreatelist response updated with emoji + color fields. Co-Authored-By: Claude Sonnet 4.6 --- CLAUDE.md | 5 +++-- README.md | 6 ++++-- SPEC.md | 30 ++++++++++++++++++++++++++++-- pyproject.toml | 2 +- src/mcp_familywall/__init__.py | 2 +- src/mcp_familywall/server.py | 8 ++++++++ 6 files changed, 45 insertions(+), 8 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index e38f9c9..3282b52 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -37,8 +37,9 @@ und wird in Claude Desktop eingebunden. ## Roadmap - v0.4.x: Kategorie-Management, Task-Felder (due_date, assignee, list_id) ✓ -- v0.5.x: Listen-Management (create_list, delete_list) ← aktuell -- v0.5.1: update_list (Umbenennen), Sharing-Verwaltung +- v0.5.x: Listen-Management (create_list, delete_list) ✓ +- v0.5.1: emoji + color in get_lists / create_list ← aktuell +- v0.5.2: update_list (Umbenennen, emoji/color ändern), Sharing-Verwaltung - v0.6.x: Erinnerungen + Wiederholungen (Premium-Account erforderlich) - v2.0: Schreibzugriff auf Wall-Posts (Erstellen, Kommentieren) diff --git a/README.md b/README.md index 28b24d1..526a90a 100644 --- a/README.md +++ b/README.md @@ -2,13 +2,13 @@ MCP server for [Family Wall](https://www.familywall.com) -- read and manage your family's circles, lists, and tasks directly from Claude. -## Features (v0.4.16) +## Features (v0.5.1) ### Read - `get_circles` -- list all family circles - `get_members` -- list members of a circle (or all circles) -- `get_lists` -- list all task lists (optionally filtered by circle) +- `get_lists` -- list all task lists (includes `emoji` and `color`; `null` when unset) - `get_tasks` -- list tasks in a specific list (includes `category_id`, `due_date`, `assignee_ids`) - `get_categories` -- list categories for a list (locale-filtered; custom categories always included; `custom` flag marks user-created ones) - `get_activities` -- list recent wall activities (author resolved to display name) @@ -19,6 +19,8 @@ MCP server for [Family Wall](https://www.familywall.com) -- read and manage your - `update_task` -- update text, description, category, due date, assignees, or move to a different list; supports `clear_due_date=True` to remove a due date - `toggle_task` -- mark a task complete or reopen it - `delete_task` -- permanently delete a task +- `create_list` -- create a new task list (SHOPPING_LIST or TODOS; optional `emoji` and `color`) +- `delete_list` -- permanently delete a list and all its tasks (system lists are protected) - `create_category` -- create a custom category for a shopping list (with optional icon) - `delete_category` -- delete a custom category (system categories are protected) - `like_post` -- like a wall post/activity diff --git a/SPEC.md b/SPEC.md index 3023aba..0ba74d7 100644 --- a/SPEC.md +++ b/SPEC.md @@ -300,6 +300,8 @@ a00.r.r → vollständiges Listen-Objekt .name → Listen-Name .taskListType → SHOPPING_LIST oder TODOS .sharedToAll → "true" / "false" + .emoji → Unicode-Emoji (fehlt wenn nicht gesetzt) + .color → Hex-Farbwert z.B. "#E53935" (fehlt wenn nicht gesetzt) .rights.canDelete → "true" (user-created lists) ``` @@ -325,10 +327,34 @@ MCP-Server prüft dies vor dem Löschen via `taskgettasklists`. **Verifiziert am:** 2026-04-16 via FW_DEBUG=1 -### `taskgettasklists` – Listen abrufen (alternativ) +### `taskgettasklists` – Listen abrufen POST https://api.familywall.com/api/taskgettasklists -Wird intern zur Verifikation von `taskListType` genutzt. +**Body-Parameter:** keine + +**Response-Struktur:** +``` +a00.r.r[] → Liste aller Task-Listen + .metaId → Listen-ID (z.B. "taskList/23431854_29740942") + .name → Systembezeichnung oder Benutzer-Name + .taskListType → SHOPPING_LIST oder TODOS + .emoji → Unicode-Emoji oder "" (leerer String = kein Emoji) + .color → Hex-Farbwert z.B. "#E53935" (fehlt wenn nicht gesetzt) + .remainingTaskNumber → offene Tasks (String) + .totalTaskNumber → Gesamt-Tasks (String) + .sharedToAll → "true" / "false" + .sharedMemberIds[] → Member-accountIds + .rights.canDelete → "true" = löschbar, fehlt/leer = Systemliste + .systemId → vorhanden nur bei Systemlisten (z.B. "-10", "-11") +``` + +**Hinweis emoji/color:** +- `emoji`: Systemlisten liefern `""`, user-created Listen liefern den Emoji-String + oder `""` wenn kein Emoji gesetzt. Normalisierung: `""` → `null` im MCP-Server. +- `color`: Fehlt komplett wenn nicht gesetzt (nicht `null` oder `""`). + Normalisierung: fehlendes Feld → `null` im MCP-Server. + +**Verifiziert am:** 2026-04-16 via FW_DEBUG=1 ## Systembezeichnungen für Listen-Namen diff --git a/pyproject.toml b/pyproject.toml index 12003bf..e7f2b3e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "mcp-familywall" -version = "0.4.16" +version = "0.5.1" description = "MCP server for Family Wall — read your family's lists and tasks via Claude" readme = "README.md" requires-python = ">=3.12" diff --git a/src/mcp_familywall/__init__.py b/src/mcp_familywall/__init__.py index 6ff6db1..dd9b22c 100644 --- a/src/mcp_familywall/__init__.py +++ b/src/mcp_familywall/__init__.py @@ -1 +1 @@ -__version__ = "0.4.16" +__version__ = "0.5.1" diff --git a/src/mcp_familywall/server.py b/src/mcp_familywall/server.py index a5f084f..d86b389 100644 --- a/src/mcp_familywall/server.py +++ b/src/mcp_familywall/server.py @@ -284,6 +284,9 @@ def get_lists(scope: str | None = None): result = [] for item in raw_lists: # TODO: apply scope filtering once the circle field is identified. + # emoji: API returns "" when unset — normalise to None for a clean JSON null. + # color: API omits the key entirely when unset — .get() returns None directly. + raw_emoji: str = item.get("emoji", "") result.append( { "id": item.get("metaId"), @@ -291,6 +294,8 @@ def get_lists(scope: str | None = None): "type": item.get("taskListType"), "open": item.get("remainingTaskNumber"), "total": item.get("totalTaskNumber"), + "emoji": raw_emoji if raw_emoji else None, + "color": item.get("color") or None, } ) @@ -927,6 +932,7 @@ def create_list( indent=2, ) + raw_emoji: str = list_obj.get("emoji", "") return json.dumps( { "created": True, @@ -934,6 +940,8 @@ def create_list( "name": list_obj.get("name", name), "type": list_obj.get("taskListType"), "shared_to_all": list_obj.get("sharedToAll") == "true", + "emoji": raw_emoji if raw_emoji else None, + "color": list_obj.get("color") or None, }, ensure_ascii=False, indent=2,