Befana Recipes

Ad-free recipes with amounts in every step: search, scale, plan meals, build shopping lists.

Should I use this

Quality & Safety

A
Description quality
97%
Schema completeness
82%
Naming quality
93%
Poisoning risk
80%
Permission match
100%
Protocol compliance
100%

Findings (3)

  • HIGHTool poisoning patterns detected
  • MEDIUMTool 'get_photo_queue' description contains placeholder textin get_photo_queue
  • INFOTool description contains placeholder or incomplete textin get_photo_queue

Based on automated analysis of tool definitions and protocol compliance.

Context Cost

~11,499Tokens (tool definitions)
~3.3 KBTypical response size
Significant attention impact (8.98% of 128k context)

This is the approximate number of tokens consumed each time the server's tools are loaded into a model's context. Higher counts reduce the attention available for other tasks.

Install

One-Click Install

Add this to your `claude_desktop_config.json` file:

{
  "mcpServers": {
    "befana": {
      "url": "https://befana.app/mcp"
    }
  }
}

Remote endpoints

https://befana.app/mcpstreamable-http

What it can do

Tool inventory

Tools (24)

🟢 Read-only🟡 Write🔴 Delete⚪ Unknown
🟢search_recipes(query, mine, max_minutes, tags, include_ingredients, ...)

Find Befana recipes by keywords, time, diet tags, and ingredients on hand or to avoid. Signed in, the cook's saved allergies, diet and avoid list already apply; signed out it works too, over public recipes only (mine needs sign-in). Returns short summaries with slugs; call get_recipe for the full recipe. Tags in use include vegetarian, vegan, gluten-free, dairy-free, quick, dinner, breakfast, dessert, baking, soup, side, snack, make-ahead. Signed in, the cook's own recipes and versions come first; mine: true returns only those ("show me my chili"), private ones included. When the cook names a recipe their allergies, diet or avoid list hide, it comes back in hidden (slug, url, title, why) instead of recipes. They asked for it, so don't stop to ask: go on with what they asked (get_recipe, get_cook_steps, get_recipe with substitute, build_shopping_list) with that slug; the result leads with the warning, and you tell the cook why it was hidden before anything else. Never present a hidden recipe as safe.

Input Schema

