From 35cbfd3061cc8306efe97d91c7e328eb218462ed Mon Sep 17 00:00:00 2001 From: Marcus van Elst Date: Fri, 17 Apr 2026 23:25:45 +0200 Subject: [PATCH] fix(wall-posts): add delete_wall_post and fix add_comment response parser (v1.3.1) - Fix add_comment response parser: corrected to a00.r.r.comment.commentId structure - Fix add_comment error handling: return errors directly instead of warnings - Add delete_wall_post: permanently delete wall posts via metadelete endpoint - Add delete_wall_post to README.md Wall & Activities section - Update SPEC.md with correct walladdComment response structure - Update SPEC.md metadelete to include wall posts as supported type - Update CHANGELOG.md with v1.3.1 bugfixes and additions - Version bumped to 1.3.1 in pyproject.toml Co-Authored-By: Claude Haiku 4.5 --- CHANGELOG.md | 15 ++++++++ README.md | 3 +- SPEC.md | 7 ++-- pyproject.toml | 2 +- src/mcp_familywall/server.py | 67 +++++++++++++++++++++++++++++------- 5 files changed, 77 insertions(+), 17 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 693536e..1944314 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,6 +10,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 This project follows Semantic Versioning (SemVer). Breaking changes (removed tools, changed parameters) increment the major version. +## [1.3.1] – 2026-04-17 + +### Fixed +- **`add_comment` response parser**: corrected response structure from `a00.r.r` with `metaId` + to nested `a00.r.r.comment.commentId`; response now includes `"created": true` flag +- **`add_comment` error handling**: now returns error messages directly instead of warnings + +### Added +- **`delete_wall_post`** — permanently delete a wall post using the `metadelete` endpoint + (identical to deleting tasks and recipes) + +### Notes +- All wall post tools now complete CRUD operations (Create, Read, Update via like_post, Delete) +- Test post (wall/16282169_31146617) removed from production after verification + ## [1.3.0] – 2026-04-17 ### Added diff --git a/README.md b/README.md index 7cf5b08..968c189 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ MCP server for [Family Wall](https://www.familywall.com) — manage your family's circles, lists, tasks, recipes, and meal plan directly from Claude. -## Tools (v1.3.0) +## Tools (v1.3.1) ### Wall & Activities @@ -12,6 +12,7 @@ MCP server for [Family Wall](https://www.familywall.com) — manage your family' | `create_wall_post` 🔒 | Create a new status post on the wall | | `add_comment` 🔒 | Add a comment to a post | | `like_post` 🔒 | Like or unlike a wall post/activity | +| `delete_wall_post` 🔒 | Permanently delete a wall post | ### Circles & Members diff --git a/SPEC.md b/SPEC.md index 6c9be35..e2f68f4 100644 --- a/SPEC.md +++ b/SPEC.md @@ -269,6 +269,7 @@ POST https://api.familywall.com/api/metadelete - Tasks: `task/` - Rezepte: `recipe/` - Essensplan-Einträge: `dish/` und `meal/` +- Wall-Posts: `wall/` (v1.3.1+) **Response:** ``` @@ -337,8 +338,8 @@ POST https://api.familywall.com/api/walladdComment **Response:** ``` -a00.r.r → Kommentar-Objekt - .metaId → neue Kommentar-ID +a00.r.r.comment → Kommentar-Objekt (nested) + .commentId → neue Kommentar-ID .text → Kommentartext .creationDate → Timestamp (ISO 8601) ``` @@ -346,7 +347,7 @@ a00.r.r → Kommentar-Objekt **Bekannte Einschränkungen:** - `mood` und `clientOpId` sind optional und werden ignoriert -**Verifiziert am:** 2026-04-17 via Briefing und Integration +**Verifiziert am:** 2026-04-17 via Briefing und Integration (Response-Struktur in v1.3.1 korrekt dokumentiert) ### `taskcategoryput` – Kategorie erstellen/aktualisieren POST https://api.familywall.com/api/taskcategoryput diff --git a/pyproject.toml b/pyproject.toml index bb0db35..a1efbe4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "mcp-familywall" -version = "1.3.0" +version = "1.3.1" description = "MCP server for Family Wall — manage your family's circles, lists, tasks, recipes, and meal plan via Claude" readme = "README.md" requires-python = ">=3.12" diff --git a/src/mcp_familywall/server.py b/src/mcp_familywall/server.py index c2788b1..22a4cb1 100644 --- a/src/mcp_familywall/server.py +++ b/src/mcp_familywall/server.py @@ -2042,9 +2042,8 @@ def get_wall_posts(limit: int = 20) -> str: raw_author: str = item.get("accountId", "") mood_map: dict[str, Any] = item.get("moodMap") or {} - liked_by_me = ( - item.get("moodStarShortcut") == "true" - or any("STAR" in moods for moods in mood_map.values()) + liked_by_me = item.get("moodStarShortcut") == "true" or any( + "STAR" in moods for moods in mood_map.values() ) like_count = sum(len(moods) for moods in mood_map.values() if isinstance(moods, list)) @@ -2164,22 +2163,66 @@ def add_comment(post_id: str, comment: str) -> str: return _err(f"Connection error: {exc}") try: - comment_obj = data["a00"]["r"]["r"] - if not isinstance(comment_obj, dict) or "metaId" not in comment_obj: - raise TypeError("unexpected shape") - except (KeyError, TypeError): + response_obj = data["a00"]["r"]["r"] + if not isinstance(response_obj, dict): + raise TypeError("a00.r.r is not a dict") + comment_obj = response_obj.get("comment") + if not isinstance(comment_obj, dict) or "commentId" not in comment_obj: + raise TypeError("comment object missing or invalid") + except (KeyError, TypeError) as exc: + return _err(f"Unexpected walladdComment response structure: {exc}") + + return json.dumps( + { + "created": True, + "id": comment_obj.get("commentId"), + "post_id": post_id, + "text": comment_obj.get("text"), + "date": comment_obj.get("creationDate"), + }, + ensure_ascii=False, + indent=2, + ) + + +# --------------------------------------------------------------------------- +# Tool: delete_wall_post +# --------------------------------------------------------------------------- + + +@mcp.tool() +def delete_wall_post(post_id: str) -> str: + """Permanently delete a wall post. + + IMPORTANT: Ask the user for confirmation before calling this tool. + + Args: + post_id: Wall post metaId from get_wall_posts + (e.g. ``"wall/16282169_31146617"``). + + Returns: + JSON success indicator or an error message. + """ + try: + data = _authenticated_call("metadelete", {"id": post_id}) + except RuntimeError as exc: + return _err(str(exc)) + + try: + result = data["a00"]["r"]["r"] + if result != "true": + raise ValueError(f"Unexpected result: {result}") + except (KeyError, ValueError) as exc: return json.dumps( - {"warning": "Unexpected walladdComment response structure", "raw": data}, + {"warning": "Unexpected metadelete response structure", "error": str(exc), "raw": data}, ensure_ascii=False, indent=2, ) return json.dumps( { - "id": comment_obj.get("metaId"), - "post_id": post_id, - "text": comment_obj.get("text") or comment_obj.get("comment"), - "date": comment_obj.get("creationDate"), + "deleted": True, + "id": post_id, }, ensure_ascii=False, indent=2,