MCP App Store
by KeenEthics
Business & Operations
BetterMenu icon

BetterMenu

by BetterMenu

Overview

BetterMenu keeps recipe formulation, nutrition analysis and FDA labeling in one versioned system, so compliance stops being a separate project at the end of development. Search standard and branded ingredients, resolve kitchen measures to gram weights, and calculate per-serving and per-container nutrition against the FDA reference values in 21 CFR 101. Add custom ingredients with your own nutrition data, set serving sizes, and export the Nutrition Facts label. Every recipe is versioned: reformulate freely, then see which ingredient change moved which nutrient, and which version any given label came from. Values carry their source, so you can answer where a number came from without reconstructing it. For food manufacturers, co-packers, and R&D and regulatory teams working on packaged food sold in the United States.

Tools

add_recipe_serving_size

ChatGPT
Use this when the user wants per-serving nutrition facts, calories per serving, %DV or an FDA-format Nutrition Facts label for a saved recipe, or tells you its serving size or yield ("makes 8 bars"). Adds a serving to the recipe and computes its per-serving nutrition facts in the same call. Returns the serving, whose id the per-serving tools take as serving_id. Needs the recipe's id and current version_id, and ingredients saved with set_recipe_ingredients: without them there is no nutrition to divide. serving_size is one of: - user_provided: household_amount and household_unit ("1", "bar"), and metric_amount with metric_unit (g or mL). For "makes 8 bars", one bar is the recipe's total grams divided by 8. - racc_guided: the US FDA reference amount (RACC) for a product category. Needs category_id from find_fda_serving_size_category, unit_type (discrete, large_discrete or bulk) and, for discrete units, unit_weight_g. Next: get_recipe_nutrition_facts_per_serving for the numbers, get_recipe_nutrition_facts_label for the label, export_nutrition_facts_label_file for a file. Do not use to change an existing serving; use update_recipe_serving_size.

archive_custom_ingredient

ChatGPT
Use this when the user wants to stop using a custom ingredient in new recipes, for example a discontinued supplier product. Moves an active ingredient to archived. It stays readable, and recipes that already use it keep their pinned version, but it no longer appears in search_ingredients_for_nutrition, cannot be added to recipes and cannot be edited. Reverse with unarchive_custom_ingredient. Archiving an already archived ingredient changes nothing and returns its current version_id. A draft cannot be archived; to remove a draft that no recipe uses, use delete_custom_ingredient.

archive_recipe

ChatGPT
Use this when the user wants to put a saved recipe aside without deleting it. Needs recipe_id and the recipe's current version_id (from get_recipe or the last change). Sets its status to archived: it stays readable, keeps its history and appears in list_saved_recipes with status archived, but it cannot be changed until unarchive_recipe. Returns the recipe and its new version_id. To remove a recipe permanently, use delete_recipe.

confirm_custom_ingredient

ChatGPT
Use this when the user has checked a draft custom ingredient and wants to use it in recipes. Moves it from draft to active. Only active custom ingredients appear in search_ingredients_for_nutrition and can be added with set_recipe_ingredients (source custom_ingredient). An active ingredient stays editable. Returns the ingredient and its new version_id. Needs the id from create_custom_ingredient or list_custom_ingredients. Works only on a draft: an active ingredient needs no confirm, and an archived one needs unarchive_custom_ingredient.

confirm_recipe_added_sugars

ChatGPT
Use this when the user has reviewed the Added Sugars report of a saved recipe and wants to confirm it, so the Added Sugars line appears on the recipe's nutrition label and in its nutrition analysis. Needs recipe_id, the report_hash of the report the user was shown (exactly as get_recipe_added_sugars returned it) and the recipe's current version_id. Confirming is the user's own attestation that the report is right. When you call it for them, only do so after you have shown them the report and they have told you to confirm it. Never confirm on your own judgement, and never to get past a missing answer. It records who confirmed and that the request came from an agent, saves a new version with the confirmed value on the label, and returns the report, its report_hash, confirmation and the new version_id, in the same shape as get_recipe_added_sugars, with absent values returned as null. confirmation_stands is true while the confirmation holds. Changing the ingredient or its pinned custom-ingredient version reopens that row: the earlier answer is dropped and the confirmation goes stale. Adding or removing an ingredient, the demographic or an answer does the same; the user has to confirm again. Changing a quantity, serving size or number of servings does not: the label is recomputed, and a quantity that would push added sugars above total sugars is still refused. A confirmation made before this rule goes stale on any change. Only the latest confirmation counts: restoring a version with other answers reads stale until confirmed again. It is refused when the report_hash is not the current report's (read the report again), when the report still has unanswered rows or findings (the error lists the rows), or when the recipe changed since version_id (read the recipe and retry). Confirming a report that is already confirmed records nothing new and returns the existing confirmation. Do not use for answering rows of the report; those answers are saved with the tool that changes one row.

convert_ingredient_amounts_to_grams

