Odel
mcp recipes

mcp recipes

Local
@smeet666TypeScriptMITUpdated 3 days ago

Search six recipe sites at once, in French, English and Spanish, and scale quantities.

mcp-recipes

npm CI license MCP Registry Glama M8ven LobeHub Install in Cursor Install in VS Code

Recipes live on many sites, and each one writes them its own way: a French cooking site publishes in French, with its own measures and its own idea of what a serving is, and a wiki cookbook in English, with equipment lists and prose the first has no field for. Asking a question of one of them answers about one of them.

This server reads six. Three publish in French, Marmiton, Ptitchef and Supertoinette; two in English, the Wikibooks Cookbook and BBC Good Food; and one in Spanish, Pequerecetas. You can search them all with one question, read a recipe from any of them in one shape, put several versions of the same dish side by side, and rescale any ingredient list. It needs no API key and no account.

Version française


Install

One-click install

Install in Cursor Install in VS Code

Claude Code

claude mcp add recipes -- npx -y mcp-recipes

Claude Desktop, Cursor, and any client using the standard config format

{
  "mcpServers": {
    "recipes": {
      "command": "npx",
      "args": ["-y", "mcp-recipes"]
    }
  }
}

Node 24 or later is required, and no environment variable has to be set.

With Docker

{
  "mcpServers": {
    "recipes": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-recipes:4.0.0"]
    }
  }
}

-i keeps stdin open, which is where the protocol travels, and -t is left out because a TTY rewrites the stream. The container needs outbound HTTPS to www.marmiton.org, api.wikimedia.org, www.ptitchef.com, www.bbcgoodfood.com, www.supertoinette.com and www.pequerecetas.com, and nothing else: no volume, no port, no credential.

Bundle, without npm

Download mcp-recipes-4.0.0.mcpb from the latest release and open it. A client that supports MCP bundles installs it on its own, with no npm and no configuration file to edit. The bundle carries its dependencies, so nothing is fetched at install time.

What you can ask

  • "Find me carbonara recipes, from wherever you can."
  • "Compare the French and English versions of that dish."
  • "Read the second one for eight people."
  • "Which of them uses cream?"
  • "Scale this list from my notebook by 1.5."

The ordinary path runs from a search to a reading: a row carries an id naming its source, and get_recipe takes it.

The sources

SourceSiteLanguage
marmitonwww.marmiton.orgFrench
cookbookWikibooks CookbookEnglish
ptitchefwww.ptitchef.comFrench
goodfoodwww.bbcgoodfood.comEnglish
supertoinettewww.supertoinette.comFrench
pequerecetaswww.pequerecetas.comSpanish

A row's id names its source, so an identifier read from one answer goes back to the right site. Counts are never added across sources, and a source that failed is reported as having failed rather than as having found nothing.

Each site is read at its own pace: two of them ask for three seconds between requests, and a setting posted for all of them can only make this server more patient than the slowest asks for.

Two of these sites file something other than a recipe at the address a recipe lives at. The Wikibooks Cookbook keeps pages about an ingredient beside the recipes using it, and Pequerecetas publishes articles that gather recipes. A search says so, and get_recipe says what it read off the page.

Tools

ToolWhat it does
search_recipesSearches every source with one question.
get_recipeReads one recipe from any source, in one shape.
compare_recipesPuts several versions of the same dish side by side.
scale_ingredientsRescales any ingredient list, with no request to any site.

search_recipes

Searches every source with one question.

ArgumentTypeRequiredWhat it does
querystring, 1 to 200 charactersyesThe dish or the ingredient to look for.
limit_per_sourceinteger, 1 to 25, default 5noRows to keep from each source.
sourcesarray of source idsnoAsk these sources alone.
fan_outboolean, default truenoAsk every source rather than stopping at the first that answers.

In return: results, rows carrying id, which get_recipe takes; source and source_name saying which site published the row; title; url; image_url; and an excerpt where the source offers one. per_source gives one report per site with its status, reading answered or failed, the count it contributed, and its reported_total alongside reported_total_means, which says what that number counts on that site. names_the_dish says how many of that site's rows carry the dish in their title, out of count: a search index answers the words it is handed, so a site can offer rows and none of them be the dish. order says in words how the list was built.

