diff --git a/SPEC.md b/SPEC.md index cc4d0eb..7bcff1b 100644 --- a/SPEC.md +++ b/SPEC.md @@ -87,6 +87,14 @@ a00.r.r[] → Kreise .name → Kreisname ``` +### `taskgettasklists` – Listen abrufen +POST https://api.familywall.com/api/taskgettasklists +Content-Type: application/x-www-form-urlencoded + +**Body-Parameter:** keine + +**Response-Struktur:** zu verifizieren beim ersten echten Call + ### `accgetallfamily` – Listen + Tasks abrufen POST https://api.familywall.com/api/accgetallfamily Content-Type: application/x-www-form-urlencoded diff --git a/pyproject.toml b/pyproject.toml index 7d4f123..45d0848 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "hatchling.build" [project] name = "mcp-familywall" -version = "0.2.3" +version = "0.2.4" 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 d31c31e..788da1f 100644 --- a/src/mcp_familywall/__init__.py +++ b/src/mcp_familywall/__init__.py @@ -1 +1 @@ -__version__ = "0.2.3" +__version__ = "0.2.4" diff --git a/src/mcp_familywall/server.py b/src/mcp_familywall/server.py index fe65724..d60316f 100644 --- a/src/mcp_familywall/server.py +++ b/src/mcp_familywall/server.py @@ -166,6 +166,8 @@ def get_circles() -> str: def get_lists(scope: str | None = None) -> str: """Return all task lists, optionally filtered by circle name. + Uses the taskgettasklists endpoint directly. + Args: scope: Optional circle name to filter by. When None, all lists from all circles are returned. @@ -175,30 +177,49 @@ def get_lists(scope: str | None = None) -> str: id, name, type, open, total. """ try: - data = _accgetallfamily() + email, password = get_credentials() except RuntimeError as exc: return f"Error: {exc}" - raw_lists = _extract_lists(data) - if not raw_lists: - # Return raw response for debugging if no lists found at expected path + try: + with FamilyWallClient() as client: + client.login(email, password) + data = client.call("taskgettasklists", {}) + client.logout() + except FamilyWallError as exc: + return f"Error: {exc}" + except Exception as exc: + return f"Connection error: {exc}" + + # Try known response patterns; fall back to raw JSON for verification. + raw_lists: list[dict[str, Any]] | None = None + try: + candidate = data["a00"]["r"]["r"] + if isinstance(candidate, list): + raw_lists = candidate + elif isinstance(candidate, dict) and isinstance(candidate.get("updatedCreated"), list): + raw_lists = candidate["updatedCreated"] + except (KeyError, TypeError): + pass + + if raw_lists is None: + # Response structure not yet verified — return raw JSON for inspection. return json.dumps( - {"warning": "No lists found at expected path", "raw": data}, + {"warning": "Unexpected taskgettasklists response structure", "raw": data}, ensure_ascii=False, indent=2, ) result = [] for item in raw_lists: - # _extract_lists already normalises to {id, name, type, open, total}. # TODO: apply scope filtering once the circle field is identified. result.append( { - "id": item.get("id"), + "id": item.get("metaId"), "name": translate_name(item.get("name", "")), - "type": item.get("type"), - "open": item.get("open"), - "total": item.get("total"), + "type": item.get("taskListType"), + "open": item.get("remainingTaskNumber"), + "total": item.get("totalTaskNumber"), } )