perf: delete_category uses single API session (v0.4.13)

Previously delete_category made two separate login cycles (accgetallfamily
to verify + taskcategorydelete to delete) = 6 HTTP calls. Now both happen
in one session = 4 HTTP calls. Halves latency and eliminates the risk of
a compounding timeout when the API is temporarily slow.

FW_DEBUG=1 investigation confirmed the API itself is fast (<1s); the
reported 4-min timeout was transient API slowness amplified by the double
session overhead.

Also recreated 'Obst & Gemüse' (emoji 🍎) as taskCategory/23431854_4956806
after it was accidentally consumed by the debug script.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-04-16 08:26:01 +02:00
parent 0d8036fd4a
commit 1ab410621c
4 changed files with 45 additions and 30 deletions
+1 -1
View File
@@ -2,7 +2,7 @@
MCP server for [Family Wall](https://www.familywall.com) -- read and manage your family's circles, lists, and tasks directly from Claude. 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.12) ## Features (v0.4.13)
### Read ### Read
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "mcp-familywall" name = "mcp-familywall"
version = "0.4.12" version = "0.4.13"
description = "MCP server for Family Wall — read your family's lists and tasks via Claude" description = "MCP server for Family Wall — read your family's lists and tasks via Claude"
readme = "README.md" readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.4.12" __version__ = "0.4.13"
+42 -27
View File
@@ -502,42 +502,57 @@ def delete_category(category_id: str) -> str:
Returns: Returns:
JSON success indicator or an error message. JSON success indicator or an error message.
""" """
# Safety check: look up the category and verify it is custom (canDelete=true). # Safety check + delete in a SINGLE session to minimise API round-trips.
# This prevents accidental deletion of shared system categories. # Previously two separate sessions were used (accgetallfamily + taskcategorydelete),
# causing 6 HTTP calls. One session = 4 HTTP calls (login, check, delete, logout).
try: try:
data = _accgetallfamily() email, password = get_credentials()
except RuntimeError as exc: except RuntimeError as exc:
return f"Error: {exc}" return f"Error: {exc}"
cat_obj: dict[str, Any] | None = None
try: try:
raw_cats: list[dict[str, Any]] = data["a01"]["r"]["r"]["updatedCreated"] with FamilyWallClient() as client:
except (KeyError, TypeError): client.login(email, password)
raw_cats = []
cat_obj: dict[str, Any] | None = next( # Fetch categories and verify the target is custom (canDelete=true).
(c for c in raw_cats if c.get("metaId") == category_id), None data = client.call(
) "accgetallfamily",
{"a01call": "taskcategorysync", "a02call": "tasksync"},
)
try:
raw_cats: list[dict[str, Any]] = data["a01"]["r"]["r"]["updatedCreated"]
except (KeyError, TypeError):
raw_cats = []
if cat_obj is None: cat_obj = next(
return f"Error: Category '{category_id}' not found." (c for c in raw_cats if c.get("metaId") == category_id), None
)
if cat_obj is None:
client.logout()
return f"Error: Category '{category_id}' not found."
can_delete: str | None = cat_obj.get("rights", {}).get("canDelete") can_delete: str | None = cat_obj.get("rights", {}).get("canDelete")
if can_delete != "true": if can_delete != "true":
return json.dumps( client.logout()
{ return json.dumps(
"error": "System categories cannot be deleted.", {
"id": category_id, "error": "System categories cannot be deleted.",
"name": cat_obj.get("name"), "id": category_id,
"hint": "Only custom categories (custom=true in get_categories) can be deleted.", "name": cat_obj.get("name"),
}, "hint": "Only custom categories (custom=true in get_categories) can be deleted.",
ensure_ascii=False, },
indent=2, ensure_ascii=False,
) indent=2,
)
try: # Verified — delete in the same session.
_authenticated_call("taskcategorydelete", {"id": category_id}) client.call("taskcategorydelete", {"id": category_id})
except RuntimeError as exc: client.logout()
return f"Error: {exc}" except FamilyWallError as exc:
return f"Error: Family Wall API error: {exc}"
except Exception as exc:
return f"Error: Connection error: {exc}"
return json.dumps( return json.dumps(
{"deleted": True, "id": category_id, "name": cat_obj.get("name")}, {"deleted": True, "id": category_id, "name": cat_obj.get("name")},