get_recipe

Reads one recipe from any source, in one shape.

ArgumentTypeRequiredWhat it does
idstring, 1 to 500 charactersyesThe identifier a row carries, such as marmiton:44078. Two sources address a recipe by a bare number, so spell an id with its source.
servingsinteger, 1 to 500noRescale the ingredients to this many servings.
sectionsarray of ingredients, steps, times, nutrition, tips, equipment, default ["ingredients", "steps"]noWhich parts to return.
max_stepsinteger, 1 to 100, default 20noSteps to serve.
max_gatheredinteger, 1 to 500, default 30noRecipes and headings to return from an address that gathers recipes.
max_step_charsinteger, 80 to 4000, default 600noCharacters kept per step.

In return: kind says what the address held. A recipe answer carries recipe and no collection; a collection answer carries collection and no recipe, and is an article gathering other recipes, with the headings it is built from and the recipes it points at, each of them readable with get_recipe.

A recipe comes in the shape every source is rendered into, whichever published it: its title, its address, its ingredients with each line's scaling and is_equipment, its steps, and the sections asked for. A field one source publishes and another has no notion of comes back absent rather than invented. rest_minutes carries a resting time from a source that prints one apart, and is in no other time here. steps_as_one_block says when a source published its method as one block of prose rather than as steps. withheld names a part a source keeps for its subscribers, which is a part the page has rather than a part that could not be read. scaling_summary counts the lines four ways, and the four add up to the list. Raise max_step_chars when a step was cut mid-sentence.

compare_recipes

Puts several versions of the same dish side by side.

ArgumentTypeRequiredWhat it does
dishstring, 1 to 200 charactersyesThe dish to compare.
servingsinteger, 1 to 500noRescale every version to this many servings.
sectionsarray of ingredients, steps, times, nutrition, tips, equipment, default ["ingredients"]noWhich parts to return per version.
max_stepsinteger, 1 to 100, default 10noSteps to serve per version.
max_step_charsinteger, 80 to 4000, default 600noCharacters kept per step.
sourcesarray of source idsnoCompare these sources alone.

In return: versions, one recipe per source that answered, all rescaled to the same number of servings so their quantities can be read against each other, and differences, what separates them. per_source reports each site as a search does.

scale_ingredients

Rescales any ingredient list, with no request to any site.

ArgumentTypeRequiredWhat it does
ingredientsarray of 1 to 200 linesyesThe lines to rescale.
factornumber, up to 1000one of twoThe multiplier to apply.
from_servingsinteger, 1 to 500one of twoHow many servings the list is written for.
to_servingsinteger, 1 to 500one of twoHow many servings are wanted.
languageauto, fr, en or es, default autonoHow each line is read.

Pass factor, or the from_servings and to_servings pair. auto reads each line on its own, which is what a list holding more than one language needs; naming a language reads every line that way.

In return: the rescaled lines in the shape get_recipe returns, each with its scaling.

Rescaling the quantities

A quantity is stated in the unit that suits it, so a line can come back in a different unit from the one the recipe used: 200 g multiplied by twenty reads 4 kg.

How finely an ingredient can be divided depends on what it is. A baguette can be cut in two, in three or in four; an egg cannot be shared out. A quantity landing between the two is rounded, and the rescaled recipe then departs a little from the proportions of the original. The line carries rounded, and its note says what was done.

The sources write their quantities in their own languages, and a line is read in the language it was written in. The figures are this server's arithmetic, so say they were recomputed when you show them.

What an answer states about the sources

Every answer accounts for each source separately. A site that failed, one nobody asked, and one that answered with nothing are three different things, and they are reported as three. A total stays beside the source that published it, with what that source counts when it says it: one site counts a whole category, another counts the rows it served, and a third publishes no total at all.

Configuration

Every variable is optional. Set them in the env block of your client config.

