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:
@@ -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
@@ -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 @@
|
|||||||
__version__ = "0.4.12"
|
__version__ = "0.4.13"
|
||||||
|
|||||||
@@ -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")},
|
||||||
|
|||||||
Reference in New Issue
Block a user