{
  "markdown": "<img src=\"assets/icon-128.png\" alt=\"\" width=\"96\" align=\"right\">\n\n# mcp-pequerecetas\n\n[![npm](https://img.shields.io/npm/v/mcp-pequerecetas.svg)](https://www.npmjs.com/package/mcp-pequerecetas)\n[![CI](https://github.com/smeet666/mcp-pequerecetas/actions/workflows/ci.yml/badge.svg)](https://github.com/smeet666/mcp-pequerecetas/actions/workflows/ci.yml)\n[![license](https://img.shields.io/npm/l/mcp-pequerecetas.svg)](./LICENSE)\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-6E56CF)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.smeet666/mcp-pequerecetas)\n[![Glama](https://glama.ai/mcp/servers/smeet666/mcp-pequerecetas/badges/score.svg)](https://glama.ai/mcp/servers/smeet666/mcp-pequerecetas)\n[![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=pequerecetas&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1wZXF1ZXJlY2V0YXMiXX0=)\n[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=pequerecetas&config=%7B%22name%22%3A%22pequerecetas%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mcp-pequerecetas%22%5D%7D)\n\n[Pequerecetas](https://www.pequerecetas.com) is a Spanish home-cooking site\nwritten for families. It holds a few thousand recipes with their ingredients,\ntheir steps and their photographs, and files each one under the diet it suits,\nthe appliance it is cooked in, the occasion it is made for and the age of whoever\neats it, from six months up.\n\nThis server connects a chat client to that site. You can search its recipes, read\none with its quantities rescaled to the number of people at your table, list the\nvalues each taxonomy publishes, walk a taxonomy page by page, and rescale any\nSpanish ingredient list you already hold. It needs no API key and no account.\n\n_[Version française](#mcp-pequerecetas-français)_\n\n---\n\n## Install\n\n**One-click install**\n\n[![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=pequerecetas&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1wZXF1ZXJlY2V0YXMiXX0=)\n[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=pequerecetas&config=%7B%22name%22%3A%22pequerecetas%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mcp-pequerecetas%22%5D%7D)\n\n**Claude Code**\n\n```bash\nclaude mcp add pequerecetas -- npx -y mcp-pequerecetas\n```\n\n**Claude Desktop, Cursor, and any client using the standard config format**\n\n```json\n{\n  \"mcpServers\": {\n    \"pequerecetas\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-pequerecetas\"]\n    }\n  }\n}\n```\n\nNode 24 or later is required, and no environment variable has to be set.\n\n### With Docker\n\n```json\n{\n  \"mcpServers\": {\n    \"pequerecetas\": {\n      \"command\": \"docker\",\n      \"args\": [\"run\", \"-i\", \"--rm\", \"ghcr.io/smeet666/mcp-pequerecetas:1.0.1\"]\n    }\n  }\n}\n```\n\n`-i` keeps stdin open, which is where the protocol travels, and `-t` is left out\nbecause a TTY rewrites the stream. The container needs outbound HTTPS to\n`www.pequerecetas.com`, and nothing else: no volume, no port, no credential.\n\n### Bundle, without npm\n\nDownload `mcp-pequerecetas-1.0.1.mcpb` from\n[the latest release](https://github.com/smeet666/mcp-pequerecetas/releases/latest)\nand open it. A client that supports MCP bundles installs it on its own, with no\nnpm and no configuration file to edit. The bundle carries its dependencies, so\nnothing is fetched at install time.\n\n## What you can ask\n\n- « Búscame una receta de paella de marisco. »\n- \"Read me that recipe for eight people.\"\n- \"What can I cook in an air fryer on this site?\"\n- \"Show me the purées it files under six months.\"\n- \"Scale this Spanish ingredient list by three.\"\n\nPequerecetas is written in Spanish and its search matches the words a page was\nwritten with, so recipes are found in Spanish. The ordinary path runs from a\nsearch or a taxonomy to a recipe: a row carries an `id`, and `get_recipe` takes\nthat id.\n\n## Tools\n\n| Tool                | What it does                                                       |\n| ------------------- | ------------------------------------------------------------------ |\n| `get_recipe`        | Reads one page of the recipe section, rescaled on request.         |\n| `search_recipes`    | Finds recipes by dish or by ingredient.                            |\n| `list_facets`       | Lists the values each taxonomy publishes.                          |\n| `browse_recipes`    | Reads one taxonomy, page by page.                                  |\n| `scale_ingredients` | Rescales any Spanish ingredient list, with no request to the site. |\n\n### `get_recipe`\n\nReads one page of the recipe section, and rescales its quantities when a number\nof servings is given.\n\n| Argument   | Type                        | Required | What it does                                         |\n| ---------- | --------------------------- | -------- | ---------------------------------------------------- |\n| `id`       | string, 1 to 200 characters | yes      | The slug in a recipe's address, as a row carries it. |\n| `servings` | integer, 1 to 1000          | no       | Rescale the quantities to this many.                 |\n\n**In return:** `kind`, which reads `recipe` or `collection`. The site publishes\nboth at this kind of address and describes them alike, so this is what tells them\napart: a collection is an article gathering other recipes, and it comes back with\n`headings` and `recipes`, the rows it points at, in place of a recipe's fields.\n\nA recipe carries `source_shape`, reading `structured` when the block the page\npublishes for search engines held its ingredients and `article` when they were\nread from the body of the page, which is where most of this site's recipes keep\nthem. Then come `title`, `url`, `description`, `published_at`, `modified_at`,\n`prep_minutes`, `cook_minutes`, `total_minutes`, `categories`, `cuisines`,\n`keywords`, `author`, `author_url`, `rating`, `nutrition` and `images`, each\n`null` or empty where the page states nothing. `yield` says what the recipe was\nwritten for and what it was rescaled to; a page stating no number of servings\ncomes back with `factor` at 1 and a note saying why. Each line of `ingredients`\ncarries `scaling`, reading `scaled`, `rounded` or `unscaled`, and `is_equipment`,\nwhich marks a line naming a tool rather than something eaten.\n\n### `search_recipes`\n\nSearches the recipes for a dish or an ingredient.\n\n| Argument | Type                        | Required | What it does                         |\n| -------- | --------------------------- | -------- | ------------------------------------ |\n| `query`  | string, 1 to 120 characters | yes      | A dish or an ingredient, in Spanish. |\n| `limit`  | integer, 1 to 60            | no       | Rows to return.                      |\n\n**In return:** rows carrying `id`, which `get_recipe` takes, `title`, `url` and\n`image_url`. Alongside come `result_count` for the rows returned and\n`total_available`, which is always `null`: the site publishes no count of what a\nsearch matched. The site serves its search on a single page and answers a request\nfor a second with the first again, so these are all the rows it offers for a\nquery. Some rows are articles gathering recipes, which `get_recipe` reports as a\n`collection`.\n\n### `list_facets`\n\nLists the values the site browses its recipes by, read from the sitemap each\ntaxonomy publishes.\n\n| Argument | Type                       | Required | What it does                           |\n| -------- | -------------------------- | -------- | -------------------------------------- |\n| `facet`  | string, 1 character and up | no       | One taxonomy. All eight when left out. |\n\nThe taxonomies are `dieta`, `edad`, `ingrediente`, `ocasion`, `recetas-de`,\n`tecnica`, `tipo-de-cocina` and `tipo-plato`: diet, the age of whoever eats it,\nmain ingredient, occasion, moment of the day, appliance, cuisine and kind of\ndish.\n\n**In return:** `facets`, each carrying `name`, `value_count` and `values`, whose\n`value` is the slug `browse_recipes` takes. The values keep the order the site\npublishes them in. Reading all eight costs one request per taxonomy. A taxonomy\nthat could not be read is named in `notes` and left out of `facets`, so a\nlisting short of one never reads like a site that has seven.\n\n### `browse_recipes`\n\nReads one page of a taxonomy's recipes.\n\n| Argument | Type                        | Required | What it does                                    |\n| -------- | --------------------------- | -------- | ----------------------------------------------- |\n| `facet`  | string, 1 character and up  | yes      | The taxonomy to browse.                         |\n| `value`  | string, 1 to 120 characters | yes      | A slug from `list_facets`, such as `thermomix`. |\n| `page`   | integer, 1 to 200           | no       | Which page to read, the first by default.       |\n\n**In return:** rows of the same shape `search_recipes` returns, with\n`page_served` for the page the site actually served, `has_more` for whether its\nown pagination offers another, and `total_available`, always `null` because the\nsite prints no count on these pages. The site writes its own slugs, so one built\nby hand reaches a page it does not hold and comes back as `not_found`. The\ntaxonomies cannot be combined: the site offers no way to ask for two at once.\n\n### `scale_ingredients`\n\nRescales a list of Spanish ingredient lines. It reaches no site.\n\n| Argument        | Type                              | Required | What it does                        |\n| --------------- | --------------------------------- | -------- | ----------------------------------- |\n| `ingredients`   | array of 1 to 200 strings         | yes      | The lines to rescale, as written.   |\n| `factor`        | number, greater than 0 up to 1000 | one of   | What to multiply the quantities by. |\n| `from_servings` | integer, 1 to 1000                | one of   | How many the list was written for.  |\n| `to_servings`   | integer, 1 to 1000                | one of   | How many it should serve.           |\n\nGive `factor`, or `from_servings` and `to_servings` together. Naming both ways at\nonce is refused, because they can ask for different things.\n\n**In return:** each line with `text` as it now reads, `original` as it was given,\n`amount`, `amount_max`, `unit`, and `scaling`, which carries the honesty of the\nanswer: `scaled` when the arithmetic landed exactly, `rounded` when the value\nmoved to stay something a kitchen can measure out, `unscaled` when the line\ncarries no quantity. `is_equipment` marks a line naming a tool. Alongside come\n`scaled_count`, `rounded_count` and `unscaled_count`. Nothing is converted\nbetween unit systems, and an approximate measure such as a `pizca` keeps the size\nthe cook gives it.\n\n## Configuration\n\n| Variable                | Default  | Bounds                     | What it does                                       |\n| ----------------------- | -------- | -------------------------- | -------------------------------------------------- |\n| `PQR_USER_AGENT`        | unset    |                            | Prefixed to this server's own User-Agent.          |\n| `PQR_MIN_INTERVAL_MS`   | `3000`   | 3000 to 60000              | Milliseconds between two requests.                 |\n| `PQR_TIMEOUT_MS`        | `20000`  | 1000 to 120000             | How long one request may take.                     |\n| `PQR_MAX_RETRIES`       | `3`      | 0 to 8                     | Attempts at a request the site did not answer.     |\n| `PQR_CACHE_TTL_MS`      | `900000` | 0 to 86400000              | How long a read is held. Zero turns the store off. |\n| `PQR_CACHE_MAX_ENTRIES` | `200`    | 1 to 5000                  | Reads held at once.                                |\n| `PQR_LOG_LEVEL`         | `error`  | silent, error, info, debug | What goes to stderr.                               |\n\nThe interval has a floor of 3000 milliseconds. A value below it is refused and\nthe default stands, which is stated on stderr rather than applied in silence.\n\n## Errors\n\n| Code            | What it means                               | What to do                                            |\n| --------------- | ------------------------------------------- | ----------------------------------------------------- |\n| `not_found`     | The site holds nothing at that address.     | Check the slug against `search_recipes`.              |\n| `invalid_input` | The arguments cannot produce a request.     | The message names the argument.                       |\n| `rate_limited`  | The site asked this client to slow down.    | Wait and ask again. The thing asked for still exists. |\n| `parse_failure` | A page arrived in a shape this cannot read. | Report it; the site may have changed.                 |\n| `network_error` | The request could not be completed.         | Try again.                                            |\n| `timeout`       | No answer arrived in time.                  | Try again, or raise `PQR_TIMEOUT_MS`.                 |\n\n## As a library\n\nThe reading layer is published on its own, with its pacing, its store and its\nerror vocabulary, and no protocol attached.\n\n```ts\nimport { PequerecetasClient } from \"mcp-pequerecetas/client\";\n\nconst client = new PequerecetasClient();\nconst read = await client.getRecipe(\"paella-de-marisco\");\n```\n\nBuilt with nothing, it takes its settings from the environment and sends its\ndiagnostics to stderr. `loadConfig` and `createLogger` come from the same entry\npoint for a caller who would rather set them in code:\n\n```ts\nimport { createLogger, loadConfig, PequerecetasClient } from \"mcp-pequerecetas/client\";\n\nconst client = new PequerecetasClient({\n  config: { ...loadConfig(), minIntervalMs: 5000 },\n  logger: createLogger(\"debug\"),\n});\n```\n\nEvery read returns `{ data, cached }`, and `cached` says whether the answer came\nfrom the store rather than from the site.\n\n## Pacing and attribution\n\nOne request at a time, three seconds apart, and the interval widens when the site\npushes back. The User-Agent carries the project's name, its version and an\naddress where a person can be reached.\n\nPequerecetas is free to read and pays for its own hosting. When you show a recipe\nto someone, credit the site and link the page it came from.\n\nThis server is not affiliated with Pequerecetas.\n\n## Privacy\n\nNothing is collected. The server reads `www.pequerecetas.com` and no other host,\nkeeps what it read in memory for fifteen minutes by default, writes nothing to\ndisk, and sends its diagnostics to stderr. It carries no credential, because the\nsite asks for none. See [PRIVACY.md](./PRIVACY.md).\n\n## Development\n\n```bash\nnpm install\nnpm run build:fixtures\nnpm test\nnpm run coverage\nnpm run check\n```\n\nThe corpus the suite reads is written by `scripts/build-fixtures.mjs` and holds\ninvented recipes, so no third-party content is stored here. A live suite runs\nbehind `PQR_LIVE=1`, one request per route.\n\n## Contributing\n\nIssues and pull requests are welcome. See [CONTRIBUTING.md](./CONTRIBUTING.md).\n\n## License\n\nMIT. See [LICENSE](./LICENSE).\n\n---\n\n<a name=\"mcp-pequerecetas-français\"></a>\n\n# mcp-pequerecetas (français)\n\n_[English version](#mcp-pequerecetas)_\n\n[Pequerecetas](https://www.pequerecetas.com) est un site espagnol de cuisine\nfamiliale. Il tient quelques milliers de recettes avec leurs ingrédients, leurs\nétapes et leurs photographies, et range chacune sous le régime auquel elle\nconvient, l'appareil qui la cuit, l'occasion pour laquelle on la fait et l'âge de\ncelui qui la mange, à partir de six mois.\n\nCe serveur relie un client de conversation à ce site. On peut chercher ses\nrecettes, en lire une avec ses quantités mises à l'échelle du nombre de personnes\nà table, lister les valeurs que publie chaque taxonomie, parcourir une taxonomie\npage par page, et mettre à l'échelle n'importe quelle liste d'ingrédients\nespagnole qu'on a déjà. Il ne demande ni clé d'API ni compte.\n\n## Installation\n\n**Installation en un clic**\n\n[![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=pequerecetas&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1wZXF1ZXJlY2V0YXMiXX0=)\n[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF?style=flat&logo=visualstudiocode&logoColor=white)](https://insiders.vscode.dev/redirect/mcp/install?name=pequerecetas&config=%7B%22name%22%3A%22pequerecetas%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mcp-pequerecetas%22%5D%7D)\n\n**Claude Code**\n\n```bash\nclaude mcp add pequerecetas -- npx -y mcp-pequerecetas\n```\n\n**Claude Desktop, Cursor, et tout client au format de configuration standard**\n\n```json\n{\n  \"mcpServers\": {\n    \"pequerecetas\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"mcp-pequerecetas\"]\n    }\n  }\n}\n```\n\nNode 24 ou plus récent est requis, et aucune variable d'environnement n'est à\ndéfinir.\n\n### Avec Docker\n\n```json\n{\n  \"mcpServers\": {\n    \"pequerecetas\": {\n      \"command\": \"docker\",\n      \"args\": [\"run\", \"-i\", \"--rm\", \"ghcr.io/smeet666/mcp-pequerecetas:1.0.1\"]\n    }\n  }\n}\n```\n\n`-i` garde stdin ouvert, où passe le protocole, et `-t` est laissé de côté parce\nqu'un TTY réécrit le flux. Le conteneur a besoin de joindre\n`www.pequerecetas.com` en HTTPS sortant, et de rien d'autre : aucun volume, aucun\nport, aucun identifiant.\n\n### Bundle, sans npm\n\nTélécharger `mcp-pequerecetas-1.0.1.mcpb` depuis\n[la dernière publication](https://github.com/smeet666/mcp-pequerecetas/releases/latest)\net l'ouvrir. Un client qui gère les bundles MCP l'installe seul, sans npm et sans\nfichier de configuration à modifier. Le bundle emporte ses dépendances, donc rien\nn'est téléchargé à l'installation.\n\n## Ce qu'on peut demander\n\n- « Búscame una receta de paella de marisco. »\n- « Lis-moi cette recette pour huit personnes. »\n- « Qu'est-ce que je peux cuisiner à la friteuse à air sur ce site ? »\n- « Montre-moi les purées qu'il range sous six mois. »\n- « Multiplie cette liste d'ingrédients espagnole par trois. »\n\nPequerecetas est écrit en espagnol et sa recherche compare les mots dont une page\nest faite, donc les recettes se trouvent en espagnol. Le chemin ordinaire va\nd'une recherche ou d'une taxonomie vers une recette : une ligne porte un `id`, et\n`get_recipe` prend cet id.\n\n## Les outils\n\n| Outil               | Ce qu'il fait                                                          |\n| ------------------- | ---------------------------------------------------------------------- |\n| `get_recipe`        | Lit une page de la section des recettes, mise à l'échelle sur demande. |\n| `search_recipes`    | Trouve des recettes par plat ou par ingrédient.                        |\n| `list_facets`       | Liste les valeurs que publie chaque taxonomie.                         |\n| `browse_recipes`    | Lit une taxonomie, page par page.                                      |\n| `scale_ingredients` | Met à l'échelle une liste d'ingrédients espagnole, sans requête.       |\n\n### `get_recipe`\n\nLit une page de la section des recettes, et met ses quantités à l'échelle quand\nun nombre de parts est donné.\n\n| Argument   | Type                       | Requis | Ce qu'il fait                               |\n| ---------- | -------------------------- | ------ | ------------------------------------------- |\n| `id`       | chaîne, 1 à 200 caractères | oui    | Le slug dans l'adresse d'une recette.       |\n| `servings` | entier, 1 à 1000           | non    | Met les quantités à l'échelle de ce nombre. |\n\n**En retour :** `kind`, qui vaut `recipe` ou `collection`. Le site publie les deux\nà ce genre d'adresse et les décrit pareillement, donc c'est ce qui les distingue :\nune collection est un article qui rassemble d'autres recettes, et elle revient\navec `headings` et `recipes`, les lignes qu'elle désigne, à la place des champs\nd'une recette.\n\nUne recette porte `source_shape`, qui vaut `structured` quand le bloc que la page\npublie pour les moteurs de recherche portait ses ingrédients, et `article` quand\nils ont été lus dans le corps de la page, où la plupart des recettes de ce site\nles gardent. Viennent ensuite `title`, `url`, `description`, `published_at`,\n`modified_at`, `prep_minutes`, `cook_minutes`, `total_minutes`, `categories`,\n`cuisines`, `keywords`, `author`, `author_url`, `rating`, `nutrition` et\n`images`, chacun `null` ou vide là où la page n'énonce rien. `yield` dit pour\ncombien la recette a été écrite et vers combien elle a été portée ; une page qui\nn'énonce aucun nombre de parts revient avec `factor` à 1 et une note qui le dit.\nChaque ligne d'`ingredients` porte `scaling`, qui vaut `scaled`, `rounded` ou\n`unscaled`, et `is_equipment`, qui marque une ligne nommant un ustensile plutôt\nque quelque chose qui se mange.\n\n### `search_recipes`\n\nCherche les recettes par plat ou par ingrédient.\n\n| Argument | Type                       | Requis | Ce qu'il fait                          |\n| -------- | -------------------------- | ------ | -------------------------------------- |\n| `query`  | chaîne, 1 à 120 caractères | oui    | Un plat ou un ingrédient, en espagnol. |\n| `limit`  | entier, 1 à 60             | non    | Lignes à rendre.                       |\n\n**En retour :** des lignes portant `id`, que prend `get_recipe`, `title`, `url` et\n`image_url`. À côté viennent `result_count` pour les lignes rendues et\n`total_available`, toujours `null` : le site ne publie aucun compte de ce qu'une\nrecherche a trouvé. Le site sert sa recherche sur une seule page et répond à une\ndemande de deuxième page par la première à l'identique, donc ce sont là toutes\nles lignes qu'il offre pour cette requête. Certaines lignes sont des articles qui\nrassemblent des recettes, ce que `get_recipe` rend comme une `collection`.\n\n### `list_facets`\n\nListe les valeurs par lesquelles le site parcourt ses recettes, lues dans le plan\nde site que chaque taxonomie publie.\n\n| Argument | Type                        | Requis | Ce qu'il fait                            |\n| -------- | --------------------------- | ------ | ---------------------------------------- |\n| `facet`  | chaîne, 1 caractère et plus | non    | Une taxonomie. Les huit quand il manque. |\n\nLes taxonomies sont `dieta`, `edad`, `ingrediente`, `ocasion`, `recetas-de`,\n`tecnica`, `tipo-de-cocina` et `tipo-plato` : le régime, l'âge de celui qui\nmange, l'ingrédient principal, l'occasion, le moment de la journée, l'appareil,\nla cuisine et le type de plat.\n\n**En retour :** `facets`, portant chacune `name`, `value_count` et `values`, dont\n`value` est le slug que prend `browse_recipes`. Les valeurs gardent l'ordre dans\nlequel le site les publie. Lire les huit coûte une requête par taxonomie. Une\ntaxonomie qui n'a pas pu être lue est nommée dans `notes` et laissée hors de\n`facets`, pour qu'une liste amputée d'une taxonomie ne se lise pas comme un site\nqui en aurait sept.\n\n### `browse_recipes`\n\nLit une page des recettes d'une taxonomie.\n\n| Argument | Type                        | Requis | Ce qu'il fait                                |\n| -------- | --------------------------- | ------ | -------------------------------------------- |\n| `facet`  | chaîne, 1 caractère et plus | oui    | La taxonomie à parcourir.                    |\n| `value`  | chaîne, 1 à 120 caractères  | oui    | Un slug de `list_facets`, comme `thermomix`. |\n| `page`   | entier, 1 à 200             | non    | La page à lire, la première par défaut.      |\n\n**En retour :** des lignes de la forme que rend `search_recipes`, avec\n`page_served` pour la page que le site a servie, `has_more` pour savoir si sa\npagination en offre une autre, et `total_available`, toujours `null` parce que le\nsite n'imprime aucun compte sur ces pages. Le site écrit ses propres slugs, donc\nun slug construit à la main atteint une page qu'il ne tient pas et revient en\n`not_found`. Les taxonomies ne se croisent pas : le site n'offre aucun moyen d'en\ndemander deux à la fois.\n\n### `scale_ingredients`\n\nMet à l'échelle une liste de lignes d'ingrédients espagnoles. Il ne joint aucun\nsite.\n\n| Argument        | Type                               | Requis | Ce qu'il fait                         |\n| --------------- | ---------------------------------- | ------ | ------------------------------------- |\n| `ingredients`   | tableau de 1 à 200 chaînes         | oui    | Les lignes à mettre à l'échelle.      |\n| `factor`        | nombre, supérieur à 0 jusqu'à 1000 | l'un   | Ce par quoi multiplier les quantités. |\n| `from_servings` | entier, 1 à 1000                   | l'un   | Pour combien la liste a été écrite.   |\n| `to_servings`   | entier, 1 à 1000                   | l'un   | Pour combien elle doit servir.        |\n\nDonner `factor`, ou `from_servings` et `to_servings` ensemble. Nommer les deux\nmanières à la fois est refusé, parce qu'elles peuvent demander deux choses\ndifférentes.\n\n**En retour :** chaque ligne avec `text` telle qu'elle se lit maintenant,\n`original` telle qu'elle a été donnée, `amount`, `amount_max`, `unit`, et\n`scaling`, qui porte l'honnêteté de la réponse : `scaled` quand l'arithmétique\nest tombée juste, `rounded` quand la valeur a bougé pour rester une quantité\nqu'une cuisine mesure, `unscaled` quand la ligne ne porte aucune quantité.\n`is_equipment` marque une ligne qui nomme un ustensile. À côté viennent\n`scaled_count`, `rounded_count` et `unscaled_count`. Rien n'est converti d'un\nsystème d'unités à un autre, et une mesure approximative comme une `pizca` garde\nla taille que lui donne le cuisinier.\n\n## Configuration\n\n| Variable                | Défaut     | Bornes                     | Ce qu'elle fait                                            |\n| ----------------------- | ---------- | -------------------------- | ---------------------------------------------------------- |\n| `PQR_USER_AGENT`        | non défini |                            | Préfixé au User-Agent du serveur.                          |\n| `PQR_MIN_INTERVAL_MS`   | `3000`     | 3000 à 60000               | Millisecondes entre deux requêtes.                         |\n| `PQR_TIMEOUT_MS`        | `20000`    | 1000 à 120000              | Durée maximale d'une requête.                              |\n| `PQR_MAX_RETRIES`       | `3`        | 0 à 8                      | Tentatives sur une requête sans réponse.                   |\n| `PQR_CACHE_TTL_MS`      | `900000`   | 0 à 86400000               | Durée de conservation d'une lecture. Zéro éteint le cache. |\n| `PQR_CACHE_MAX_ENTRIES` | `200`      | 1 à 5000                   | Lectures gardées à la fois.                                |\n| `PQR_LOG_LEVEL`         | `error`    | silent, error, info, debug | Ce qui part sur stderr.                                    |\n\nL'intervalle a un plancher de 3000 millisecondes. Une valeur en dessous est\nrefusée et le défaut s'applique, ce qui est dit sur stderr plutôt qu'appliqué en\nsilence.\n\n## Erreurs\n\n| Code            | Ce que ça veut dire                               | Le geste suivant                                           |\n| --------------- | ------------------------------------------------- | ---------------------------------------------------------- |\n| `not_found`     | Le site ne tient rien à cette adresse.            | Vérifier le slug avec `search_recipes`.                    |\n| `invalid_input` | Les arguments ne peuvent pas produire de requête. | Le message nomme l'argument.                               |\n| `rate_limited`  | Le site a demandé de ralentir.                    | Attendre et redemander. La chose demandée existe toujours. |\n| `parse_failure` | Une page est arrivée sous une forme illisible.    | Le signaler ; le site a pu changer.                        |\n| `network_error` | La requête n'a pas abouti.                        | Réessayer.                                                 |\n| `timeout`       | Aucune réponse n'est arrivée à temps.             | Réessayer, ou élargir `PQR_TIMEOUT_MS`.                    |\n\n## Comme bibliothèque\n\nLa couche de lecture est publiée seule, avec son rythme, son cache et son\nvocabulaire d'erreurs, sans protocole attaché.\n\n```ts\nimport { PequerecetasClient } from \"mcp-pequerecetas/client\";\n\nconst client = new PequerecetasClient();\nconst read = await client.getRecipe(\"paella-de-marisco\");\n```\n\nConstruit sans rien, il prend ses réglages dans l'environnement et envoie ses\ndiagnostics sur stderr. `loadConfig` et `createLogger` viennent du même point\nd'entrée pour qui préfère les fixer dans le code :\n\n```ts\nimport { createLogger, loadConfig, PequerecetasClient } from \"mcp-pequerecetas/client\";\n\nconst client = new PequerecetasClient({\n  config: { ...loadConfig(), minIntervalMs: 5000 },\n  logger: createLogger(\"debug\"),\n});\n```\n\nToute lecture rend `{ data, cached }`, et `cached` dit si la réponse vient du\ncache plutôt que du site.\n\n## Rythme et attribution\n\nUne requête à la fois, trois secondes d'écart, et l'intervalle s'élargit quand le\nsite demande de la place. Le User-Agent porte le nom du projet, sa version et une\nadresse où joindre une personne.\n\nPequerecetas se lit gratuitement et paie son hébergement. Quand on montre une\nrecette à quelqu'un, on crédite le site et on lie la page d'où elle vient.\n\nCe serveur n'est pas affilié à Pequerecetas.\n\n## Confidentialité\n\nRien n'est collecté. Le serveur lit `www.pequerecetas.com` et aucun autre hôte,\ngarde ce qu'il a lu en mémoire quinze minutes par défaut, n'écrit rien sur\ndisque, et envoie ses diagnostics sur stderr. Il ne porte aucun identifiant,\npuisque le site n'en demande aucun. Voir [PRIVACY.md](./PRIVACY.md).\n\n## Développement\n\n```bash\nnpm install\nnpm run build:fixtures\nnpm test\nnpm run coverage\nnpm run check\n```\n\nLe corpus que lit la suite est écrit par `scripts/build-fixtures.mjs` et tient\ndes recettes inventées, donc aucun contenu tiers n'est stocké ici. Une suite en\ndirect tourne derrière `PQR_LIVE=1`, une requête par route.\n\n## Contribuer\n\nLes issues et les pull requests sont bienvenues. Voir\n[CONTRIBUTING.md](./CONTRIBUTING.md).\n\n## Licence\n\nMIT. Voir [LICENSE](./LICENSE).\n",
  "bytes": 30234,
  "sha": "94170c5097016696f2ee452ea16ad1adc2811a3ce545ed0c6a588461d076a2bd",
  "repo_slug": "smeet666/mcp-pequerecetas",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_smeet666_mcp_pequerecetas_08f81b17/readme"
}