VariableDefaultWhat it does
RECIPES_USER_AGENTthe project identityNames your application to the sites, with an address where a person can be reached.
RECIPES_MIN_INTERVAL_MS1000Gap between two requests to one site, from 500 to 60000.
RECIPES_TIMEOUT_MS20000Deadline for one request, from 1000 to 120000.
RECIPES_MAX_RETRIES3Attempts after a transient failure, from 0 to 8.
RECIPES_CACHE_TTL_MS900000How long an answer stays in memory, from 0 to 86400000.
RECIPES_CACHE_MAX_ENTRIES200Answers held in memory at once, from 1 to 5000.
RECIPES_LOG_LEVELerrorsilent, error, info or debug, written to stderr.

A value outside its range falls back to the default, and the reason is written to stderr.

Errors

Every failure carries one of six codes, a message, and where it helps a hint naming the next move.

CodeWhat happenedWhat to do
not_foundA source answered, and holds no such recipe.Check the identifier with search_recipes.
invalid_inputThe arguments were refused before any request went out.Read the message, which names the argument.
rate_limitedA source asked this client to slow down.Wait, then call again with the same arguments. The recipe is still there.
parse_failureA page loaded and the expected content was absent.Report it at the issue tracker.
network_errorThe request did not complete.Try again shortly.
timeoutThe request passed its deadline.Raise RECIPES_TIMEOUT_MS, or ask for fewer rows.

A source that failed is reported per source rather than failing the whole answer, so one silent site never hides the other.

As a library

The layer reading the sites is published on its own, with its pacing, its cache and its errors, and with no protocol attached.

import { RecipesClient } from "mcp-recipes/client";

const client = new RecipesClient();
const { rows, reports } = await client.searchRecipes("carbonara", 3);
console.log(
  rows.length,
  reports.map((report) => report.status),
);

const { recipe } = await client.getRecipe(rows[0].id);

searchRecipes(query, limitPerSource, sources?, options?) answers { rows, reports }: one report per source, saying whether it answered and what its own count measured, so a source that failed is never read as a source that holds nothing. getRecipe(id) answers { recipe, cached, read }, and throws an error carrying one of the six codes. client.profiles lists the sources the build registers.

The scaler is published separately at mcp-recipes/scale, and works offline on any list:

import { scaleIngredients } from "mcp-recipes/scale";

scaleIngredients(["200 g de harina", "4 oeufs", "1 cup milk"], { factor: 2 });

Each site keeps its own pace, and the floors hold here as well.

Pacing and attribution

Each site is paced on its own, one request at a time with at least a second between two, and the floor of half a second holds however the server is configured. Two of the sites ask for more, three seconds between two requests, and they get it: a setting posted for every source can raise a site's spacing and never lower it. Asking every site at once therefore costs each of them one request, never two. The User-Agent always ends with the project identity and an address where a person can be reached.

Every row carries the address of the recipe's own page and the name of the site that published it. The Cookbook pages are published under CC BY-SA 4.0, which asks that what is built on them be shared under the same licence. Marmiton, Ptitchef, BBC Good Food, Supertoinette and Pequerecetas state no terms on a recipe page, and their recipes belong to those sites and to the cooks who wrote them. Silence is not a grant, so credit the site and link the page you took a recipe from.

A recipe BBC Good Food keeps for its subscribers comes back without its ingredients and its method, named as a recipe held back, with the address of its page. This server does not reconstruct what that site chose to sell.

Two figures the sites publish are not repeated here. A difficulty is a word each site writes its own way, on no scale any of them publishes, so it sits on no axis along which two versions could be put. A cost is a price in euros on one site and a rank inside its own list on another, and one field holding both would invite them to be compared.

This MCP server is an unofficial project, with no affiliation to any of the sites it reads.

Privacy

This server collects nothing about you and sends nothing to its author. It runs on your machine, contacts www.marmiton.org, api.wikimedia.org, www.ptitchef.com, www.bbcgoodfood.com, www.supertoinette.com and www.pequerecetas.com and nothing else, holds its answers in memory while it runs, and writes nothing to disk. PRIVACY.md states what a request carries and which settings change any of it.

Development

npm install
npm run build:fixtures
npm test
npm run check

Tests run against generated fixtures and make no network request. The live suite, npm run test:live, makes one request per route and runs nightly against the sites themselves.

Contributing

Bugs, questions and ideas belong in the issue tracker. Pull requests are welcome; opening an issue first helps agree on the shape of the change. See CONTRIBUTING.md.