ChatGPT
Use this when the user asks how much an amount of an ingredient weighs ("how many grams is 2 cups of flour?"), or when you need gram weights for a recipe's ingredients before saving them with set_recipe_ingredients. Nutrition is computed from grams, so every ingredient needs one. Send all items in one call: each is an ingredient_id from search_ingredients_for_nutrition (a standard hit), a quantity and a unit (empty for a count, such as "3 eggs"). For a branded product's serving, pass portion_id (from get_ingredient_nutrition_facts's portions[].id) instead of a unit. Saves nothing, so it is safe for exploring. Each item returns status: - ok: gram_weight.quantity_grams, and gram_weight.conversion_source saying how it was reached. USDA_FOOD_PORTIONS, USDA_MEASUREMENT_TABLES and identity are exact conversions; system_estimate is an estimate and carries gram_weight.estimate: an explanation already written as a sentence, low_grams/high_grams, and basis. Report the explanation as it stands with the range beside it, since a lone figure reads as precision an estimate does not have. - needs_resolution: no exact conversion. Do not stop and ask: reason out a weight yourself, or call again with allow_estimation: true when that option is listed, and keep going. Then give every estimated line its estimate.explanation and range in one message, and invite a correction — a weight the user gives beats any estimate and is passed as metric_quantity_g to set_recipe_ingredients. Ask outright only when no estimate can be produced, which is when resolve_options lists the ask-the-user option alone. An option's action.operationId is the operation's REST name; here it means set_recipe_ingredients or this tool. - error: an invalid quantity or an unknown ingredient. Next: set_recipe_ingredients, using quantity_grams as metric_quantity_g and gram_weight.portion_reference.portion_bmid as portion_id when present.

create_custom_ingredient

ChatGPT
Use this when the user wants to add their own ingredient to BetterMenu, such as a supplier's product with its own nutrition panel or spec sheet, so their recipes can use it for US FDA nutrition facts. Creates a draft from name. nutrients and the serving fields (reference_amount, reference_unit, household_measure, reference_quantity_g, density_g_per_ml) can go in the same call. approved_markets defaults to US. Returns the ingredient in data (its id is cing_…) and its version_id. Each nutrient amount is per the serving whose weight is reference_quantity_g grams; without that weight the ingredient adds no nutrients to a recipe. A nutrient counts on US labels only with a market_nutrients.US entry. amount: null means unknown, not zero. A draft does not appear in search_ingredients_for_nutrition and cannot go in a recipe. Next: confirm_custom_ingredient, then set_recipe_ingredients with source custom_ingredient. To change values later: set_custom_ingredient_nutrition, set_custom_ingredient_serving_size. Do not use for an ingredient BetterMenu already has in its standard data; find that with search_ingredients_for_nutrition.

create_recipe_for_nutrition_label

ChatGPT
Use this when the user wants to save a recipe in BetterMenu, or wants US nutrition facts, calories per serving, %DV or an FDA-format label for a recipe they make or sell (pasted, or from a recipe page). It saves a recipe to the user's account, so ask the user before calling it. First look for an existing recipe with find_saved_recipes; if one matches, confirm with the user whether to use it. Per-serving facts and labels are computed for saved recipes. Values are computed from USDA data and the user's custom ingredients, under US FDA rules (market "US"). BetterMenu does not fetch URLs; it takes ingredient lines. Take a recipe page's yield with them, and ask for the yield if the page gives none. Creates an empty recipe from a name and returns its id as data.id, plus a version_id. Only name is required, and it must be unique in the organization; if it is taken, ask for another name. country is US (FDA rules). demographic sets the %DV basis: adults_and_children_over_4 (default), infants_through_12_months, children_1_3_years or pregnant_and_lactating_women. You can run search_ingredients_for_nutrition and convert_ingredient_amounts_to_grams before or after this. Next: set_recipe_ingredients with this recipe's id and version_id, then add_recipe_serving_size. To rename a recipe, use update_recipe_details.

delete_custom_ingredient

ChatGPT
Use this when the user wants to remove a custom ingredient they created by mistake, such as a misnamed or duplicate draft. Works only on a draft that was never confirmed and that no recipe uses. For an ingredient that is or was active, use archive_custom_ingredient. The delete is permanent: restore_custom_ingredient_version cannot undo it. The ingredient stays readable with status deleted, and its history is kept. To check which recipes use an ingredient, use get_custom_ingredient_usage.

delete_recipe

ChatGPT
Use this when the user wants to delete a saved recipe permanently. Needs recipe_id and the recipe's current version_id (from get_recipe or the last change). A deleted recipe cannot be recovered: it disappears from list_saved_recipes and find_saved_recipes, no tool can read it or its history, and restore_recipe_version cannot bring it back. If the recipe then reads as not found, it is already deleted. To keep a recipe but set it aside, use archive_recipe.

delete_recipe_serving_size

ChatGPT
Use this when the user wants to remove a serving size from a recipe. The serving no longer appears in list_recipe_serving_sizes; it stays in the recipe's audit trail. Returns no body. Needs the serving_id from list_recipe_serving_sizes and the recipe's current version_id (from the last write, get_recipe or list_recipe_serving_sizes). Before the next change to the recipe, get the new version_id from get_recipe. Do not use for changing a serving size; use update_recipe_serving_size.

export_nutrition_facts_label_file

ChatGPT
Use this when the user wants a downloadable US FDA Nutrition Facts label file for one serving of a recipe, to print or put on packaging or a website. Renders the label as PDF (default), PNG or JPEG; request several with formats. resolution is print (300 DPI, default) or digital (96 DPI). Returns one artifact_url per format, a download link valid until its expires_at, and the recipe version_id rendered. Give the user the link. A DRAFT watermark is on by default; pass draft_watermark false for the final label. During a trial, or when the plan cannot be confirmed, the watermark is always applied. An organization without an active subscription can re-download labels already made but cannot make new ones. Needs a serving_id with nutrition facts (from list_recipe_serving_sizes or add_recipe_serving_size). Do not use for the label content as data; use get_recipe_nutrition_facts_label.

find_fda_serving_size_category

ChatGPT
Use this when the user asks what serving size to use for a food on a US Nutrition Facts label ("what serving size should I use for cookies?"), or wants the US FDA serving-size category for a food. Categories are the FDA Reference Amounts Customarily Consumed (RACC, 21 CFR 101.12). Takes a name query q (for example "cookies") and an optional audience (general or infant_toddler). Returns matching categories ranked by relevance, each with its category_id, name, reference amount in grams (racc_g), unit_type, label_statements and cfr_reference. Next: add_recipe_serving_size, passing the chosen category_id to set a recipe's serving size from the category. get_fda_serving_size_category returns one category by id; list_fda_serving_size_categories lists them all.

find_saved_recipes

ChatGPT
Use this when the user refers to a recipe they already saved in BetterMenu by name, for example "my banana bread" or "the granola recipe", and you need its recipe_id. Searches the recipes the user can access by name (tolerates small typos and partial words) and returns matches most relevant first, each with id, name, status and updated_at. Pass q: "*" to match every recipe the user can access. Use the returned id as recipe_id in get_recipe, get_recipe_ingredients, get_recipe_total_nutrition or any other recipe tool. To browse recent recipes or filter by active or archived, use list_saved_recipes. Do not use for finding foods or ingredients to put in a recipe; use search_ingredients_for_nutrition.

get_custom_ingredient

ChatGPT
Use this when the user wants to see one of their custom ingredients in full. Returns its name, status (draft, active, archived or deleted), nutrients, serving fields including reference_quantity_g, and approved_markets, plus the current version_id. Needs the id from list_custom_ingredients, create_custom_ingredient, or a search_ingredients_for_nutrition result with kind custom. For the ingredient as it was at an earlier version, use get_custom_ingredient_version. For the recipes that use it, use get_custom_ingredient_usage.

get_custom_ingredient_audit_trail

ChatGPT
Use this when the user wants a record of who changed a custom ingredient, when, and through which channel, for example for a compliance review. Returns events newest first, each with event_type (such as custom_ingredient.nutrition_set or custom_ingredient.confirmed), actor, channel, timestamp, changed_fields and the version_id it committed. On an agent-channel event, client names the app that made the call (claude, chatgpt, ...; null if unrecognized or recorded before this field existed) and client_id is its verified OAuth client id. Paginated: pass meta.cursor back as cursor. For the list of versions to view or restore, use list_custom_ingredient_versions.

get_custom_ingredient_usage

ChatGPT
Use this when the user wants to know which recipes use a custom ingredient, for example before changing, archiving or deleting it. Returns one row per recipe: recipe_id, recipe_name, recipe_status and pinned_version_id (the ingredient version that recipe uses). Set version_id to list only recipes pinned to that version. The list catches up with recipe changes within moments, not instantly. The version_id filter runs after each page is read, so a page can be short or empty while more matches remain: keep paging with meta.cursor while meta.has_more is true.

get_custom_ingredient_version

ChatGPT
Use this when the user wants to see a custom ingredient as it was at an earlier version, for example the values a recipe pinned. Needs version_id from list_custom_ingredient_versions or from a recipe's custom-ingredient row. Returns the full ingredient as of that version, in the same shape as get_custom_ingredient. For the current state, use get_custom_ingredient. To make this version current again, use restore_custom_ingredient_version.

get_custom_ingredient_version_changes

ChatGPT
Use this when the user wants to know what changed in a custom ingredient at one version, or between two versions. Needs version_id from list_custom_ingredient_versions; compared_to defaults to that version's parent and must differ from version_id. Returns data.field_changes, a diff of only the fields that changed (before is the comparison point, after is version_id); an empty map means no difference. data.field_relevance marks each changed field label_affecting (changes nutrition results), availability_affecting (changes whether it can be found or added to new recipes) or non_label_affecting.

get_fda_daily_value

ChatGPT
Use this when the user wants the US FDA Daily Value for one nutrient, the reference amount a US label's %DV is calculated against (21 CFR 101.9), for example "what's the daily value for sodium?". Do not use to explain what %DV means in general. Takes a nutrient id bmid (for example n_protein, n_vitamin_c, n_calcium) and a required demographic: adults_and_children_over_4, children_1_3_years, infants_through_12_months or pregnant_and_lactating_women. Daily Values differ between these groups. Returns the nutrient's name, daily_value and unit, with the regulation reference. Do not use for a recipe's %DV; get_recipe_nutrition_facts_per_serving returns it. list_fda_daily_values returns every nutrient at once.

get_fda_serving_size_category

ChatGPT
Use this when the user wants the details of one US FDA serving-size category, for example the reference amount for cookies or bread. Categories are the FDA Reference Amounts Customarily Consumed (RACC, 21 CFR 101.12), which set the serving size on a US Nutrition Facts label. Takes a category_id (for example racc_cookies_crackers) and returns the category's name, reference amount in grams (racc_g), unit_type, label_statements, target_audience and cfr_reference. Ids come from find_fda_serving_size_category or list_fda_serving_size_categories. Next: add_recipe_serving_size, passing the category_id to set a recipe's serving size from the category.

get_ingredient_nutrition_facts

ChatGPT
Use this when the user wants USDA-sourced nutrition for one food or ingredient, such as "calories in an apple" or "protein in 100 g chicken breast", including packaged and branded products (USDA branded foods), or the details of one of their own custom ingredients. Values are computed from USDA data and the user's custom ingredients, under US FDA rules (market "US"). Takes an ingredient id from search_ingredients_for_nutrition (or list_ingredients_used_in_recipes, get_recipe_ingredients) and market ("US"). Returns name, kind (custom or standard), status, used_in_recipes, nutrients and portions. Every nutrient held is returned (often about 100 rows), each with amount, unit and basis: per_100g for standard ingredients, per_reference_serving for custom ones, so do not compare the two directly. portions gives household amounts with their gram_weight (for example a medium apple, 182 g): scale a per-100 g amount by gram_weight / 100. For a comparison, such as butter vs margarine, look up each food. Do not use for finding an ingredient by name; use search_ingredients_for_nutrition. For an amount the portions do not cover, convert_ingredient_amounts_to_grams gives grams.

get_ingredient_usage

ChatGPT
Use this when the user wants to know which of their recipes use a given ingredient, for example before they change or archive it. Works for standard (f_…) and custom (cing_…) ingredient ids. Returns one entry per recipe with recipe_id, recipe_name, recipe_status, source and, for custom ingredients, pinned_version_id. The list is kept up to date in the background, so a recipe saved a moment ago can take a short time to appear. To page, pass meta.cursor back and continue until meta.has_more is false. With version_id set, a page can hold fewer entries than limit, even none, while more matches remain, so keep paging. Ids come from search_ingredients_for_nutrition or list_ingredients_used_in_recipes. Next: get_recipe for any recipe in the list.

get_latest_ingredient_resolution

ChatGPT
Use this when the user wants to see how a recipe's pasted ingredient lines were last matched to foods and gram weights, for example to check why a line got a certain weight. Needs recipe_id. Returns the latest resolution: its resolution_id, summary (with ready_to_confirm) and one row per line with the matched ingredient_id, the candidates considered, quantity_grams and the conversion steps. A recipe whose ingredients were set with set_recipe_ingredients has no resolution, so this returns not found. Do not use for reading a recipe's current ingredients; use get_recipe_ingredients. list_ingredient_resolutions returns every past resolution.

get_nutrition_label_settings

ChatGPT
Use this when the user wants to see which nutrients a recipe's US FDA Nutrition Facts label shows, or before changing that. Returns every nutrient with visible, is_mandatory, is_toggleable, display_name, allowed_synonyms and source (regulatory default, account or recipe), and has_custom_configuration. A recipe with no custom settings returns the defaults. Next: set_nutrition_label_settings to show, hide or rename optional nutrients. Do not use for the label's nutrient values; use get_recipe_nutrition_facts_label.

get_plan_and_usage

ChatGPT
Use this when the user asks about their BetterMenu plan or usage, for example which plan they are on, how much of their monthly quota is left, when a trial ends, or why a feature is unavailable. Returns plan_name and display_name, trial state (is_trialing, trial_ends_at, trial_days_remaining), pending_cancellation_at, feature_gates, and quotas, each with limit, used, remaining and resets_at. During a trial, limit is the trial limit. write_access and write_access_reason say whether the organization can save changes, and metered_usage_enabled says whether it accepts usage beyond its included monthly allowance.

get_recipe

ChatGPT
Use this when the user asks about one of their saved recipes and you need its current state, or before you change it. Needs recipe_id from find_saved_recipes, list_saved_recipes or create_recipe_for_nutrition_label. Returns the recipe's name, status (active or archived), country, demographic (the group whose US FDA Daily Values set %DV), and a summary: ingredient_count, serving_count, has_nutrition and is_nutrition_current. actions says whether the user can modify, archive or delete it. The top-level version_id is the recipe's current version; the tools that change a recipe need it. Pass version_id to read the recipe as it was at an earlier version from list_recipe_versions. Next: get_recipe_ingredients for the ingredient list, list_recipe_serving_sizes for servings, get_recipe_total_nutrition for nutrition.

get_recipe_added_sugars

ChatGPT
Use this when the user wants to know how the Added Sugars figure on a saved recipe's label was worked out, which ingredient rows are still open, or whether a person has confirmed it. Needs recipe_id from find_saved_recipes, list_saved_recipes or create_recipe_for_nutrition_label. It only reads. Answering rows and confirming the report are a person's decisions, made in BetterMenu; until a person confirms, an export lists Added Sugars as a finding. data.report is the report, or null when the recipe has none. determination has one row per ingredient (grams counted, per 100 g in added_sugars_per_100g, who settled it), the totals, the declared amount per serving with %DV, and findings. A row is settled when effective.source is set. presentation.readiness counts open rows. Rows and the report carry checks: status (ok, needs_answer, problem), a summary sentence in the recipe's own numbers, a docs_url, and on any check that is not ok also why_it_matters and the rule's exact words in citation.quote. No Total Sugars leaves those figures absent: presentation.total_sugars_complete is false and rows_without_total_sugars names the rows. data.confirmation: - confirmed: a person confirmed these answers. Quantity, serving or servings changes keep it. - stale: an ingredient, the demographic or an answer changed since, or an earlier version was read. - unconfirmed: never confirmed. ungated: no report. - unreadable: treat as not confirmed. Only a confirmed report puts Added Sugars on the label. data.report_hash fingerprints the answers; version_id is the version read. Pass version_id from list_recipe_versions to read an earlier version. Do not use for the label itself; use get_recipe_nutrition_facts_label.

get_recipe_audit_trail

ChatGPT
Use this when the user asks who changed a saved recipe, when, or why, for example "who edited the ingredients last week?". Needs recipe_id. Returns the recipe's change events, newest first. Each event has its event_type, the actor who made it, the channel, a timestamp, the version_id it produced (when it produced one), and, on some edits, the changed fields or the reason the user gave. On an agent-channel event, client names the app that made the call (claude, chatgpt, ...; null if unrecognized or recorded before this field existed) and client_id is its verified OAuth client id. Narrow with event_type, actor_id, actor_type, the from/to time range, or since_version_id/up_to_version_id. For more, pass meta.cursor back as cursor while meta.has_more is true. With the actor or version filters a page can hold fewer events than limit, even none, while more exist; keep paging. With event_type you get one page only, and meta.has_more is always false: narrow from/to or raise limit to see more. Do not use for the list of saved versions or for a diff; use list_recipe_versions and get_recipe_version_changes.

get_recipe_ingredients

ChatGPT
Use this when the user wants to see the ingredients of a saved recipe, or before you edit them. Needs recipe_id from find_saved_recipes, list_saved_recipes or create_recipe_for_nutrition_label. Returns the ingredients in order. Each row has its id, position, display_name, the matched food (selected_ingredient_id, selected_ingredient_name) and its weight in grams (metric_quantity_g), which nutrition uses. The top-level version_id is the recipe's current version, and ingredients_entry_method is the entry method the recipe is locked to. Pass version_id to read the ingredients as they were at an earlier version from list_recipe_versions. To change the list, send the full list to set_recipe_ingredients, keeping each existing row's id.

get_recipe_nutrition_analysis

ChatGPT
Use this when the user asks which ingredients contribute the most to a nutrient in a recipe, for example what drives the sodium or saturated fat. Returns, for each nutrient, the whole-batch total and each ingredient's contribution, sorted largest first, with an ingredient index (name, grams, original line). Filter with nutrient_set (for example fda_mandatory, macronutrients, vitamins_minerals) and limit with top_n. Needs recipe_id with ingredients saved by set_recipe_ingredients. Do not use for the batch totals alone; use get_recipe_total_nutrition. Do not use for one serving's contributions with FDA rounding; use get_recipe_serving_nutrition_analysis.

get_recipe_nutrition_facts_label

ChatGPT
Use this when the user wants the US FDA Nutrition Facts label for a saved recipe: what goes on it, or to show it. Returns the label content for one serving, ready to render: the header (servings per container, serving size, calories), nutrients in regulatory order with rounded amounts and %DV, the per-container column when there is one, footnotes, and whether the label is complete and current. Needs the recipe's id and a serving_id from add_recipe_serving_size or list_recipe_serving_sizes. Pass version_id to read an earlier version. Next: export_nutrition_facts_label_file for a printable PDF, PNG or JPEG file. Do not use for plain per-serving numbers; use get_recipe_nutrition_facts_per_serving.

get_recipe_nutrition_facts_per_container

ChatGPT
Use this when the user wants the nutrition for a whole package, the per-container column of a US FDA dual-column Nutrition Facts label. Returns FDA-rounded amounts, label display text and %DV for the full container, and reference_weight_grams, the container weight. Exists only for a serving whose dual_column_status is required or voluntary; check has_per_container_nutrition_facts in list_recipe_serving_sizes or get_recipe_serving_size. Needs a serving_id. Do not use for per-serving values; use get_recipe_nutrition_facts_per_serving. Do not use for the whole recipe batch; use get_recipe_total_nutrition.

get_recipe_nutrition_facts_per_serving

ChatGPT
Use this when the user asks for a saved recipe's nutrition per serving: calories, nutrients or %DV. Returns one serving's nutrient values rounded under US FDA rules (21 CFR 101.9), with %DV for the recipe's demographic. Needs the recipe's id and a serving_id from add_recipe_serving_size or list_recipe_serving_sizes. Pass version_id to read an earlier version. Do not use for the whole recipe's unrounded totals (get_recipe_total_nutrition), the label layout (get_recipe_nutrition_facts_label) or a label file (export_nutrition_facts_label_file).

get_recipe_serving_nutrition_analysis

ChatGPT
Use this when the user asks why a serving's Nutrition Facts show a value: which ingredients contribute to each nutrient in one serving, and how the US FDA rounding and %DV were applied. Returns, per nutrient, the unrounded per-serving amount, each ingredient's contribution scaled to the serving weight, the rounding rule and result, the %DV and its Daily Value reference, plus the serving's scale_factor against the batch. Filter with nutrient_set or bmids. Needs a serving_id from list_recipe_serving_sizes. Do not use for the plain label values; use get_recipe_nutrition_facts_per_serving. Do not use for whole-batch contributions; use get_recipe_nutrition_analysis.

get_recipe_serving_size

ChatGPT
Use this when you have a serving_id and need the detail of that one serving on a recipe. Returns its US FDA serving size (household measure, metric amount, servings per container), how it was set (user_provided or racc_guided, with the RACC inputs), dual_column_status, and whether per-serving and per-container nutrition facts exist. Also returns the recipe's version_id. Needs a serving_id from list_recipe_serving_sizes or add_recipe_serving_size. Do not use for the nutrient values of the serving; use get_recipe_nutrition_facts_per_serving.

get_recipe_total_nutrition

ChatGPT
Use this when the user wants the nutrient totals for a whole recipe batch, all ingredients summed. Returns each nutrient's total_amount and unit, and reference_weight_grams, the weight of the whole batch. Values are unrounded and carry no %DV; they come from USDA data and the user's custom ingredients. Nutrition is computed when ingredients are saved with set_recipe_ingredients. Do not use for per-serving Nutrition Facts, calories per serving or %DV; use get_recipe_nutrition_facts_per_serving. Do not use for which ingredient contributes what; use get_recipe_nutrition_analysis.

get_recipe_version_changes

ChatGPT
Use this when the user asks what changed in a saved recipe at a version, or how two versions differ. Needs recipe_id and a version_id from list_recipe_versions. Returns field_changes: only the recipe fields that differ, each with its before and after values. An empty map means the two versions are the same. By default it compares the version with the one before it. Pass compared_to to compare with another version. To preview a restore, pass the recipe's current version_id as compared_to and the older version as version_id: the result shows what restore_recipe_version would change. compared_to must differ from version_id.

list_custom_ingredient_versions

ChatGPT
Use this when the user wants to see the edit history of a custom ingredient. Returns its versions newest first, each with version_id, version_number, parent_version_id, created_at, created_by, a short summary of the change, and restored_from_version_id for restores. Up to 50 per page; pass meta.cursor back as after for the next page. Next: get_custom_ingredient_version for a version's full state, get_custom_ingredient_version_changes for what changed, restore_custom_ingredient_version to go back to one. For who made each change and through which channel, use get_custom_ingredient_audit_trail.

list_custom_ingredients

ChatGPT
Use this when the user wants to see the custom ingredients they have saved in BetterMenu, or find one by name to view or edit. Returns one summary per ingredient: id, name, status, created_at, updated_at. For nutrients and serving, use get_custom_ingredient. Returns every status, deleted included, unless status is set. The status filter runs after each page is read, so a page can be short or empty while more matches remain: keep paging with meta.cursor while meta.has_more is true. Do not use for picking an ingredient to add to a recipe; use search_ingredients_for_nutrition, which returns only active custom ingredients next to standard ones.

list_fda_daily_values

ChatGPT
Use this when the user wants the full table of US FDA Daily Values, or the Daily Values of several nutrients: the reference amounts a US label's %DV is calculated against (21 CFR 101.9). Do not use to explain what %DV means in general. Takes a required demographic: adults_and_children_over_4, children_1_3_years, infants_through_12_months or pregnant_and_lactating_women. Daily Values differ between these groups. Returns each nutrient's bmid, name, daily_value and unit, with the regulation reference. Nutrients that have no Daily Value, such as trans fat and total sugars, are listed with daily_value null. Do not use for a recipe's %DV; get_recipe_nutrition_facts_per_serving returns it. For one nutrient, use get_fda_daily_value.

list_fda_serving_size_categories

ChatGPT
Use this when the user wants to browse all US FDA serving-size categories, for example to choose one for a product. Categories are the FDA Reference Amounts Customarily Consumed (RACC, 21 CFR 101.12), which set the serving size on a US Nutrition Facts label. Returns every category with its category_id, name, reference amount in grams (racc_g), unit_type, label_statements, target_audience and cfr_reference. Filter with audience (general or infant_toddler). Next: add_recipe_serving_size, passing the chosen category_id. Do not use for finding a category by food name; use find_fda_serving_size_category.

list_ingredient_resolutions

ChatGPT
Use this when the user wants the history of how a recipe's pasted ingredient lines were matched to foods and gram weights across several attempts. Needs recipe_id. Returns every resolution for the recipe, newest first, each with its resolution_id, summary and full rows: matched ingredient_id, candidates, quantity_grams and conversion steps. The list is empty for a recipe whose ingredients were set with set_recipe_ingredients. Do not use for reading a recipe's current ingredients; use get_recipe_ingredients. For only the latest resolution, use get_latest_ingredient_resolution.

list_ingredients_used_in_recipes

ChatGPT
Use this when the user wants to see the ingredients their organization actually uses in its recipes, for example "which ingredients do we use most?". Lists standard and custom ingredients together, most-used first by default; it can also sort by recency or name and filter by source or status. Each row has ingredient_id, name, source, status, used_in_recipes and updated_at. The list is kept up to date in the background, so a recipe saved seconds or minutes ago may not be counted yet. To page, pass meta.next_cursor back unchanged and continue until meta.has_more is false. With a source or status filter, a page can hold fewer rows than limit, even none, while more rows remain. Next: get_ingredient_nutrition_facts or get_ingredient_usage for one row. Do not use for finding an ingredient to add to a recipe; use search_ingredients_for_nutrition.

list_recipe_serving_sizes

ChatGPT
Use this when the user wants to see the serving sizes saved on a recipe, or you need a serving_id for a recipe's nutrition facts or label. Returns every active serving with its id, US FDA serving size (household measure, metric amount, servings per container), dual_column_status, and whether per-serving and per-container nutrition facts exist. Also returns the recipe's current version_id, which the next change to the recipe needs. Needs recipe_id from create_recipe_for_nutrition_label, list_saved_recipes or find_saved_recipes. Next: get_recipe_nutrition_facts_per_serving, get_recipe_nutrition_facts_label or export_nutrition_facts_label_file with a serving_id. If the list is empty, add one with add_recipe_serving_size.

list_recipe_versions

ChatGPT
Use this when the user wants the history of a saved recipe, wants to go back to an earlier version, or asks what the recipe looked like at a given time. Needs recipe_id. Returns the versions newest first, each with version_id, version_number, parent_version_id, created_at, created_by and a short summary of the change (for example ingredients.confirm). Pass at (an ISO 8601 time with a UTC offset, such as 2026-05-04T12:00:00Z) to get only the version that was current at that time. Otherwise page with after set to the previous meta.cursor, up to 50 per page. Next: get_recipe_version_changes to see what a version changed, get_recipe with version_id to read it, restore_recipe_version to go back to it. For who changed what and why, use get_recipe_audit_trail.

list_saved_recipes

ChatGPT
Use this when the user wants to see the recipes they saved in BetterMenu, for example "what recipes do I have" or "show my archived recipes", or to pick one when they do not name it. Returns the user's recipes, most recently updated first, each with id, name, status (active or archived) and latest_version_id. Deleted recipes never appear. Filter with status; change the order with sort_by and order. For the next page, pass meta.cursor back as cursor exactly as returned, while meta.has_more is true. Use the returned id as recipe_id in get_recipe and the other recipe tools. To find a recipe by its name, use find_saved_recipes.

patch_recipe_added_sugars_row

ChatGPT
Use this when the user wants to answer the Added Sugars of one ingredient of a saved recipe, for example to give the added sugars from a supplier sheet, state that the ingredient has none, or keep the answer BetterMenu's checks already gave. Records the answer and returns the same answer as get_recipe_added_sugars: the updated report, its report_hash (the value confirming needs), whether it is confirmed, and the recipe's new version_id. Needs the recipe's id, the ingredient's row id (irow_..., from get_recipe_added_sugars) and the recipe's current version_id (from the last write or get_recipe). Set action to accept_suggestion, set_contribution, add_contribution, remove_contribution or keep. accept_suggestion works only on a row that already carries a suggested answer; most rows do not. set_contribution and add_contribution act the same and need exactly one of added_sugars_grams (grams in this ingredient at its current quantity) or added_sugars_per_100g (grams per 100 g of the ingredient, 0 to 100); both or neither is refused, and no other action takes an amount. reason and supplier_reference are optional. For several ingredients use patch_recipe_added_sugars_rows. A per-100 g figure is turned into grams for the current quantity, and both are kept. If the quantity changes later, the amount that counts scales with it. Each row of the report shows the counted amount per 100 g (added_sugars_per_100g), so you never divide. Added sugars can never exceed total sugars: an answer above the row's ingredient.total_sugars_grams is refused with the rows named, and nothing is saved. Each answer saves a new version and ends any earlier confirmation, so confirmation is normally stale or unconfirmed. Added Sugars stays off the recipe's nutrition and labels until the user confirms the new report. Do not use for changing ingredients or quantities; use set_recipe_ingredients.

patch_recipe_added_sugars_rows

ChatGPT
Use this when the user wants to answer the Added Sugars of several ingredients of a saved recipe at once, for example to give supplier figures for a few ingredients or state that several have none. Records all the answers as one new version and returns the same answer as get_recipe_added_sugars: the updated report, its report_hash (the value confirming needs), whether it is confirmed, and the new version_id. Needs the recipe's id, the recipe's current version_id (from the last write or get_recipe) and items: 1 to 100 answers, each naming a different ingredient by its row id (irow_..., from get_recipe_added_sugars). Each item takes the fields of patch_recipe_added_sugars_row: action (accept_suggestion, set_contribution, add_contribution, remove_contribution or keep); for set_contribution and add_contribution exactly one of added_sugars_grams (grams in the ingredient at its current quantity) or added_sugars_per_100g (0 to 100); and an optional reason and supplier_reference. A row named twice, or more than 100 items, is refused. All answers are saved together or none are. If any ingredient cannot take its answer (no such row, accept_suggestion with no suggestion, keep on a row the checks left open) the call is refused with every such row listed in rows: fix them all and send the batch again. If the answers together put added sugars above total sugars, it is refused with the rows named. If both faults are in one batch, rows also lists each ingredient above its own total sugars (ingredient.total_sugars_grams; row_code added_sugars_exceed_total), so one round shows every bad row. Nothing is saved. The new version ends any earlier confirmation, so confirmation is normally stale or unconfirmed. Added Sugars stays off the recipe's nutrition and labels until the user confirms the new report. For one ingredient use patch_recipe_added_sugars_row. Do not use for changing ingredients or quantities; use set_recipe_ingredients.

reset_nutrition_label_settings

ChatGPT
Use this when the user wants a recipe's Nutrition Facts label back to its default nutrients and names, removing all custom label settings. Later labels and exports use the defaults. Fails when the recipe has no custom settings. Returns no body. Needs the recipe's current version_id (from the last write, get_recipe or list_recipe_serving_sizes). Before the next change to the recipe, get the new version_id from get_recipe. Do not use for changing one nutrient; use set_nutrition_label_settings.

restore_custom_ingredient_version

ChatGPT
Use this when the user wants to undo changes to a custom ingredient by going back to an earlier version. Needs target_version_id from list_custom_ingredient_versions. The whole ingredient returns to that version's state: nutrients, serving, name, markets and status, so restoring to a point before an archive makes it active or draft again. It adds a new version and keeps the full history. Returns the ingredient and its new version_id. Recipes that already use the ingredient keep the version they pinned. A deleted ingredient cannot be restored. To see what differs first, use get_custom_ingredient_version_changes.

restore_recipe_version

ChatGPT
Use this when the user wants to roll a saved recipe back to an earlier version. Needs recipe_id, the target_version_id to go back to, and the recipe's current version_id (from get_recipe or the last change). This is a full point-in-time restore. Everything in the recipe (ingredients, servings, nutrition, label configuration and metadata) goes back to exactly what it was at target_version_id. Anything added or changed after that version, including servings added later, is removed. It does not restore only the fields that changed. Before you call it, use list_recipe_versions to find the right version, and confirm that version already has the ingredients, servings and other parts the user wants to keep. get_recipe_version_changes with compared_to set to the current version shows what will change. The restore is saved as a new version; the history stays. Returns the restored recipe and its new version_id. It cannot bring back a deleted recipe.

search_ingredients_for_nutrition

ChatGPT
Searches USDA and custom ingredients by name. Use this when the user gives a recipe or ingredient list (pasted, or taken from a recipe page) and wants US nutrition facts, calories per serving, %DV or an FDA-format label, or wants to save the recipe; or when they want USDA-sourced nutrition for one food or ingredient ("calories in an apple", a packaged or branded product, butter vs margarine). USDA data covers raw ingredients and branded foods. Values are computed from USDA data and the user's custom ingredients, under US FDA rules (market "US"). BetterMenu does not fetch URLs; it takes ingredient lines. Take a recipe page's yield with them, and ask for it when the page gives none. Matches ingredient names for a market (market: "US"). Send every ingredient of a recipe in one call with queries (up to 20, each with a position); results come back as result_groups, one per query. Or pass q for one search, or q: "*" to browse. Each hit has an id, a name and a kind: custom hits (the user's own ingredients) rank above every standard hit. A standard hit's source is ingredient or product (branded). It only reads. Next: get_ingredient_nutrition_facts for one food's nutrients and portion weights, or convert_ingredient_amounts_to_grams to turn each picked standard ingredient's quantity into grams for a recipe. Ask the user when two close matches would give different nutrition.

set_custom_ingredient_nutrition

ChatGPT
Use this when the user wants to enter or correct the nutrition panel values of a custom ingredient. Replaces the whole nutrient list: the list sent becomes the complete nutrients, so include every nutrient to keep, and an empty list clears them all. Keep each existing row's id (from get_custom_ingredient) so the history tracks it. Each amount is per the serving whose weight is reference_quantity_g grams (set it with set_custom_ingredient_serving_size). amount: null means unknown, not zero. A nutrient counts on US FDA labels only with a market_nutrients.US entry (bmid and the USDA nutrient id), and its unit must be that nutrient's standard unit or the call is rejected. Works on draft and active ingredients, not archived ones. Returns the updated ingredient and its new version_id. Recipes that already use the ingredient keep the version they pinned.

set_custom_ingredient_serving_size

ChatGPT
Use this when the user wants to set or fix the serving that a custom ingredient's nutrition panel refers to, for example "1 tbsp (15 g)". Replaces all serving fields at once: reference_amount and reference_unit (the serving as printed), household_measure, reference_quantity_g (the serving's weight in grams) and density_g_per_ml. A field left out is cleared. Nutrient amounts are read as per reference_quantity_g grams; without it the ingredient adds no nutrients to a recipe. Works on draft and active ingredients, not archived ones. Returns the updated ingredient and its new version_id. Recipes that already use the ingredient keep the version they pinned. For nutrient values, use set_custom_ingredient_nutrition.

set_nutrition_label_settings

ChatGPT
Use this when the user wants to show or hide an optional nutrient on a recipe's US FDA Nutrition Facts label, or use a permitted alternative name for one. Send only the nutrients to customize, each with bmid, visible and optionally display_name_override from that nutrient's allowed_synonyms. The list replaces any earlier custom entries. Returns the resolved configuration and the recipe's new version_id; later labels and exports use it. Read get_nutrition_label_settings first for is_toggleable and allowed_synonyms. Needs the recipe's current version_id (from the last write, get_recipe or list_recipe_serving_sizes). Only an active (not archived) recipe can be changed. To go back to the defaults, use reset_nutrition_label_settings.

set_recipe_ingredients

ChatGPT
Use this when the user wants to add, change, remove or reorder the ingredients of a saved recipe, for example to get nutrition facts or a label for their ingredient list. Saves the complete ordered list in one call and recomputes the recipe's nutrition, and that of every existing serving. A row left out is deleted; an empty items list deletes every ingredient. Needs the recipe's id and current version_id (from create_recipe_for_nutrition_label, the last write, get_recipe or get_recipe_ingredients), ingredient ids from search_ingredients_for_nutrition and grams from convert_ingredient_amounts_to_grams. Next: add_recipe_serving_size. Set ingredients_entry_method to form, or to resolution when the list keeps rows from the paste-and-resolve workflow. Every row has position, metric_quantity_g, search_provenance (user_selected if the user picked the match, else system_matched) and unit_conversion_provenance (the lower-cased conversion_source, or user_provided). Then, by source: - form, a standard ingredient: selected_ingredient_id, selected_ingredient_name and display_name, plus quantity and unit as the user gave them and unit_grams (quantity × unit_grams must equal metric_quantity_g within 0.01 g). Add portion_id when the conversion returned a portion. - custom_ingredient, a kind: "custom" hit: custom_ingredient_id (must be active). An existing row keeps its pinned version only if you resend its version_id; without it, the row moves to the ingredient's latest version. - resolution: an existing row from that workflow, with its id, selected_ingredient_id, selected_ingredient_name and display_name. Rejected when ingredients_entry_method is form. To edit, resend every existing row with its id and the fields above. Leave id out on new rows.

unarchive_custom_ingredient

ChatGPT
Use this when the user wants to use an archived custom ingredient again. Moves it from archived back to active, so it appears in search_ingredients_for_nutrition, can be added to recipes and can be edited again. Reverses archive_custom_ingredient. On an ingredient that is not archived it changes nothing and returns its current version_id.

unarchive_recipe

ChatGPT
Use this when the user wants to use or edit an archived recipe again. Needs recipe_id and the recipe's current version_id (from get_recipe). Sets its status back to active, so it can be changed again. Returns the recipe and its new version_id. If the recipe is not archived, nothing changes. Archived recipes are listed by list_saved_recipes with status archived.

update_custom_ingredient_details

ChatGPT
Use this when the user wants to rename a custom ingredient or change the markets it is approved for. Send only the fields to change: name, or approved_markets (the full list, which replaces the old one). A custom ingredient appears in search_ingredients_for_nutrition only for its approved markets; an empty list hides it from search without archiving it. Works on draft and active ingredients, not archived or deleted ones. Returns the updated ingredient and its new version_id. Do not use for nutrient values (set_custom_ingredient_nutrition) or the serving (set_custom_ingredient_serving_size).

update_recipe_details

ChatGPT
Use this when the user wants to rename a saved recipe or change its demographic (the group whose US FDA Daily Values set the %DV). Needs recipe_id and the recipe's current version_id (from get_recipe or the last change). Send only the fields to change; the rest stay as they are. You can add a rationale, which is kept in the recipe's history. The name must be unique in the user's organization. Changing demographic recalculates the %DV on the recipe's servings. Only an active recipe can be changed; use unarchive_recipe first for an archived one. Returns the updated recipe and its new version_id. Do not use for changing ingredients; use set_recipe_ingredients.

update_recipe_serving_size

ChatGPT
Use this when the user wants to change the serving size of a serving already saved on a recipe. Replaces the serving's size input in full, either user_provided (household measure plus grams or mL) or racc_guided (derived from a US FDA RACC category). Per-serving and per-container nutrition facts are recomputed in the same change, so no follow-up call is needed. Returns the updated serving and the recipe's new version_id. Needs the serving_id from list_recipe_serving_sizes and the recipe's current version_id (from the last write, get_recipe or list_recipe_serving_sizes). For racc_guided, find the category with find_fda_serving_size_category first. Do not use for adding a new serving; use add_recipe_serving_size.

Capabilities

InteractiveWrites

App Stats

62

Tools

ChatGPT

Platforms

Works with

ChatGPT

Data refreshed daily