docs(usability): enforce ID→name resolution in all tool docstrings (v1.4.3)

Add explicit guidance to resolve raw API IDs to human-readable names before
user display. Affected tools: get_tasks, get_lists, get_activities,
get_wall_posts, get_members, get_circles, get_categories, get_meal_plan.

Add general usability rule to CLAUDE.md implementation section: never present
raw numeric/metaIDs to the user. No breaking changes; docstring improvements only.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-04-18 00:10:26 +02:00
parent 0e34b067e6
commit 5671d70000
4 changed files with 52 additions and 3 deletions
+19
View File
@@ -10,6 +10,25 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
This project follows Semantic Versioning (SemVer). This project follows Semantic Versioning (SemVer).
Breaking changes (removed tools, changed parameters) increment the major version. Breaking changes (removed tools, changed parameters) increment the major version.
## [1.4.3] 2026-04-18
### Improved
- **Usability: ID resolution in docstrings** — enforce transparent display of human-readable names:
- `get_tasks`: Document required member/category name resolution before user display
- `get_lists`: Document required circle name resolution before user display
- `get_activities`: Document required author name resolution before user display
- `get_wall_posts`: Document required author name resolution before user display
- `get_members`: Added proactive call guidance before presenting member-ID data
- `get_circles`: Added proactive call guidance before presenting circle-ID data
- `get_categories`: Added proactive call guidance for shopping list tasks
- `get_meal_plan`: Document required recipe name resolution for recipe_id before user display
- `CLAUDE.md`: Added general usability rule at top of implementation section
### Notes
- No breaking changes; docstring enhancements only
- All tools remain backward compatible
- Ensures consistent UX: no raw numeric/metaIDs shown to users in any context
## [1.4.2] 2026-04-18 ## [1.4.2] 2026-04-18
### Fixed ### Fixed
+4 -1
View File
@@ -27,7 +27,7 @@ und wird in Claude Desktop eingebunden.
## Aktueller Stand ## Aktueller Stand
### Version: **v1.3.0** ← aktuell ### Version: **v1.4.3** ← aktuell
### Implementierte Tools ### Implementierte Tools
@@ -97,6 +97,9 @@ können den echten Request-Body in diesen Fällen nicht sehen.
## Claude Code Implementierungsregeln ## Claude Code Implementierungsregeln
**Usability rule:** Never present raw API IDs (numeric IDs, metaIds, category IDs, circle IDs, member IDs) to the user.
Always resolve them to human-readable names before responding.
- **Feature complete before next feature** jedes Feature vollständig - **Feature complete before next feature** jedes Feature vollständig
implementieren, testen und verifizieren bevor das nächste beginnt implementieren, testen und verifizieren bevor das nächste beginnt
- **Kein destruktives Probing** keine Probe-Calls auf System-Kategorien, - **Kein destruktives Probing** keine Probe-Calls auf System-Kategorien,
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "mcp-familywall" name = "mcp-familywall"
version = "1.4.2" version = "1.4.3"
description = "MCP server for Family Wall — manage your family's circles, lists, tasks, recipes, and meal plan via Claude" description = "MCP server for Family Wall — manage your family's circles, lists, tasks, recipes, and meal plan via Claude"
readme = "README.md" readme = "README.md"
requires-python = ">=3.12" requires-python = ">=3.12"
+28 -1
View File
@@ -146,7 +146,10 @@ def _extract_tasks(data: dict[str, Any]) -> list[dict[str, Any]]:
@mcp.tool() @mcp.tool()
def get_circles() -> str: def get_circles() -> str:
"""Return all Family Wall circles as JSON list of {id, name}.""" """Return all Family Wall circles as JSON list of {id, name}.
Call this proactively before presenting any data that contains circle IDs to the user.
"""
try: try:
raw_circles = _famlistfamily() raw_circles = _famlistfamily()
except RuntimeError as exc: except RuntimeError as exc:
@@ -220,6 +223,9 @@ def _famlistfamily() -> list[dict[str, Any]]:
def get_members(circle_id: str | None = None) -> str: def get_members(circle_id: str | None = None) -> str:
"""Return Family Wall circle members as JSON, optionally filtered by circle. """Return Family Wall circle members as JSON, optionally filtered by circle.
Call this proactively before presenting any data that contains member IDs
(assignee_ids, author_id, creator) to the user.
Args: Args:
circle_id: Optional circle ID from get_circles (e.g. ``family/23431854``). circle_id: Optional circle ID from get_circles (e.g. ``family/23431854``).
When omitted all members across all circles are returned. When omitted all members across all circles are returned.
@@ -311,6 +317,9 @@ def get_lists(scope: str | None = None) -> str:
Returns: Returns:
JSON list of list objects with keys id, name, type, open, total, JSON list of list objects with keys id, name, type, open, total,
emoji, color, circle_id. emoji, color, circle_id.
IMPORTANT: When presenting lists to the user, always resolve
circle_id to the circle name via get_circles. Never show raw IDs.
""" """
try: try:
email, password = get_credentials() email, password = get_credentials()
@@ -419,6 +428,12 @@ def get_tasks(list_id: str, only_open: bool = True) -> str:
JSON array of task objects with keys: id, text, description, completed, JSON array of task objects with keys: id, text, description, completed,
category_id, due_date, assignee_ids, recurrency, recurrency_interval, category_id, due_date, assignee_ids, recurrency, recurrency_interval,
rrule, reminder. rrule, reminder.
IMPORTANT: Before presenting results to the user, always resolve:
- assignee_ids → member names via get_members
- category_id → category name via get_categories
- circle context → circle name from get_lists
Never show raw IDs to the user.
""" """
# Extract circle number from list_id format: taskList/<circleNum>_<listNum> # Extract circle number from list_id format: taskList/<circleNum>_<listNum>
try: try:
@@ -541,6 +556,9 @@ def get_categories(list_id: str, locale: str = "de") -> str:
Use the returned ``id`` values as the ``category_id`` parameter in Use the returned ``id`` values as the ``category_id`` parameter in
``create_task`` and ``update_task``. ``create_task`` and ``update_task``.
Call this proactively before presenting shopping list tasks to the user so
category_id values can be shown as readable names.
Args: Args:
list_id: List ID from get_lists (e.g. ``taskList/23431854_29740942``). list_id: List ID from get_lists (e.g. ``taskList/23431854_29740942``).
locale: BCP-47 language code for category names (default ``"de"``). locale: BCP-47 language code for category names (default ``"de"``).
@@ -772,6 +790,9 @@ def get_activities(limit: int = 20) -> str:
Returns: Returns:
JSON list of activity objects sorted by date descending, JSON list of activity objects sorted by date descending,
including wall, task, and taskList activity entries. including wall, task, and taskList activity entries.
IMPORTANT: Before presenting to the user, resolve author_id to
the member name via get_members. Never show raw IDs.
""" """
try: try:
email, password = get_credentials() email, password = get_credentials()
@@ -2035,6 +2056,9 @@ def get_wall_posts(limit: int = 20) -> str:
JSON list of post objects with keys: JSON list of post objects with keys:
id, type, text, date, author, author_id, id, type, text, date, author, author_id,
liked_by_me, like_count, comment_count. liked_by_me, like_count, comment_count.
IMPORTANT: Before presenting to the user, resolve author_id to
the member name via get_members. Never show raw IDs.
""" """
try: try:
email, password = get_credentials() email, password = get_credentials()
@@ -2776,6 +2800,9 @@ def get_meal_plan(date_from: str, date_to: str) -> str:
- ``can_update`` — whether the entry can be updated - ``can_update`` — whether the entry can be updated
- ``can_delete`` — whether the entry can be deleted - ``can_delete`` — whether the entry can be deleted
IMPORTANT: When recipe_id is present, use get_recipe to resolve it to the
recipe name for display. Never show raw recipe IDs.
Returns an error message string on failure. Returns an error message string on failure.
""" """
if date_err := _validate_date(date_from): if date_err := _validate_date(date_from):