License

MIT, see LICENSE. The recipes belong to the sites that published them and to their authors.


mcp-recipes (français)

English version

Les recettes vivent sur beaucoup de sites, et chacun les écrit à sa façon : un site de cuisine français publie en français, avec ses mesures et son idée de ce qu'est une part, et un wiki de cuisine en anglais, avec des listes de matériel et une prose pour lesquelles le premier n'a aucun champ. Poser une question à l'un d'eux répond au sujet de l'un d'eux.

Ce serveur en lit six. Trois publient en français, Marmiton, Ptitchef et Supertoinette ; deux en anglais, le Cookbook des Wikibooks et BBC Good Food ; un en espagnol, Pequerecetas. On peut chercher dans les six avec une seule question, lire une recette de n'importe lequel sous une seule forme, mettre plusieurs versions d'un même plat côte à côte, et adapter n'importe quelle liste d'ingrédients. Aucune clé d'API, aucun compte.

Installation

Installation en un clic

Install in Cursor Install in VS Code

Claude Code

claude mcp add recipes -- npx -y mcp-recipes

Claude Desktop, Cursor, et tout client au format de configuration standard

{
  "mcpServers": {
    "recipes": {
      "command": "npx",
      "args": ["-y", "mcp-recipes"]
    }
  }
}

Node 24 ou plus récent est nécessaire, et aucune variable d'environnement n'est à renseigner.

Avec Docker

{
  "mcpServers": {
    "recipes": {
      "command": "docker",
      "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-recipes:4.0.0"]
    }
  }
}

-i garde l'entrée standard ouverte, qui est le canal du protocole, et -t est omis parce qu'un TTY réécrit le flux. Le conteneur a besoin d'un accès HTTPS sortant vers www.marmiton.org, api.wikimedia.org, www.ptitchef.com, www.bbcgoodfood.com, www.supertoinette.com et www.pequerecetas.com, et de rien d'autre : aucun volume, aucun port, aucun identifiant.

Bundle, sans npm

Téléchargez mcp-recipes-4.0.0.mcpb depuis la dernière publication et ouvrez-le. Un client qui gère les bundles MCP l'installe seul, sans npm et sans fichier de configuration à modifier. Le bundle emporte ses dépendances, donc rien n'est téléchargé à l'installation.

Ce qu'on peut demander

  • « Trouve-moi des recettes de carbonara, d'où que tu puisses. »
  • « Compare les versions française et anglaise de ce plat. »
  • « Lis-moi la seconde pour huit personnes. »
  • « Laquelle utilise de la crème ? »
  • « Multiplie par 1,5 cette liste de mon carnet. »

Le chemin ordinaire va d'une recherche à une lecture : une ligne porte un id qui nomme sa source, et get_recipe le reprend.

Les sources

SourceSiteLangue
marmitonwww.marmiton.orgfrançais
cookbookCookbook Wikibooksanglais
ptitchefwww.ptitchef.comfrançais
goodfoodwww.bbcgoodfood.comanglais
supertoinettewww.supertoinette.comfrançais
pequerecetaswww.pequerecetas.comespagnol

L'id d'une ligne nomme sa source, donc un identifiant lu dans une réponse retourne vers le bon site. Les comptes ne sont jamais additionnés entre sources, et une source qui a échoué est rapportée comme ayant échoué plutôt que comme n'ayant rien trouvé.

Chaque site est lu à son propre rythme : deux d'entre eux demandent trois secondes entre deux requêtes, et un réglage posé pour tous ne peut que rendre ce serveur plus patient que ce que le plus lent demande.

Deux de ces sites rangent autre chose qu'une recette à l'adresse où vit une recette. Le Cookbook des Wikibooks garde des pages sur un ingrédient à côté des recettes qui l'emploient, et Pequerecetas publie des articles qui rassemblent des recettes. Une recherche le dit, et get_recipe dit ce qu'il a lu sur la page.

Les outils

OutilCe qu'il fait
search_recipesCherche dans toutes les sources avec une seule question.
get_recipeLit une recette de n'importe quelle source, sous une seule forme.
compare_recipesMet plusieurs versions d'un même plat côte à côte.
scale_ingredientsAdapte n'importe quelle liste d'ingrédients, sans requête.

