Skip to content

Add recipe creation functions - #43

Merged
rwestergren merged 2 commits into
rwestergren:mainfrom
jep513:feat/create-recipe
Aug 22, 2026
Merged

Add recipe creation functions#43
rwestergren merged 2 commits into
rwestergren:mainfrom
jep513:feat/create-recipe

Conversation

@jep513

@jep513 jep513 commented Aug 16, 2026

Copy link
Copy Markdown
Contributor

What

create_recipe(name, ingredients=[(food_id, grams), ...]) on the client,
plus an add_recipe MCP tool.

How the payload shape was established

Recipes go through the existing /api/v2/add_food endpoint — what makes a
food a recipe is the presence of an ingredients array. I confirmed that
rather than assuming it.

Shape came from decoding the web app's GWT-RPC addFood/editFood calls
across five captures (serving-based and weight-based, simple and advanced
serving sizes), then reading the results back through this client to see
how the mobile API represents the same food. I did not attempt to intercept
the mobile app.

Verified with one POST and a read-back diff (food 79474948):

  • ingredients round-trip exactly — foodId, measureId, translationId and
    grams all preserved, with server-assigned row IDs
  • all four measures preserved with their exact values
  • defaultMeasureId sent as 0 comes back assigned from the first measure
    in the array
  • 93 nutrients sent, 90 stored: 318, 325 and 326 were dropped as outside
    the account's catalog
  • net carbs is recomputed server-side as carbs − fibre − sugar alcohol, so
    sending it is advisory
  • source and owner sent as null come back set correctly

Design notes

Weight-based rather than serving-based. Cronometer supports both: serving-
based recipes use type: "Recipe" measures and store nutrients per batch,
which is what makes the diary's grams field a serving count — the quirk
enrich_diary_servings already handles. Weight-based uses type: "Weight"
measures with nutrients per-100g, matching create_custom_food's existing
convention and avoiding that quirk entirely.

Ingredients are (food_id, grams). The measure ID is display metadata —
Cronometer renders the amount as grams / measure value — so it's resolved
automatically to the food's gram measure. A three-tuple overrides it where
that matters.

One batched get_foods resolves every ingredient. Unresolvable IDs raise
rather than being silently dropped. Input is validated before any network
call, so a malformed tuple fails fast.

Tests

Five: payload shape (ingredients, weight-based measures, per-100g
aggregation), explicit serving size and comments, measure-ID override,
input validation, and missing-food handling. Plus add_recipe added to the
tool-registry set — which caught the omission on its first run.

jep513 and others added 2 commits August 15, 2026 12:37
# Conflicts:
#	src/cronometer_api_mcp/client.py
#	tests/test_client.py

@rwestergren rwestergren left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good, thank you

@rwestergren
rwestergren merged commit bc19046 into rwestergren:main Aug 22, 2026
1 check passed
@jep513

jep513 commented Aug 23, 2026

Copy link
Copy Markdown
Contributor Author

Thanks for reviewing and merging. Glad this was useful

@jep513
jep513 deleted the feat/create-recipe branch August 23, 2026 02:12
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants