feat(recipes): add get_recipe_box + parser-fix ingredients_parsed (v0.11.7)

- New tool get_recipe_box: filtered version of get_recipes returning only real recipes (isRecipe=true), excluding stubs created for free-text meal entries
- Parser fix: ingredients_parsed now generated from free-text ingredients field instead of API's ingredientsList which has parser bug on comma+space (e.g. '1, 5g' breaks)
- Updated SPEC.md with parser bug documentation
- Updated version to 0.11.7 in __init__.py and pyproject.toml
- Updated .gitignore to exclude debug/test scripts

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-04-17 13:55:05 +02:00
parent 343e8eeb58
commit 5e3b7e08a3
12 changed files with 222 additions and 10 deletions
+11
View File
@@ -0,0 +1,11 @@
{
"permissions": {
"allow": [
"Bash(ruff format *)",
"Bash(ruff check *)",
"Bash(uv run *)",
"Bash(git add *)",
"Bash(git commit -m ' *)"
]
}
}
+7
View File
@@ -41,3 +41,10 @@ htmlcov/
# uv # uv
uv.lock uv.lock
# Debug and test scripts
debug_*.py
probe_*.py
probe_*.txt
p*_err.txt
test_*.py
+4 -3
View File
@@ -24,7 +24,7 @@ und wird in Claude Desktop eingebunden.
## Aktueller Stand ## Aktueller Stand
### Implementierte Tools (v0.11.6) ### Implementierte Tools (v0.11.7)
| Kategorie | Tools | | Kategorie | Tools |
|---|---| |---|---|
@@ -33,7 +33,7 @@ und wird in Claude Desktop eingebunden.
| Listen | `create_list`, `update_list`, `delete_list` | | Listen | `create_list`, `update_list`, `delete_list` |
| Kategorien | `create_category`, `delete_category` | | Kategorien | `create_category`, `delete_category` |
| Aktivitäten | `like_post` | | Aktivitäten | `like_post` |
| Rezepte | `get_recipes`, `get_recipe`, `create_recipe`, `update_recipe`, `delete_recipe`, `get_recipe_categories` | | Rezepte | `get_recipes`, `get_recipe_box`, `get_recipe`, `create_recipe`, `update_recipe`, `delete_recipe`, `get_recipe_categories` |
| Essensplaner | `get_meal_plan`, `add_recipe_to_meal_plan`, `add_meal_to_meal_plan`, `add_meal_note`, `delete_meal_plan_entry` | | Essensplaner | `get_meal_plan`, `add_recipe_to_meal_plan`, `add_meal_to_meal_plan`, `add_meal_note`, `delete_meal_plan_entry` |
| Kreise | `create_circle`, `update_circle`, `delete_circle`, `add_member_to_circle` | | Kreise | `create_circle`, `update_circle`, `delete_circle`, `add_member_to_circle` |
@@ -69,7 +69,8 @@ und wird in Claude Desktop eingebunden.
- v0.11.3: add_meal_to_meal_plan strukturierter Output (a00.r.r ist Array, nicht Objekt) ✓ - v0.11.3: add_meal_to_meal_plan strukturierter Output (a00.r.r ist Array, nicht Objekt) ✓
- v0.11.4: delete_meal_plan_entry (metadelete für dish/ und meal/-Objekte) ✓ - v0.11.4: delete_meal_plan_entry (metadelete für dish/ und meal/-Objekte) ✓
- v0.11.5: add_meal_note (mpmealput; Notiz + Portionen; strukturierter Output) ✓ - v0.11.5: add_meal_note (mpmealput; Notiz + Portionen; strukturierter Output) ✓
- v0.11.6: clear_list (alle Tasks einer Liste in einer Session löschen; bulk delete) ✓ ← aktuell - v0.11.6: clear_list (alle Tasks einer Liste in einer Session löschen; bulk delete) ✓
- v0.11.7: get_recipe_box (nur echte Rezepte, isRecipe=true) + Parser-Fix ingredients_parsed aus Freitext statt API-List ✓ ← aktuell
- v2.0: Schreibzugriff auf Wall-Posts (Erstellen, Kommentieren) - v2.0: Schreibzugriff auf Wall-Posts (Erstellen, Kommentieren)
+3 -2
View File
@@ -2,7 +2,7 @@
MCP server for [Family Wall](https://www.familywall.com) -- read and manage your family's circles, lists, tasks, and recipes directly from Claude. MCP server for [Family Wall](https://www.familywall.com) -- read and manage your family's circles, lists, tasks, and recipes directly from Claude.
## Features (v0.11.6) ## Features (v0.11.7)
### Read ### Read
@@ -13,7 +13,8 @@ MCP server for [Family Wall](https://www.familywall.com) -- read and manage your
- `get_categories` -- list categories for a list (locale-filtered; custom categories always included; `custom` flag marks user-created ones) - `get_categories` -- list categories for a list (locale-filtered; custom categories always included; `custom` flag marks user-created ones)
- `get_activities` -- list recent wall activities (author resolved to display name) - `get_activities` -- list recent wall activities (author resolved to display name)
- `get_recipes` -- list all family recipes (compact summary: id, name, prep/cook time, serves) - `get_recipes` -- list all family recipes (compact summary: id, name, prep/cook time, serves)
- `get_recipe` -- get a single recipe in full detail (ingredients, instructions, ingredients_parsed, category_ids, etc.) - `get_recipe_box` -- list only real recipes from the recipe box (excludes stubs created for free-text meal entries)
- `get_recipe` -- get a single recipe in full detail (ingredients, instructions, ingredients_parsed, category_ids, etc.; ingredients_parsed generated from free-text field to avoid parser bugs)
- `get_recipe_categories` -- list all available recipe categories (always returns all 5 standard categories: Bei Kindern beliebt, Wirklich einfach, Nachspeisen, Schmeckt toll, Gemüse; plus any additional categories found in existing recipes) - `get_recipe_categories` -- list all available recipe categories (always returns all 5 standard categories: Bei Kindern beliebt, Wirklich einfach, Nachspeisen, Schmeckt toll, Gemüse; plus any additional categories found in existing recipes)
- `get_meal_plan` -- get meal plan entries for a date range (Premium feature; merges dish and meal entries, sorted by date + type; fields: id, date, type, name, recipe_id, is_from_recipe_box, note, serves, can_update, can_delete) - `get_meal_plan` -- get meal plan entries for a date range (Premium feature; merges dish and meal entries, sorted by date + type; fields: id, date, type, name, recipe_id, is_from_recipe_box, note, serves, can_update, can_delete)
+4
View File
@@ -503,6 +503,10 @@ a00.r.r → vollständiges Rezept-Objekt
.familyId, .accountId, .creationDate, .moodMap, .moodStarShortcut .familyId, .accountId, .creationDate, .moodMap, .moodStarShortcut
``` ```
**Parser-Bug (v0.11.7):** Das Feld `.ingredientsList[]` wird vom Server geparst und hat einen Bug
bei Komma+Leerzeichen (z.B. "1, 5g" wird abgeschnitten). Der MCP-Client ignoriert `.ingredientsList`
und generiert `ingredients_parsed` stattdessen client-seitig durch Splitting von `.ingredients` auf `\r\n`/`\n`.
**Verifiziert am:** 2026-04-16 via FW_DEBUG=1 **Verifiziert am:** 2026-04-16 via FW_DEBUG=1
### `mprecipeput` Rezept aktualisieren (Update) ### `mprecipeput` Rezept aktualisieren (Update)
+157
View File
File diff suppressed because one or more lines are too long
View File
+1 -1
View File
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
[project] [project]
name = "mcp-familywall" name = "mcp-familywall"
version = "0.11.6" version = "0.11.7"
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"
Submodule reference/mcp-synology added at fdeac08dff
+1 -1
View File
@@ -1 +1 @@
__version__ = "0.11.6" __version__ = "0.11.7"
+7 -3
View File
@@ -71,9 +71,13 @@ def parse_recipe_full(raw: dict[str, Any]) -> dict[str, Any]:
cook = raw.get("cookTime") cook = raw.get("cookTime")
srv = raw.get("serves") srv = raw.get("serves")
# ingredientsList is auto-parsed by the server; normalise to a plain list of names. # Parse ingredients from the free-text ingredients field.
ingredients_list_raw: list[dict[str, Any]] = raw.get("ingredientsList") or [] # The API's ingredientsList has a parser bug: it breaks on comma+space (e.g. "1, 5g").
ingredients_parsed = [item.get("name") for item in ingredients_list_raw if item.get("name")] # We parse the raw ingredients text instead by splitting on \r\n and \n.
raw_ingredients = raw.get("ingredients") or ""
ingredients_parsed = [
line.strip() for line in raw_ingredients.replace("\r\n", "\n").split("\n") if line.strip()
]
# Extract recipe categories from API response. # Extract recipe categories from API response.
# The API provides both recipeCategoryIdList (actual IDs) and recipeCategories # The API provides both recipeCategoryIdList (actual IDs) and recipeCategories
+26
View File
@@ -1956,6 +1956,32 @@ def get_recipes() -> str:
return json.dumps(result, ensure_ascii=False, indent=2) return json.dumps(result, ensure_ascii=False, indent=2)
# ---------------------------------------------------------------------------
# Tool: get_recipe_box
# ---------------------------------------------------------------------------
@mcp.tool()
def get_recipe_box() -> str:
"""Return only real recipes from the recipe box (isRecipe=true).
Excludes stub recipes that are auto-created when free-text meal plan
entries are added. Use this for meal planning and ingredient lookups.
For the full list including stubs use get_recipes.
Returns:
JSON list of recipe summary objects (same format as get_recipes).
Returns an error message string on failure.
"""
try:
raw_recipes = _get_raw_recipes()
except RuntimeError as exc:
return f"Error: {exc}"
result = [parse_recipe_summary(r) for r in raw_recipes if r.get("isRecipe") == "true"]
return json.dumps(result, ensure_ascii=False, indent=2)
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------
# Tool: get_recipe # Tool: get_recipe
# --------------------------------------------------------------------------- # ---------------------------------------------------------------------------