search_recipes

Cherche dans toutes les sources avec une seule question.

ArgumentTypeRequisCe qu'il fait
querychaîne, 1 à 200 caractèresouiLe plat ou l'ingrédient cherché.
limit_per_sourceentier, 1 à 25, défaut 5nonLignes à garder de chaque source.
sourcestableau d'identifiants de sourcenonN'interroger que ces sources.
fan_outbooléen, défaut truenonInterroger chaque source plutôt que s'arrêter à la première qui répond.

En retour : results, des lignes portant id, que get_recipe reprend ; source et source_name qui disent quel site a publié la ligne ; title ; url ; image_url ; et un excerpt là où la source en propose un. per_source donne un rapport par site avec son status, valant answered ou failed, le count qu'il a fourni, et son reported_total accompagné de reported_total_means, qui dit ce que ce nombre compte sur ce site. names_the_dish dit combien des lignes de ce site portent le plat dans leur titre, sur count : un index de recherche répond aux mots qu'on lui tend, donc un site peut rendre des lignes dont aucune n'est le plat. order dit en mots comment la liste a été bâtie.

get_recipe

Lit une recette de n'importe quelle source, sous une seule forme.

ArgumentTypeRequisCe qu'il fait
idchaîne, 1 à 500 caractèresouiL'identifiant d'une ligne, tel que marmiton:44078. Deux sources adressent une recette par un nombre nu : écrivez l'id avec sa source.
servingsentier, 1 à 500nonAdapte les ingrédients à ce nombre de parts.
sectionstableau de ingredients, steps, times, nutrition, tips, equipment, défaut ["ingredients", "steps"]nonLes parties à rendre.
max_gatheredentier, 1 à 500, défaut 30nonRecettes et intertitres rendus pour une adresse qui rassemble des recettes.
max_stepsentier, 1 à 100, défaut 20nonÉtapes à servir.
max_step_charsentier, 80 à 4000, défaut 600nonCaractères gardés par étape.

En retour : kind dit ce que l'adresse portait. Une réponse recipe porte recipe et pas de collection ; une réponse collection porte collection et pas de recipe, et c'est un article rassemblant d'autres recettes, avec les headings dont il est bâti et les recipes vers lesquelles il pointe, chacune lisible par get_recipe.

Une recette vient dans la forme où toutes les sources sont rendues, quelle que soit celle qui l'a publiée : son titre, son adresse, ses ingrédients avec le scaling et l'is_equipment de chaque ligne, ses étapes, et les parties demandées. Un champ qu'une source publie et dont une autre n'a pas la notion revient absent plutôt qu'inventé. rest_minutes porte le temps de repos d'une source qui l'imprime à part, et il n'entre dans aucun autre temps rendu ici. steps_as_one_block dit quand une source a publié sa méthode d'un seul bloc de prose plutôt qu'en étapes. scaling_summary compte les lignes de quatre façons, et les quatre font le total de la liste. withheld nomme la partie qu'une source réserve à ses abonnés, qui est une partie que la page porte et non une partie illisible. Augmentez max_step_chars quand une étape a été coupée au milieu d'une phrase.

compare_recipes

Met plusieurs versions d'un même plat côte à côte.

ArgumentTypeRequisCe qu'il fait
dishchaîne, 1 à 200 caractèresouiLe plat à comparer.
servingsentier, 1 à 500nonAdapte chaque version à ce nombre de parts.
sectionstableau de ingredients, steps, times, nutrition, tips, equipment, défaut ["ingredients"]nonLes parties à rendre par version.
max_stepsentier, 1 à 100, défaut 10nonÉtapes à servir par version.
max_step_charsentier, 80 à 4000, défaut 600nonCaractères gardés par étape.
sourcestableau d'ids de sourcenonNe compare que ces sources.

En retour : versions, une recette par source ayant répondu, toutes adaptées au même nombre de parts pour que leurs quantités se lisent l'une contre l'autre, et differences, ce qui les sépare. per_source rapporte chaque site comme le fait une recherche.

scale_ingredients

