feat(meal-planner): add add_meal_note tool (v0.11.5)
New write tool using mpmealput endpoint to create meal/ note entries with optional free-text and serving count. Response structure verified from JS-bundle (Sg class); a00.r.r is a plain object (unlike mpcreate). Structured output matches get_meal_plan meal entry format. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -1 +1 @@
|
||||
__version__ = "0.11.4"
|
||||
__version__ = "0.11.5"
|
||||
|
||||
@@ -2499,6 +2499,79 @@ def delete_meal_plan_entry(entry_id: str) -> str:
|
||||
return json.dumps({"deleted": True, "id": entry_id}, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Tool: add_meal_note
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
@mcp.tool()
|
||||
def add_meal_note(
|
||||
date: str,
|
||||
meal_type: str,
|
||||
note: str | None = None,
|
||||
serves: int | None = None,
|
||||
) -> str:
|
||||
"""Add a note and/or serving count to a meal plan slot.
|
||||
|
||||
IMPORTANT: Ask the user for confirmation before calling this tool.
|
||||
|
||||
Creates a ``meal/`` entry for the given date and meal type.
|
||||
At least one of ``note`` or ``serves`` must be provided.
|
||||
|
||||
Args:
|
||||
date: Target date in ISO format (e.g. ``"2026-04-20"``).
|
||||
meal_type: Meal slot — one of ``"BREAKFAST"``, ``"LUNCH"``,
|
||||
``"SNACK"``, or ``"DINNER"``.
|
||||
note: Optional free-text note (e.g. ``"Bitte ohne Zwiebeln"``).
|
||||
serves: Optional number of servings as integer (e.g. ``4``).
|
||||
|
||||
Returns:
|
||||
JSON with the new meal entry on success, or an error message.
|
||||
"""
|
||||
if meal_type not in ("BREAKFAST", "LUNCH", "SNACK", "DINNER"):
|
||||
return "Error: meal_type must be one of 'BREAKFAST', 'LUNCH', 'SNACK', 'DINNER'."
|
||||
if note is None and serves is None:
|
||||
return "Error: At least one of 'note' or 'serves' must be provided."
|
||||
|
||||
params: dict[str, Any] = {"date": date, "type": meal_type}
|
||||
if note is not None:
|
||||
params["note"] = note
|
||||
if serves is not None:
|
||||
params["serves"] = str(serves) # API expects string (int→string)
|
||||
|
||||
try:
|
||||
data = _authenticated_call("mpmealput", params)
|
||||
except RuntimeError as exc:
|
||||
return f"Error: {exc}"
|
||||
|
||||
try:
|
||||
meal = data["a00"]["r"]["r"]
|
||||
if not isinstance(meal, dict) or "metaId" not in meal:
|
||||
raise TypeError("unexpected shape")
|
||||
except (KeyError, TypeError):
|
||||
return json.dumps(
|
||||
{"warning": "Unexpected mpmealput response structure", "raw": data},
|
||||
ensure_ascii=False,
|
||||
indent=2,
|
||||
)
|
||||
|
||||
rights = meal.get("rights") or {}
|
||||
raw_serves = meal.get("serves")
|
||||
result: dict[str, Any] = {
|
||||
"id": meal.get("metaId"),
|
||||
"date": meal.get("date"),
|
||||
"type": meal.get("type"),
|
||||
"name": None,
|
||||
"recipe_id": None,
|
||||
"is_from_recipe_box": None,
|
||||
"note": meal.get("note") or None,
|
||||
"serves": int(raw_serves) if raw_serves is not None else None,
|
||||
"can_update": rights.get("canUpdate") == "true",
|
||||
"can_delete": rights.get("canDelete") == "true",
|
||||
}
|
||||
return json.dumps(result, ensure_ascii=False, indent=2)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Factory
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user