{
  "type": "object",
  "properties": {
    "query": {
      "description": "Keywords, e.g. \"lemon pasta\" or \"soup\"",
      "type": "string",
      "maxLength": 200
    },
    "mine": {
      "default": false,
      "description": "Only the cook's own recipes and versions, including private ones",
      "type": "boolean"
    },
    "max_minutes": {
      "description": "Maximum prep + cook time",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "tags": {
      "description": "All must match, e.g. [\"vegetarian\", \"quick\"]",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "include_ingredients": {
      "description": "Ingredients the recipe must use, e.g. what is in the fridge",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "exclude_ingredients": {
      "description": "Extra ingredients to avoid for this search (saved allergies and dislikes already apply)",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "from_pantry": {
      "default": false,
      "description": "Rank by what the cook has in their saved pantry (\"something with pasta from what I have\"); each result says what they have and what's missing. For a pure \"what can I make?\" use suggest_from_pantry",
      "type": "boolean"
    },
    "limit": {
      "default": 8,
      "type": "integer",
      "minimum": 1,
      "maximum": 25
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_recipe(slug, servings, units, units_for, substitute)

Full recipe scaled to any number of servings, in US or metric units. Every step already contains the amounts it uses, so you can read steps aloud without referring back to the ingredient list. Works signed out (public recipes, substitute and units_for included, no preferences). A step's tip is a short pointer to pass on with the step. Mention the chef's note (chef_note) only if the cook asks about the recipe's background. your_versions lists the cook's own versions of this recipe, so you can say "you have your own version of this" and offer it. On a recipe the cook owns, revision counts their edits and revisions lists the last ten (undo one with update_recipe({ restore_revision })). When the cook asks for an amount in another unit ("how many tablespoons of butter is that?"), pass units_for rather than converting yourself: the list and every step follow. When the cook wants a change, pass substitute to get sound swaps for one ingredient or for a whole diet ("dairy-free"), already filtered by the cook's allergies and diet; then show the cook the changed ingredients and steps and, once they say yes, save with fork_recipe (or update_recipe on their own recipe).

Input Schema

{
  "type": "object",
  "properties": {
    "slug": {
      "type": "string",
      "description": "Recipe slug from search_recipes"
    },
    "servings": {
      "description": "Scale to this many servings (defaults to the cook's household size, then the recipe's own)",
      "type": "number",
      "minimum": 0.25,
      "maximum": 1000
    },
    "units": {
      "description": "US cups/oz/°F or metric grams/ml/°C. Defaults to the cook's setting.",
      "type": "string",
      "enum": [
        "us",
        "metric"
      ]
    },
    "units_for": {
      "description": "The cook's own unit for particular ingredients, by ingredient key or name: { \"butter\": \"tbsp\", \"flour\": \"g\" }. Units: tsp, tbsp, cup, fl oz, ml, oz, lb, g. When the cook asks for an amount in another unit, pass this rather than converting yourself; the ingredient list and every step follow. Ones that can't convert come back in ignored_units",
      "type": "object",
      "propertyNames": {
        "type": "string",
        "maxLength": 60
      },
      "additionalProperties": {
        "type": "string",
        "maxLength": 20
      }
    },
    "substitute": {
      "description": "Ask for substitutions: for one ingredient, for a diet, or both",
      "type": "object",
      "properties": {
        "ingredient": {
          "description": "The ingredient to replace, e.g. \"butter\"",
          "type": "string",
          "maxLength": 80
        },
        "for": {
          "description": "What the swap is for: a diet (vegetarian, vegan, pescatarian, gluten-free, dairy-free, low-sodium, halal, kosher), an allergen-free tag (egg-free, nut-free, peanut-free, sesame-free, shellfish-free, soy-free) or a context (baking, sauce, frying, dressing). Alone, it covers every ingredient that breaks that diet.",
          "type": "string",
          "maxLength": 40
        }
      }
    }
  },
  "required": [
    "slug"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_cook_steps(slug, servings, units, units_for)

One recipe as a hands-free sequence for voice or chat guidance: a gather list first, then each step with its amounts, the ingredients it uses, its tip (if the chef left one) and any timer. Give the cook one step at a time, and offer to set a timer when a step has one. The recipe url shows the same steps as a checklist on the cook's phone. Works signed out (public recipes).

Input Schema

{
  "type": "object",
  "properties": {
    "slug": {
      "type": "string"
    },
    "servings": {
      "type": "number",
      "minimum": 0.25,
      "maximum": 1000
    },
    "units": {
      "description": "US cups/oz/°F or metric grams/ml/°C. Defaults to the cook's setting.",
      "type": "string",
      "enum": [
        "us",
        "metric"
      ]
    },
    "units_for": {
      "description": "The cook's own unit for particular ingredients, by ingredient key or name: { \"butter\": \"tbsp\", \"flour\": \"g\" }. Units: tsp, tbsp, cup, fl oz, ml, oz, lb, g. When the cook asks for an amount in another unit, pass this rather than converting yourself; the ingredient list and every step follow. Ones that can't convert come back in ignored_units",
      "type": "object",
      "propertyNames": {
        "type": "string",
        "maxLength": 60
      },
      "additionalProperties": {
        "type": "string",
        "maxLength": 20
      }
    }
  },
  "required": [
    "slug"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡build_shopping_list(recipes, pantry, include_staples, extra_items, units, ...)

Merge any set of recipes (each at its own servings) into one shopping list. The same ingredient is combined across recipes and converted to what a store sells ("10 cloves garlic → buy 1 head"), grouped by aisle. extra_items keep the amount the cook gave ("2 lb bananas" stays 2 lb). One that matches a recipe ingredient is added to that line when the units agree, or shown beside it when they don't ("Lemons: 1 + 2 lb"). Staples like salt and oil, anything listed in pantry, and the cook's saved pantry staples go to a separate check-the-pantry group. Items that hit the cook's allergies are flagged. Signed in, the list is saved to the cook's kitchen and returns a shareable list url and id for order_groceries. Works signed out too: the list comes back without being saved (no url or id), with a next step to keep it (keep: true asks the cook to sign in).

Input Schema

{
  "type": "object",
  "properties": {
    "recipes": {
      "minItems": 1,
      "maxItems": 21,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "servings": {
            "type": "number",
            "minimum": 0.25,
            "maximum": 1000
          }
        },
        "required": [
          "slug"
        ]
      }
    },
    "pantry": {
      "description": "Ingredients the cook already has, e.g. [\"flour\", \"eggs\"]",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "include_staples": {
      "default": false,
      "description": "Put salt, oil, sugar, etc. on the list instead of the pantry check",
      "type": "boolean"
    },
    "extra_items": {
      "description": "Anything else for the same trip, as the cook said it, amount included: [\"paper towels\", \"2 lb bananas\"]. A matching recipe ingredient gets that quantity added when the units agree, or both amounts when they don't.",
      "maxItems": 50,
      "type": "array",
      "items": {
        "type": "string",
        "minLength": 1,
        "maxLength": 80
      }
    },
    "units": {
      "description": "US cups/oz/°F or metric grams/ml/°C. Defaults to the cook's setting.",
      "type": "string",
      "enum": [
        "us",
        "metric"
      ]
    },
    "keep": {
      "description": "Save the list to the cook's kitchen. Signed in it is always saved; signed out, keep: true asks the cook to sign in first",
      "type": "boolean"
    }
  },
  "required": [
    "recipes"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢plan_meals(meals, servings, tags, meal_type, occasion, ...)

Pick several recipes for the coming days that fit the filters and overlap in ingredients, so less food goes to waste. The cook's allergies, diet, avoid list, weeknight time limit and household size already apply. Saves the plan to the cook's kitchen and optionally returns the merged shopping list too. Works signed out too: the plan and list come back without being saved (share the recipe urls), with a next step to keep them (keep: true asks the cook to sign in).

Input Schema

{
  "type": "object",
  "properties": {
    "meals": {
      "description": "How many meals to plan; leave out to use the cook's usual number (workflow.plan_meals in preferences), else 5",
      "type": "integer",
      "minimum": 1,
      "maximum": 14
    },
    "servings": {
      "description": "Servings per meal (defaults to each recipe's own)",
      "type": "number",
      "minimum": 0.25,
      "maximum": 1000
    },
    "tags": {
      "description": "Required tags, e.g. [\"vegetarian\"]",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "meal_type": {
      "default": "dinner",
      "type": "string",
      "enum": [
        "dinner",
        "breakfast",
        "any"
      ]
    },
    "occasion": {
      "default": "weeknight",
      "description": "weeknight: quick, everyday. guests or party: the plan comes with share links and an offer to adapt a recipe for a guest's needs before the list",
      "type": "string",
      "enum": [
        "weeknight",
        "guests",
        "party"
      ]
    },
    "guest_notes": {
      "description": "Who's coming and what they need, in the cook's words: \"one vegetarian, Sam hates cilantro\". Used to offer a version of a recipe; never stored as a preference",
      "type": "string",
      "maxLength": 200
    },
    "max_minutes": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "exclude_ingredients": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "with_shopping_list": {
      "default": true,
      "type": "boolean"
    },
    "pantry": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "units": {
      "description": "US cups/oz/°F or metric grams/ml/°C. Defaults to the cook's setting.",
      "type": "string",
      "enum": [
        "us",
        "metric"
      ]
    },
    "keep": {
      "description": "Save the plan (and its list) to the cook's kitchen. Signed in it is always saved; signed out, keep: true asks the cook to sign in first",
      "type": "boolean"
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢order_groceries(list_id, recipes, pantry, units, provider)

Hand a shopping list to grocery delivery so the cook can order from a store near them. Pass the list_id returned by build_shopping_list or plan_meals, or pass recipes directly. Items marked as in the pantry are left off. Returns one link that opens the whole list when checkout is connected, otherwise a search link per item. When the cook's saved store is a Kroger banner (Kroger, King Soopers, and the other Kroger stores) and Kroger checkout is on, the list is added to their Kroger cart and the link opens that cart; if they haven't connected Kroger, ask them to open the connect link in the response (it is the one question that turn). Always share share_url with the cook: it's the one link that opens their order (a Befana link that sends them to the grocer's list, or Befana's order page with every item's store search). Optional provider picks the grocer (instacart, walmart, kroger, amazon or search); omit it and Befana uses the cook's saved store when that grocer is available, otherwise Instacart. Grocers are never ranked by commission. Befana does not choose brands or promote products; the cook picks the store and products and places the order themselves. When the reply includes commission_disclosure, say that sentence to the cook next to the link.

Input Schema

{
  "type": "object",
  "properties": {
    "list_id": {
      "description": "Id of a saved list from build_shopping_list or plan_meals",
      "type": "string"
    },
    "recipes": {
      "maxItems": 21,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "slug": {
            "type": "string"
          },
          "servings": {
            "type": "number",
            "minimum": 0.25,
            "maximum": 1000
          }
        },
        "required": [
          "slug"
        ]
      }
    },
    "pantry": {
      "description": "Ingredients the cook already has; they are not ordered",
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "units": {
      "description": "US cups/oz/°F or metric grams/ml/°C. Defaults to the cook's setting.",
      "type": "string",
      "enum": [
        "us",
        "metric"
      ]
    },
    "provider": {
      "description": "Grocer to hand the list to: instacart, walmart, kroger, amazon or search. Omit for the cook's saved store, or Instacart when that store isn't available. An unknown or unavailable grocer returns an error listing the available ones.",
      "type": "string",
      "maxLength": 40
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡draft_recipe(text, url)

Turn a recipe the cook pasted, typed or linked to into a Befana draft: ingredients matched to Befana's list, steps rewritten in plain words with amounts as tags, and servings, times, timers and tags filled in. Pass text (up to 20,000 characters) or url (a public recipe page; a Pinterest Pin or pin.it link works too: Befana follows the Pin to the recipe it saved), not both. Nothing is published. Show the cook the draft (title, servings, ingredients and steps), point out anything listed in guessed, and ask them to confirm or change it. Then publish with create_recipe({ draft_id }) plus only the fields they changed, or give them edit_url to review and publish on the website. For a photo of a recipe card, read it yourself and pass the text. Limited to 20 drafts a day per cook.

Input Schema

{
  "type": "object",
  "properties": {
    "text": {
      "description": "The recipe as the cook gave it, in any format",
      "type": "string",
      "maxLength": 20000
    },
    "url": {
      "description": "A public recipe page (http or https), or a Pinterest Pin link",
      "type": "string",
      "maxLength": 2000
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡create_recipe(draft_id, title, summary, servings, yield_label, ...)

Publish a recipe to Befana. When the cook pastes, types or links a recipe, call draft_recipe first, show them the draft and publish it here with create_recipe({ draft_id }) once they confirm: never publish their text straight from fields, even a short one (for a recipe card photo, read it and pass the text to draft_recipe). Pass fields without a draft_id only for a recipe you worked out with the cook in this conversation, after showing it to them. Write each step with ingredient tags instead of typed amounts: "Whisk {flour} with {salt}". Tags default to the last word of the ingredient name ("all-purpose flour" → {flour}); set key to choose. Use {butter:1/2} when an ingredient is split across steps and {t:375} for oven temperatures in °F. title, servings, ingredients and steps are required, unless you pass draft_id: then the draft from draft_recipe is published, with any fields you pass replacing the draft's. Publish a draft only after the cook has seen and confirmed it. Returns the url plus any warnings (e.g. an ingredient never used in a step). Recipes are public and appear under My recipes in the cook's kitchen. tested marks it cooked and timed, only when the cook tells you they made it and how long it took; ask, never assume.

Input Schema

{
  "type": "object",
  "properties": {
    "draft_id": {
      "description": "A draft_id from draft_recipe, to publish that draft",
      "type": "string",
      "maxLength": 64
    },
    "title": {
      "type": "string",
      "minLength": 1,
      "maxLength": 120
    },
    "summary": {
      "description": "One or two sentences on what makes it good",
      "type": "string",
      "maxLength": 400
    },
    "servings": {
      "type": "number",
      "minimum": 0.25,
      "maximum": 1000
    },
    "yield_label": {
      "description": "servings, cookies, loaves, jars…",
      "type": "string",
      "maxLength": 40
    },
    "prep_minutes": {
      "type": "integer",
      "minimum": 0,
      "maximum": 2880
    },
    "cook_minutes": {
      "type": "integer",
      "minimum": 0,
      "maximum": 2880
    },
    "tags": {
      "maxItems": 20,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 30
      }
    },
    "author": {
      "description": "Name to credit (the cook)",
      "type": "string",
      "maxLength": 80
    },
    "chef_note": {
      "description": "The chef's note, up to 500 characters: a sentence or two in the cook's words on what makes the recipe theirs. Only what the cook said; never write one for them.",
      "type": "string",
      "maxLength": 500
    },
    "ingredients": {
      "minItems": 1,
      "maxItems": 80,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "qty": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0,
                "maximum": 100000
              },
              {
                "type": "string",
                "maxLength": 20
              }
            ],
            "description": "Amount, e.g. 1.5 or \"1 1/2\". Use 0 for 'to taste'."
          },
          "unit": {
            "default": "",
            "description": "tsp, tbsp, cup, fl oz, qt, oz, lb, g, kg, ml, l, clove, can, slice, sprig, bunch, head, stick, each, or empty",
            "type": "string",
            "maxLength": 20
          },
          "item": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "description": "Ingredient name, e.g. \"all-purpose flour\""
          },
          "note": {
            "description": "Prep note, e.g. \"finely chopped\"",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "key": {
            "description": "Short tag steps use, e.g. \"flour\". When omitted: an ingredient already in the recipe keeps its key (match by item), a new one takes the tag your steps use for it if that tag is its name (\"nutritional_yeast\") or last word (\"yeast\"), else the last word of item.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 24,
                "pattern": "^[a-z0-9_-]+$"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "qty",
          "item"
        ]
      }
    },
    "steps": {
      "minItems": 1,
      "maxItems": 60,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "body": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1000,
            "description": "Step text with amounts as tags: {flour}, a portion {butter:1/2}, oven temp in °F {t:375}"
          },
          "tip": {
            "description": "A short pointer shown under the step, up to 140 characters: \"The batter should look lumpy; don't overmix.\"",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 140
              },
              {
                "type": "null"
              }
            ]
          },
          "timer_minutes": {
            "description": "Up to 24 hours (1440)",
            "anyOf": [
              {
                "type": "number",
                "exclusiveMinimum": 0,
                "maximum": 1440
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "body"
        ]
      }
    },
    "tested": {
      "description": "Mark the recipe tested: the cook says they cooked it themselves and timed it. Ask the cook (\"Have you cooked this? About how long did it take, start to finish?\") and pass only what they say; never assume it, never estimate the minutes, and never mark a recipe tested because you drafted, imported or adapted it. null clears the mark. Shown as \"Tested by the cook · 45 min\" and counted as one timed cook.",
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "minutes": {
              "type": "integer",
              "minimum": 1,
              "maximum": 2880,
              "description": "How long it took, start to finish, in minutes"
            }
          },
          "required": [
            "minutes"
          ]
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡fork_recipe(slug, visibility, title, summary, servings, ...)

Save the cook's own version of a recipe they don't own ("make it dairy-free", "halve the sugar", "scale it for 8 and keep that"). Pass only what changes; anything omitted is copied from the original. When you pass ingredients or steps, pass the complete new list (fetch the original with get_recipe first and edit it). Ingredients you keep can be resent without key; they keep the original's tags. For a new ingredient, tag it in the steps by its name in snake_case ({nutritional_yeast}) or set key. Steps carry the amounts, so when you preview a change, show the steps whose amounts change along with the ingredients. Before calling, show the cook the changed ingredients and steps and get a yes; never save silently. Without a title, the version is named after the change ("Dairy-free Chili", "Chili with Olive Oil"). A version made only to change servings keeps those as its default. The version links back to the original, which never changes. Versions are public by default and appear under My versions in the cook's kitchen; visibility "private" keeps it just for the cook (out of search, the sitemap and the original's list of variations). To change it again later, use update_recipe. On a recipe the cook already owns, use update_recipe instead; fork_recipe refuses.

Input Schema

{
  "type": "object",
  "properties": {
    "slug": {
      "type": "string",
      "description": "The original recipe's slug"
    },
    "visibility": {
      "description": "private = just for the cook; public (the default) lists it under the original",
      "type": "string",
      "enum": [
        "public",
        "private"
      ]
    },
    "title": {
      "type": "string",
      "minLength": 1,
      "maxLength": 120
    },
    "summary": {
      "description": "One or two sentences on what makes it good",
      "type": "string",
      "maxLength": 400
    },
    "servings": {
      "type": "number",
      "minimum": 0.25,
      "maximum": 1000
    },
    "yield_label": {
      "description": "servings, cookies, loaves, jars…",
      "type": "string",
      "maxLength": 40
    },
    "prep_minutes": {
      "type": "integer",
      "minimum": 0,
      "maximum": 2880
    },
    "cook_minutes": {
      "type": "integer",
      "minimum": 0,
      "maximum": 2880
    },
    "tags": {
      "maxItems": 20,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 30
      }
    },
    "author": {
      "description": "Name to credit (the cook)",
      "type": "string",
      "maxLength": 80
    },
    "chef_note": {
      "description": "The chef's note, up to 500 characters: a sentence or two in the cook's words on what makes the recipe theirs. Only what the cook said; never write one for them.",
      "type": "string",
      "maxLength": 500
    },
    "ingredients": {
      "minItems": 1,
      "maxItems": 80,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "qty": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0,
                "maximum": 100000
              },
              {
                "type": "string",
                "maxLength": 20
              }
            ],
            "description": "Amount, e.g. 1.5 or \"1 1/2\". Use 0 for 'to taste'."
          },
          "unit": {
            "default": "",
            "description": "tsp, tbsp, cup, fl oz, qt, oz, lb, g, kg, ml, l, clove, can, slice, sprig, bunch, head, stick, each, or empty",
            "type": "string",
            "maxLength": 20
          },
          "item": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "description": "Ingredient name, e.g. \"all-purpose flour\""
          },
          "note": {
            "description": "Prep note, e.g. \"finely chopped\"",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "key": {
            "description": "Short tag steps use, e.g. \"flour\". When omitted: an ingredient already in the recipe keeps its key (match by item), a new one takes the tag your steps use for it if that tag is its name (\"nutritional_yeast\") or last word (\"yeast\"), else the last word of item.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 24,
                "pattern": "^[a-z0-9_-]+$"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "qty",
          "item"
        ]
      }
    },
    "steps": {
      "minItems": 1,
      "maxItems": 60,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "body": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1000,
            "description": "Step text with amounts as tags: {flour}, a portion {butter:1/2}, oven temp in °F {t:375}"
          },
          "tip": {
            "description": "A short pointer shown under the step, up to 140 characters: \"The batter should look lumpy; don't overmix.\"",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 140
              },
              {
                "type": "null"
              }
            ]
          },
          "timer_minutes": {
            "description": "Up to 24 hours (1440)",
            "anyOf": [
              {
                "type": "number",
                "exclusiveMinimum": 0,
                "maximum": 1440
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "body"
        ]
      }
    }
  },
  "required": [
    "slug"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡update_recipe(slug, restore_revision, visibility, title, summary, ...)

Edit a recipe the cook owns (one they published, or their own version from fork_recipe) in place: "add more garlic to my version". Pass only what changes; everything else stays. When you pass ingredients or steps, pass the complete new list (fetch the current one with get_recipe first and edit it); ingredients resent without key keep their tags, so changing one amount is just the list with that amount changed. For a new ingredient, tag it in the steps by its name in snake_case ({nutritional_yeast}) or set key. Steps carry the amounts, so when you preview a change, show the steps whose amounts change along with the ingredient. Before calling, show the cook the changed ingredients and steps and get a yes; never save silently. Every edit keeps the previous version: get_recipe returns revision (how many edits) and revisions; restore_revision: n puts the recipe back to how it was before edit n (the current revision number undoes the last edit), and is itself kept as an edit. visibility switches between public and "private" (just for the cook). The slug and the link to the original never change. Fails for a recipe the cook doesn't own: use fork_recipe for those. tested ({ minutes }) marks it cooked and timed when the cook says they made it ("I made it tonight, took about 50 minutes"); ask for the time if they didn't say it, never assume. The mark isn't part of a revision.

Input Schema

{
  "type": "object",
  "properties": {
    "slug": {
      "type": "string",
      "description": "The cook's recipe or version to change"
    },
    "restore_revision": {
      "description": "Undo: put the recipe back to how it was before edit n (see get_recipe's revisions). Other fields you pass apply on top.",
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "visibility": {
      "type": "string",
      "enum": [
        "public",
        "private"
      ]
    },
    "title": {
      "type": "string",
      "minLength": 1,
      "maxLength": 120
    },
    "summary": {
      "description": "One or two sentences on what makes it good",
      "type": "string",
      "maxLength": 400
    },
    "servings": {
      "type": "number",
      "minimum": 0.25,
      "maximum": 1000
    },
    "yield_label": {
      "description": "servings, cookies, loaves, jars…",
      "type": "string",
      "maxLength": 40
    },
    "prep_minutes": {
      "type": "integer",
      "minimum": 0,
      "maximum": 2880
    },
    "cook_minutes": {
      "type": "integer",
      "minimum": 0,
      "maximum": 2880
    },
    "tags": {
      "maxItems": 20,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 30
      }
    },
    "author": {
      "description": "Name to credit (the cook)",
      "type": "string",
      "maxLength": 80
    },
    "chef_note": {
      "description": "The chef's note, up to 500 characters: a sentence or two in the cook's words on what makes the recipe theirs. Only what the cook said; never write one for them.",
      "type": "string",
      "maxLength": 500
    },
    "ingredients": {
      "minItems": 1,
      "maxItems": 80,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "qty": {
            "anyOf": [
              {
                "type": "number",
                "minimum": 0,
                "maximum": 100000
              },
              {
                "type": "string",
                "maxLength": 20
              }
            ],
            "description": "Amount, e.g. 1.5 or \"1 1/2\". Use 0 for 'to taste'."
          },
          "unit": {
            "default": "",
            "description": "tsp, tbsp, cup, fl oz, qt, oz, lb, g, kg, ml, l, clove, can, slice, sprig, bunch, head, stick, each, or empty",
            "type": "string",
            "maxLength": 20
          },
          "item": {
            "type": "string",
            "minLength": 1,
            "maxLength": 120,
            "description": "Ingredient name, e.g. \"all-purpose flour\""
          },
          "note": {
            "description": "Prep note, e.g. \"finely chopped\"",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 200
              },
              {
                "type": "null"
              }
            ]
          },
          "key": {
            "description": "Short tag steps use, e.g. \"flour\". When omitted: an ingredient already in the recipe keeps its key (match by item), a new one takes the tag your steps use for it if that tag is its name (\"nutritional_yeast\") or last word (\"yeast\"), else the last word of item.",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 24,
                "pattern": "^[a-z0-9_-]+$"
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "qty",
          "item"
        ]
      }
    },
    "steps": {
      "minItems": 1,
      "maxItems": 60,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "body": {
            "type": "string",
            "minLength": 1,
            "maxLength": 1000,
            "description": "Step text with amounts as tags: {flour}, a portion {butter:1/2}, oven temp in °F {t:375}"
          },
          "tip": {
            "description": "A short pointer shown under the step, up to 140 characters: \"The batter should look lumpy; don't overmix.\"",
            "anyOf": [
              {
                "type": "string",
                "maxLength": 140
              },
              {
                "type": "null"
              }
            ]
          },
          "timer_minutes": {
            "description": "Up to 24 hours (1440)",
            "anyOf": [
              {
                "type": "number",
                "exclusiveMinimum": 0,
                "maximum": 1440
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "body"
        ]
      }
    },
    "tested": {
      "description": "Mark the recipe tested: the cook says they cooked it themselves and timed it. Ask the cook (\"Have you cooked this? About how long did it take, start to finish?\") and pass only what they say; never assume it, never estimate the minutes, and never mark a recipe tested because you drafted, imported or adapted it. null clears the mark. Shown as \"Tested by the cook · 45 min\" and counted as one timed cook.",
      "anyOf": [
        {
          "type": "object",
          "properties": {
            "minutes": {
              "type": "integer",
              "minimum": 1,
              "maximum": 2880,
              "description": "How long it took, start to finish, in minutes"
            }
          },
          "required": [
            "minutes"
          ]
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "slug"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡rate_recipe(slug, stars, comment, made_it, name)

Record the cook's star rating (1 to 5) and optional comment. One rating per cook per recipe: calling again updates it ("Updated your rating 3★ → 5★") and recalculates the average; it does not add another review. A comment you leave out is kept. Refuses the cook's own recipe, since a rating has to come from someone else. Only post what the cook actually said; ask them for the rating if they have not given one.

Input Schema

{
  "type": "object",
  "properties": {
    "slug": {
      "type": "string"
    },
    "stars": {
      "type": "integer",
      "minimum": 1,
      "maximum": 5
    },
    "comment": {
      "type": "string",
      "maxLength": 2000
    },
    "made_it": {
      "default": true,
      "type": "boolean"
    },
    "name": {
      "description": "Display name the cook wants shown (defaults to their account name)",
      "type": "string",
      "maxLength": 60
    }
  },
  "required": [
    "slug",
    "stars"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡save_recipe(slug)

Save (favorite) a recipe for the cook. It shows under Saved in My Kitchen on the website, with a heart on the recipe. Saving twice is harmless.

Input Schema

{
  "type": "object",
  "properties": {
    "slug": {
      "type": "string",
      "description": "Recipe slug from search_recipes"
    }
  },
  "required": [
    "slug"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🔴unsave_recipe(slug)

Remove a recipe from the cook's Saved recipes. Only use when the cook asks.

Input Schema

{
  "type": "object",
  "properties": {
    "slug": {
      "type": "string"
    }
  },
  "required": [
    "slug"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_my_kitchen(section, limit)

What the cook has on Befana: saved recipes, recipes they published, their variations, shopping lists and meal plans (from the web or any assistant), their ratings, and a count of their pantry. Use it to answer "what did I save?" or to reopen a list. Same as My Kitchen on the website. When newly_assigned is present, tell the cook first, once: those recipes were added to their kitchen by Befana (they're the owner and can edit them). When fixes_asked is present, tell the cook (once, it isn't repeated): Befana's reviewers asked for these specific fixes on their recipes before launch; offer to make them with update_recipe after showing the changes. Keeping them is the default; if the cook says one isn't theirs, hand_back_recipe returns it.

Input Schema

{
  "type": "object",
  "properties": {
    "section": {
      "default": "all",
      "type": "string",
      "enum": [
        "all",
        "saved",
        "recipes",
        "versions",
        "lists",
        "activity",
        "pantry"
      ]
    },
    "limit": {
      "default": 10,
      "description": "Items per section",
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🔴hand_back_recipe(slug)

When the Befana team added a recipe to the cook's kitchen (get_my_kitchen newly_assigned) and the cook says it isn't theirs, this hands it back to the team member who added it. Keeping it is the default and needs nothing. Confirm with the cook before calling; it works once per recipe.

Input Schema

{
  "type": "object",
  "properties": {
    "slug": {
      "type": "string",
      "maxLength": 200
    }
  },
  "required": [
    "slug"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_pantry

The cook's pantry on Befana: what they said they have (fresh items, with how long ago they said it) and their staples (always on hand, left off shopping lists). Same as the Pantry page on the website. Use suggest_from_pantry to turn it into recipes.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟡update_pantry(text, photo, add, remove, replace, ...)

Add to or take from the cook's pantry. Pass what they said in `text`, as they said it, however messy: a comma list, a dictated ramble ("um I've got like 2 lbs of chicken thighs and half an onion"), things they're out of ("we're out of eggs") and corrections ("no wait, not the chicken"); Befana reads it and returns exactly what changed, plus `unsure` for anything that didn't read as an ingredient. Or pass `add` and `remove` as plain ingredient names. `replace: true` swaps everything fresh for the new list (staples stay). `staples` sets the always-on-hand list outright. For a photo of the fridge, freezer or a shelf, have the cook upload it (POST /api/upload with purpose "parse", or the pantry page's camera button) and pass the upload name as `photo`: Befana lists the food it can see, deletes the photo, and adds what it read (`unsure` holds what it couldn't make out). If you can see the photo yourself, read it and pass the names in `add` instead. The pantry isn't health data: the cook saying what they have is the yes, so save it and read the change back to them (one line). Never add anything the cook didn't say, and never suggest a brand. Every item is left off their shopping lists and counts toward suggest_from_pantry.

Input Schema

{
  "type": "object",
  "properties": {
    "text": {
      "description": "What the cook said, verbatim",
      "type": "string",
      "maxLength": 2000
    },
    "photo": {
      "description": "An upload name (or its /media/ URL) from POST /api/upload with purpose \"parse\": a photo of the fridge or shelf to read",
      "type": "string",
      "maxLength": 200
    },
    "add": {
      "description": "Ingredient names to add",
      "maxItems": 300,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "remove": {
      "description": "Ingredient names to take out",
      "maxItems": 300,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "replace": {
      "default": false,
      "description": "Take out every fresh item not in this update (staples stay)",
      "type": "boolean"
    },
    "staples": {
      "description": "Set the always-on-hand list to exactly these",
      "maxItems": 100,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢suggest_from_pantry(pantry, must_use, query, tags, max_minutes, ...)

Recipes ranked by how much of each the cook already has, with what's missing named on every one ("You have 7 of 9. Missing: lemon, parmesan."). Staples (salt, oil, sugar) are assumed. Uses the cook's saved pantry (update_pantry); signed out, or for "what if I had…", pass `pantry` as a list of ingredient names. `must_use` pins things that have to go in ("the chicken has to get used tonight"): recipes using them come first. Keywords, tags and max_minutes narrow it like search_recipes. Preferences (allergies, diet, avoid list) already apply. Read the cook the top few with the have/missing line and the url; a shopping list of just the missing items is the natural next step.

Input Schema

{
  "type": "object",
  "properties": {
    "pantry": {
      "description": "Ingredient names to use instead of the saved pantry (signed out, or a what-if)",
      "maxItems": 300,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "must_use": {
      "description": "Ingredients the recipe has to use",
      "maxItems": 10,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "query": {
      "description": "Keywords, e.g. \"soup\"",
      "type": "string",
      "maxLength": 200
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "max_minutes": {
      "type": "integer",
      "exclusiveMinimum": 0,
      "maximum": 9007199254740991
    },
    "limit": {
      "default": 6,
      "type": "integer",
      "minimum": 1,
      "maximum": 25
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_preferences

The cook's saved Befana preferences: allergies, diet, ingredients to avoid, household size, units, weeknight time, skill, equipment, cuisines, pantry staples, store, privacy choices (do not sell, region), and workflow: how they want you to work (which offers to make: always, ask or never; setup questions; what's new; their usual number of planned meals). They already apply to every Befana tool.

Input Schema

{
  "type": "object",
  "properties": {},
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🔴update_preferences(cook_confirmed, allergies, custom_allergies, diets, avoid, ...)

Change the cook's saved Befana preferences. When the cook asks in their own words for a specific change to units, household size (servings), weeknight time, skill, equipment, cuisines, pantry, store or how you work with them (workflow: "switch me to metric", "set us to 4 people", "stop offering shopping lists", "always make the list"), that request is their yes: save it with cook_confirmed and tell them what changed (and that they can change it in Settings). For allergies, diets, the avoid list and privacy settings, and for any change you are proposing or the cook only mentioned in passing ("we're usually 4"), first tell the cook exactly what you will change and get a clear yes; set cook_confirmed only then. Never infer allergies or diets from conversation ("I'm making a cheese-free dinner" is not a milk allergy): only add them when the cook states them and confirms they should be saved. Pass only the fields to change. Lists replace the saved list, so read get_preferences first and send the full new list.

Input Schema

{
  "type": "object",
  "properties": {
    "cook_confirmed": {
      "type": "boolean",
      "const": true,
      "description": "True only when the cook asked for this exact change in their own words (units, household size and the other non-health settings) or said yes to it after you showed it (always for allergies, diets, avoid list, privacy)"
    },
    "allergies": {
      "description": "Major allergens: milk, eggs, fish, shellfish, tree_nuts, peanuts, wheat, soy, sesame",
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "milk",
          "eggs",
          "fish",
          "shellfish",
          "tree_nuts",
          "peanuts",
          "wheat",
          "soy",
          "sesame"
        ]
      }
    },
    "custom_allergies": {
      "description": "Other allergy ingredients, e.g. [\"kiwi\"]",
      "maxItems": 40,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "diets": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "vegetarian",
          "vegan",
          "pescatarian",
          "gluten-free",
          "dairy-free",
          "low-sodium",
          "halal",
          "kosher"
        ]
      }
    },
    "avoid": {
      "description": "Ingredients the cook dislikes",
      "maxItems": 40,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "avoid_mode": {
      "description": "exclude hides those recipes; rank_lower shows them lower",
      "type": "string",
      "enum": [
        "exclude",
        "rank_lower"
      ]
    },
    "servings": {
      "description": "Household size; null to use each recipe's own",
      "anyOf": [
        {
          "type": "integer",
          "minimum": 1,
          "maximum": 24
        },
        {
          "type": "null"
        }
      ]
    },
    "servings_mode": {
      "description": "offer (default): recipes open at their own servings and the household size is offered; always: recipes open scaled to it. Lists and meal plans use the household size either way",
      "type": "string",
      "enum": [
        "offer",
        "always"
      ]
    },
    "units": {
      "type": "string",
      "enum": [
        "us",
        "metric"
      ]
    },
    "weeknight_minutes": {
      "anyOf": [
        {
          "type": "integer",
          "minimum": 5,
          "maximum": 240
        },
        {
          "type": "null"
        }
      ]
    },
    "skill": {
      "anyOf": [
        {
          "type": "string",
          "enum": [
            "beginner",
            "comfortable",
            "confident"
          ]
        },
        {
          "type": "null"
        }
      ]
    },
    "equipment": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "air fryer",
          "slow cooker",
          "instant pot",
          "no oven"
        ]
      }
    },
    "cuisines_love": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "American",
          "Chinese",
          "Indian",
          "Italian",
          "Japanese",
          "Korean",
          "Mediterranean",
          "Mexican",
          "Middle Eastern",
          "Thai"
        ]
      }
    },
    "cuisines_skip": {
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "American",
          "Chinese",
          "Indian",
          "Italian",
          "Japanese",
          "Korean",
          "Mediterranean",
          "Mexican",
          "Middle Eastern",
          "Thai"
        ]
      }
    },
    "pantry": {
      "description": "Always-on-hand staples",
      "maxItems": 100,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 60
      }
    },
    "store": {
      "type": "object",
      "properties": {
        "retailer": {
          "anyOf": [
            {
              "type": "string",
              "maxLength": 60
            },
            {
              "type": "null"
            }
          ]
        },
        "zip": {
          "anyOf": [
            {
              "type": "string",
              "pattern": "^\\d{5}$"
            },
            {
              "type": "null"
            }
          ]
        }
      },
      "required": [
        "retailer",
        "zip"
      ]
    },
    "do_not_sell": {
      "description": "True keeps the cook out of every aggregated data product Befana sells or licenses",
      "type": "boolean"
    },
    "share_region": {
      "description": "False stops usage counts from recording the cook's state or country",
      "type": "boolean"
    },
    "workflow": {
      "description": "How the cook wants you to work with them. Pass only the keys that change",
      "type": "object",
      "properties": {
        "offer_shopping_list": {
          "description": "Shopping list after a recipe or plan: always (make it without asking), ask, never (stop offering)",
          "type": "string",
          "enum": [
            "always",
            "ask",
            "never"
          ]
        },
        "offer_order": {
          "description": "Grocery delivery after a list",
          "type": "string",
          "enum": [
            "always",
            "ask",
            "never"
          ]
        },
        "offer_fork_on_substitution": {
          "description": "Saving the cook's own version after a swap. always still shows the changes and needs their yes; it only skips asking to save",
          "type": "string",
          "enum": [
            "always",
            "ask",
            "never"
          ]
        },
        "offer_pantry_update": {
          "description": "Adding an order to the pantry and taking a cooked recipe's ingredients off it",
          "type": "string",
          "enum": [
            "always",
            "ask",
            "never"
          ]
        },
        "setup_questions": {
          "description": "never stops questions like household size",
          "type": "string",
          "enum": [
            "ask",
            "never"
          ]
        },
        "whats_new": {
          "description": "off stops mentions of new Befana features",
          "type": "string",
          "enum": [
            "on",
            "off"
          ]
        },
        "plan_meals": {
          "description": "The cook's usual number of meals for plan_meals",
          "anyOf": [
            {
              "type": "integer",
              "minimum": 1,
              "maximum": 14
            },
            {
              "type": "null"
            }
          ]
        }
      }
    }
  },
  "required": [
    "cook_confirmed"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_cook_profile(handle)

A cook's public page on Befana by handle (the author.handle on any recipe, or the cook's own): display name, photo, about me, location, interests and links when they show them, and their public recipes and variations with ratings and urls. Works signed out with a handle; pass no handle for the signed-in cook's own profile. ai_chef is true when the cook is an AI chef persona. Nothing private is ever here: no email, allergies, diet, preferences, saved recipes, lists or pantry.

Input Schema

{
  "type": "object",
  "properties": {
    "handle": {
      "description": "The cook's handle, e.g. \"andrew_rexroad\" (with or without @). Omit for the signed-in cook's own profile.",
      "type": "string",
      "maxLength": 40
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🔴update_profile(cook_confirmed, handle, display_name, about, location, ...)

Change the cook's own public profile at befana.app/cook/<handle>: handle, display name, about me, location, cooking interests, up to three links, and whether the photo and about me show (show_details; off until the cook turns it on). Before calling, tell the cook exactly what will change and get a clear yes; set cook_confirmed only then. Pass only the fields to change; interests and links replace the saved list. A changed handle keeps the old one redirecting for 90 days. A photo is uploaded on the website (Settings → Your public profile); photo: "google" copies the cook's Google account photo, photo: null removes it. Never write about-me text for the cook: only what they said.

Input Schema

{
  "type": "object",
  "properties": {
    "cook_confirmed": {
      "type": "boolean",
      "const": true,
      "description": "True only after the cook said yes to this exact change"
    },
    "handle": {
      "description": "3 to 30 letters, digits or underscores; reserved words are refused",
      "type": "string",
      "maxLength": 40
    },
    "display_name": {
      "type": "string",
      "maxLength": 60
    },
    "about": {
      "description": "Up to 300 characters, in the cook's words; null clears it",
      "anyOf": [
        {
          "type": "string",
          "maxLength": 300
        },
        {
          "type": "null"
        }
      ]
    },
    "location": {
      "description": "As the cook says it, e.g. \"Denver\"; null clears it",
      "anyOf": [
        {
          "type": "string",
          "maxLength": 60
        },
        {
          "type": "null"
        }
      ]
    },
    "interests": {
      "description": "Cooking interests, up to 10; replaces the list",
      "maxItems": 10,
      "type": "array",
      "items": {
        "type": "string",
        "maxLength": 30
      }
    },
    "links": {
      "description": "Up to 3; an Instagram, TikTok, YouTube or Substack link must be on that site; replaces the list",
      "maxItems": 3,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "website",
              "instagram",
              "tiktok",
              "youtube",
              "substack"
            ]
          },
          "url": {
            "type": "string",
            "maxLength": 300
          }
        },
        "required": [
          "kind",
          "url"
        ]
      }
    },
    "show_details": {
      "description": "True shows the photo, about me, location, interests and links on the public page",
      "type": "boolean"
    },
    "photo": {
      "description": "\"google\" copies the account's Google photo (processed and stored by Befana); null removes the photo",
      "anyOf": [
        {
          "type": "string",
          "const": "google"
        },
        {
          "type": "null"
        }
      ]
    }
  },
  "required": [
    "cook_confirmed"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}
🟢get_photo_queue(limit)

The cook's own published recipes that have no cover photo, a generated placeholder instead of a photo, or a cover that doesn't meet Befana's photo standard (dark, blurry, washed out, too small). Use it to help the cook decide what to reshoot. Returns each recipe's url, the current cover's tier and what's wrong with it.

Input Schema

{
  "type": "object",
  "properties": {
    "limit": {
      "default": 10,
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    }
  },
  "$schema": "http://json-schema.org/draft-07/schema#"
}
⚪report_content(kind, id, reason, note)

Flag a recipe, review, photo or a cook's profile for Befana's moderators: spam, offensive, unsafe as written, copied without permission, not a recipe, or something else. Only report what the cook asked to report, in their words. Moderators review every report; nothing is hidden automatically.

Input Schema

{
  "type": "object",
  "properties": {
    "kind": {
      "type": "string",
      "enum": [
        "recipe",
        "review",
        "photo",
        "profile"
      ]
    },
    "id": {
      "type": "string",
      "minLength": 1,
      "maxLength": 500,
      "description": "The recipe slug, the review id, the photo URL, or the cook's handle for a profile"
    },
    "reason": {
      "type": "string",
      "enum": [
        "spam",
        "offensive",
        "unsafe",
        "copyright",
        "not_recipe",
        "other"
      ],
      "description": "spam: Spam or advertising; offensive: Offensive or hateful; unsafe: Unsafe to cook or eat as written; copyright: Copied without permission; not_recipe: Not a real recipe; other: Something else"
    },
    "note": {
      "description": "What's wrong, in the cook's words",
      "type": "string",
      "maxLength": 500
    }
  },
  "required": [
    "kind",
    "id",
    "reason"
  ],
  "$schema": "http://json-schema.org/draft-07/schema#"
}

Community

Rate this Server

Evidence

Recent observations

verifiedversion not recorded24 tools