Adapte n'importe quelle liste d'ingrédients, sans requête à aucun site.

ArgumentTypeRequisCe qu'il fait
ingredientstableau de 1 à 200 lignesouiLes lignes à adapter.
factornombre, jusqu'à 1000l'un des deuxLe multiplicateur à appliquer.
from_servingsentier, 1 à 500l'un des deuxLe nombre de parts de la liste d'origine.
to_servingsentier, 1 à 500l'un des deuxLe nombre de parts voulu.
languageauto, fr, en ou es, défaut autononComment chaque ligne est lue.

Passez factor, ou le couple from_servings et to_servings. auto lit chaque ligne pour elle-même, ce dont a besoin une liste portant plusieurs langues ; nommer une langue lit toutes les lignes ainsi.

En retour : les lignes adaptées dans la forme que rend get_recipe, chacune avec son scaling et son is_equipment, vrai pour une ligne qui nomme un outil et qu'on laisse telle quelle. scaled_count, rounded_count, unscaled_count et equipment_count font le total des lignes envoyées.

L'adaptation des quantités

Une quantité est exprimée dans l'unité qui lui convient. Après adaptation, une ligne peut donc apparaître dans une autre unité que celle de la recette : 200 g multipliés par vingt donnent 4 kg.

La finesse à laquelle un ingrédient se coupe dépend de sa nature. Une baguette se coupe en deux, en trois ou en quatre ; un oeuf ne se partage pas. Une quantité qui tombe entre les deux est donc arrondie, et la recette adaptée s'écarte alors un peu des proportions de l'originale. La ligne porte rounded, et sa note dit ce qui a été fait.

Les sources écrivent leurs quantités dans leur propre langue, et une ligne est lue dans la langue où elle a été écrite. Les chiffres sont l'arithmétique de ce serveur, donc dites qu'ils ont été recalculés quand vous les montrez.

Ce qu'une réponse dit des sources

Chaque réponse rend compte de chaque source séparément. Un site qui a échoué, un que personne n'a interrogé et un qui a répondu vide sont trois choses différentes, et elles sont rapportées comme trois. Un total reste à côté de la source qui l'a publié, avec ce que cette source compte en le disant : l'un compte une catégorie entière, un autre compte les lignes qu'il a servies, et un troisième ne publie aucun total.

Configuration

Chaque variable est facultative. Elles se posent dans le bloc env de la configuration du client.

VariableDéfautCe qu'elle fait
RECIPES_USER_AGENTl'identité du projetNomme votre application auprès des sites, avec une adresse où joindre une personne.
RECIPES_MIN_INTERVAL_MS1000Écart entre deux requêtes vers un même site, de 500 à 60000.
RECIPES_TIMEOUT_MS20000Délai d'une requête, de 1000 à 120000.
RECIPES_MAX_RETRIES3Tentatives après un échec passager, de 0 à 8.
RECIPES_CACHE_TTL_MS900000Durée pendant laquelle une réponse reste en mémoire, de 0 à 86400000.
RECIPES_CACHE_MAX_ENTRIES200Réponses gardées en mémoire à la fois, de 1 à 5000.
RECIPES_LOG_LEVELerrorsilent, error, info ou debug, écrit sur la sortie d'erreur.

Une valeur hors de sa plage retombe sur le défaut, et la raison est écrite sur la sortie d'erreur.

Erreurs

Chaque échec porte un des six codes, un message, et quand cela aide une indication du geste suivant.

CodeCe qui s'est passéQue faire
not_foundUne source a répondu, et n'a pas cette recette.Vérifiez l'identifiant avec search_recipes.
invalid_inputLes arguments ont été refusés avant toute requête.Lisez le message, qui nomme l'argument.
rate_limitedUne source demande à ce client de ralentir.Attendez, puis rappelez avec les mêmes arguments. La recette est toujours là.
parse_failureUne page a chargé et le contenu attendu est absent.Signalez-le sur le suivi d'incidents.
network_errorLa requête n'a pas abouti.Réessayez sous peu.
timeoutLa requête a dépassé son délai.Augmentez RECIPES_TIMEOUT_MS, ou demandez moins de lignes.

Une source qui échoue est rapportée source par source plutôt que de faire échouer toute la réponse, donc un site silencieux n'en cache jamais un autre.

Comme bibliothèque

La couche qui lit les sites est publiée seule, avec son rythme, son cache et ses erreurs, sans protocole attaché.

import { RecipesClient } from "mcp-recipes/client";

const client = new RecipesClient();
const { rows, reports } = await client.searchRecipes("carbonara", 3);
console.log(
  rows.length,
  reports.map((report) => report.status),
);

const { recipe } = await client.getRecipe(rows[0].id);

searchRecipes(query, limitPerSource, sources?, options?) répond { rows, reports } : un rapport par source, disant si elle a répondu et ce que son propre compte mesure, pour qu'une source en échec ne se lise jamais comme une source qui ne détient rien. getRecipe(id) répond { recipe, cached, read }, et lève une erreur portant un des six codes. client.profiles énumère les sources que cette construction enregistre.

La mise à l'échelle est publiée à part, sous mcp-recipes/scale, et travaille hors ligne sur n'importe quelle liste :

import { scaleIngredients } from "mcp-recipes/scale";

scaleIngredients(["200 g de harina", "4 oeufs", "1 cup milk"], { factor: 2 });

Chaque site garde son propre rythme, et les planchers tiennent également ici.

Rythme et attribution

Chaque site est cadencé pour lui-même, une requête à la fois avec au moins une seconde entre deux, et le plancher d'une demi-seconde tient quelle que soit la configuration. Deux des sites en demandent davantage, trois secondes entre deux requêtes, et ils l'obtiennent : un réglage posé pour toutes les sources peut élargir l'écart d'un site, jamais le réduire. Les interroger toutes à la fois coûte donc à chacune une requête, jamais deux. Le User-Agent se termine toujours par l'identité du projet et une adresse où joindre une personne.

Chaque ligne porte l'adresse de la page de la recette et le nom du site qui l'a publiée. Les pages du Cookbook sont publiées sous CC BY-SA 4.0, qui demande que ce qu'on bâtit dessus soit partagé sous la même licence. Marmiton, Ptitchef, BBC Good Food, Supertoinette et Pequerecetas n'énoncent aucune condition sur une page de recette, et leurs recettes appartiennent à ces sites et aux cuisiniers qui les ont écrites. Le silence n'est pas une autorisation : créditez le site et liez la page d'où vient la recette.

Une recette que BBC Good Food réserve à ses abonnés revient sans ses ingrédients ni sa méthode, nommée comme une recette retenue, avec l'adresse de sa page. Ce serveur ne reconstitue pas ce que ce site a choisi de vendre.

Deux chiffres que les sites publient ne sont pas repris ici. Une difficulté est un mot que chaque site écrit à sa façon, sur aucune échelle publiée : elle ne siège sur aucun axe le long duquel deux versions se compareraient. Un coût est un prix en euros sur un site et un rang dans sa propre liste sur un autre, et un seul champ portant les deux inviterait à les comparer.

Ce MCP est un projet non officiel, sans affiliation à aucun des sites qu'il lit.

Confidentialité

Ce serveur ne collecte rien sur vous et n'envoie rien à son auteur. Il tourne sur votre machine, ne joint que www.marmiton.org, api.wikimedia.org, www.ptitchef.com, www.bbcgoodfood.com, www.supertoinette.com et www.pequerecetas.com, garde ses réponses en mémoire le temps qu'il tourne, et n'écrit rien sur le disque. PRIVACY.md dit ce qu'une requête emporte et quels réglages changent cela.

Développement

npm install
npm run build:fixtures
npm test
npm run check

Les tests s'exécutent sur des fixtures engendrées et n'émettent aucune requête. La suite en direct, npm run test:live, émet une requête par route et tourne chaque nuit contre les sites eux-mêmes.

Contribuer

Les anomalies, les questions et les idées ont leur place dans le suivi d'incidents. Les propositions de modification sont bienvenues ; ouvrir un ticket d'abord aide à s'accorder sur la forme du changement. Voir CONTRIBUTING.md.

Licence

MIT, voir LICENSE. Les recettes appartiennent aux sites qui les ont publiées et à leurs auteurs.