mcp-recipes 3.0.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -6,6 +6,7 @@
6
6
  [![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-6E56CF)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.smeet666/mcp-recipes)
7
7
  [![Glama](https://glama.ai/mcp/servers/smeet666/mcp-recipes/badges/score.svg)](https://glama.ai/mcp/servers/smeet666/mcp-recipes)
8
8
  [![M8ven](https://m8ven.ai/badge/mcp/smeet666-mcp-recipes-1o0x5l?variant=verified)](https://m8ven.ai/mcp/smeet666-mcp-recipes-1o0x5l)
9
+ [![LobeHub](https://lobehub.com/badge/mcp/smeet666-mcp-recipes)](https://lobehub.com/mcp/smeet666-mcp-recipes)
9
10
  [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=recipes&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1yZWNpcGVzIl19)
10
11
  [![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=recipes&config=%7B%22name%22%3A%22recipes%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mcp-recipes%22%5D%7D)
11
12
 
@@ -15,17 +16,15 @@ a serving is, and a wiki cookbook in English, with equipment lists and prose the
15
16
  first has no field for. Asking a question of one of them answers about one of
16
17
  them.
17
18
 
18
- This server reads five at once. Three publish in French:
19
- [Marmiton](https://www.marmiton.org), where home cooks publish,
20
- [Ptitchef](https://www.ptitchef.com), which files its recipes under a tree of
21
- ingredients, and [Supertoinette](https://www.supertoinette.com), which prints a
22
- resting time of its own. Two publish in English: the
23
- [Wikibooks Cookbook](https://en.wikibooks.org/wiki/Cookbook:Table_of_Contents),
24
- written and maintained in the open, and
25
- [BBC Good Food](https://www.bbcgoodfood.com), which groups an ingredient list
26
- under headings. You can search them all with one question, read a recipe from any
27
- of them in one shape, put several versions of the same dish side by side, and
28
- rescale any ingredient list. It needs no API key and no account.
19
+ This server reads six. Three publish in French,
20
+ [Marmiton](https://www.marmiton.org), [Ptitchef](https://www.ptitchef.com) and
21
+ [Supertoinette](https://www.supertoinette.com); two in English, the
22
+ [Wikibooks Cookbook](https://en.wikibooks.org/wiki/Cookbook:Table_of_Contents)
23
+ and [BBC Good Food](https://www.bbcgoodfood.com); and one in Spanish,
24
+ [Pequerecetas](https://www.pequerecetas.com). You can search them all with
25
+ one question, read a recipe from any of them in one shape, put several versions
26
+ of the same dish side by side, and rescale any ingredient list. It needs no API
27
+ key and no account.
29
28
 
30
29
  _[Version française](#mcp-recipes-français)_
31
30
 
@@ -66,7 +65,7 @@ Node 24 or later is required, and no environment variable has to be set.
66
65
  "mcpServers": {
67
66
  "recipes": {
68
67
  "command": "docker",
69
- "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-recipes:3.0.0"]
68
+ "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-recipes:4.0.0"]
70
69
  }
71
70
  }
72
71
  }
@@ -75,12 +74,12 @@ Node 24 or later is required, and no environment variable has to be set.
75
74
  `-i` keeps stdin open, which is where the protocol travels, and `-t` is left out
76
75
  because a TTY rewrites the stream. The container needs outbound HTTPS to
77
76
  `www.marmiton.org`, `api.wikimedia.org`, `www.ptitchef.com`,
78
- `www.bbcgoodfood.com` and `www.supertoinette.com`, and nothing else:
79
- no volume, no port, no credential.
77
+ `www.bbcgoodfood.com`, `www.supertoinette.com` and `www.pequerecetas.com`, and
78
+ nothing else: no volume, no port, no credential.
80
79
 
81
80
  ### Bundle, without npm
82
81
 
83
- Download `mcp-recipes-3.0.0.mcpb` from
82
+ Download `mcp-recipes-4.0.0.mcpb` from
84
83
  [the latest release](https://github.com/smeet666/mcp-recipes/releases/latest) and
85
84
  open it. A client that supports MCP bundles installs it on its own, with no npm
86
85
  and no configuration file to edit. The bundle carries its dependencies, so
@@ -106,11 +105,21 @@ its source, and `get_recipe` takes it.
106
105
  | `ptitchef` | `www.ptitchef.com` | French |
107
106
  | `goodfood` | `www.bbcgoodfood.com` | English |
108
107
  | `supertoinette` | `www.supertoinette.com` | French |
108
+ | `pequerecetas` | `www.pequerecetas.com` | Spanish |
109
109
 
110
110
  A row's `id` names its source, so an identifier read from one answer goes back to
111
111
  the right site. **Counts are never added across sources**, and a source that
112
112
  failed is reported as having failed rather than as having found nothing.
113
113
 
114
+ Each site is read at its own pace: two of them ask for three seconds between
115
+ requests, and a setting posted for all of them can only make this server more
116
+ patient than the slowest asks for.
117
+
118
+ Two of these sites file something other than a recipe at the address a recipe
119
+ lives at. The Wikibooks Cookbook keeps pages about an ingredient beside the
120
+ recipes using it, and Pequerecetas publishes articles that gather recipes. A
121
+ search says so, and `get_recipe` says what it read off the page.
122
+
114
123
  ## Tools
115
124
 
116
125
  | Tool | What it does |
@@ -136,8 +145,10 @@ Searches every source with one question.
136
145
  `image_url`; and an `excerpt` where the source offers one. `per_source` gives one
137
146
  report per site with its `status`, reading `answered` or `failed`, the `count` it
138
147
  contributed, and its `reported_total` alongside `reported_total_means`, which
139
- says what that number counts on that site. `order` says in words how the list was
140
- built.
148
+ says what that number counts on that site. `names_the_dish` says how many of that
149
+ site's rows carry the dish in their title, out of `count`: a search index answers
150
+ the words it is handed, so a site can offer rows and none of them be the dish.
151
+ `order` says in words how the list was built.
141
152
 
142
153
  ### `get_recipe`
143
154
 
@@ -149,17 +160,26 @@ Reads one recipe from any source, in one shape.
149
160
  | `servings` | integer, 1 to 500 | no | Rescale the ingredients to this many servings. |
150
161
  | `sections` | array of `ingredients`, `steps`, `times`, `nutrition`, `tips`, `equipment`, default `["ingredients", "steps"]` | no | Which parts to return. |
151
162
  | `max_steps` | integer, 1 to 100, default `20` | no | Steps to serve. |
163
+ | `max_gathered` | integer, 1 to 500, default `30` | no | Recipes and headings to return from an address that gathers recipes. |
152
164
  | `max_step_chars` | integer, 80 to 4000, default `600` | no | Characters kept per step. |
153
165
 
154
- **In return:** the recipe in the shape every source is rendered into, whichever
155
- published it: its title, its address, its ingredients with each line's `scaling`,
166
+ **In return:** `kind` says what the address held. A `recipe` answer carries
167
+ `recipe` and no `collection`; a `collection` answer carries `collection` and no
168
+ `recipe`, and is an article gathering other recipes, with the `headings` it is
169
+ built from and the `recipes` it points at, each of them readable with
170
+ `get_recipe`.
171
+
172
+ A recipe comes in the shape every source is rendered into, whichever
173
+ published it: its title, its address, its ingredients with each line's `scaling`
174
+ and `is_equipment`,
156
175
  its steps, and the sections asked for. A field one source publishes and another
157
176
  has no notion of comes back absent rather than invented. `rest_minutes` carries a
158
177
  resting time from a source that prints one apart, and is in no other time here.
159
178
  `steps_as_one_block` says when a source published its method as one block of
160
179
  prose rather than as steps. `withheld` names a part a source keeps for its
161
180
  subscribers, which is a part the page has rather than a part that could not be
162
- read. Raise `max_step_chars` when a step was cut mid-sentence.
181
+ read. `scaling_summary` counts the lines four ways, and the four add up to the
182
+ list. Raise `max_step_chars` when a step was cut mid-sentence.
163
183
 
164
184
  ### `compare_recipes`
165
185
 
@@ -181,18 +201,18 @@ search does.
181
201
 
182
202
  ### `scale_ingredients`
183
203
 
184
- Rescales any ingredient list, with no request to either site.
204
+ Rescales any ingredient list, with no request to any site.
185
205
 
186
- | Argument | Type | Required | What it does |
187
- | --------------- | ------------------------------------ | ---------- | ------------------------------------------ |
188
- | `ingredients` | array of 1 to 200 lines | yes | The lines to rescale. |
189
- | `factor` | number, up to 1000 | one of two | The multiplier to apply. |
190
- | `from_servings` | integer, 1 to 500 | one of two | How many servings the list is written for. |
191
- | `to_servings` | integer, 1 to 500 | one of two | How many servings are wanted. |
192
- | `language` | `auto`, `fr` or `en`, default `auto` | no | How each line is read. |
206
+ | Argument | Type | Required | What it does |
207
+ | --------------- | ------------------------------------------ | ---------- | ------------------------------------------ |
208
+ | `ingredients` | array of 1 to 200 lines | yes | The lines to rescale. |
209
+ | `factor` | number, up to 1000 | one of two | The multiplier to apply. |
210
+ | `from_servings` | integer, 1 to 500 | one of two | How many servings the list is written for. |
211
+ | `to_servings` | integer, 1 to 500 | one of two | How many servings are wanted. |
212
+ | `language` | `auto`, `fr`, `en` or `es`, default `auto` | no | How each line is read. |
193
213
 
194
214
  Pass `factor`, or the `from_servings` and `to_servings` pair. `auto` reads each
195
- line on its own, which is what a list holding both languages needs; naming a
215
+ line on its own, which is what a list holding more than one language needs; naming a
196
216
  language reads every line that way.
197
217
 
198
218
  **In return:** the rescaled lines in the shape `get_recipe` returns, each with
@@ -219,22 +239,22 @@ say they were recomputed when you show them.
219
239
  Every answer accounts for each source separately. A site that failed, one nobody
220
240
  asked, and one that answered with nothing are three different things, and they
221
241
  are reported as three. A total stays beside the source that published it, with
222
- what that source counts when it says it: one site counts a whole category and the
223
- other counts the rows it served.
242
+ what that source counts when it says it: one site counts a whole category, another
243
+ counts the rows it served, and a third publishes no total at all.
224
244
 
225
245
  ## Configuration
226
246
 
227
247
  Every variable is optional. Set them in the `env` block of your client config.
228
248
 
229
- | Variable | Default | What it does |
230
- | --------------------------- | -------------------- | ------------------------------------------------------------------------------------ |
231
- | `RECIPES_USER_AGENT` | the project identity | Names your application to both sites, with an address where a person can be reached. |
232
- | `RECIPES_MIN_INTERVAL_MS` | `1000` | Gap between two requests to one site, from 500 to 60000. |
233
- | `RECIPES_TIMEOUT_MS` | `20000` | Deadline for one request, from 1000 to 120000. |
234
- | `RECIPES_MAX_RETRIES` | `3` | Attempts after a transient failure, from 0 to 8. |
235
- | `RECIPES_CACHE_TTL_MS` | `900000` | How long an answer stays in memory, from 0 to 86400000. |
236
- | `RECIPES_CACHE_MAX_ENTRIES` | `200` | Answers held in memory at once, from 1 to 5000. |
237
- | `RECIPES_LOG_LEVEL` | `error` | `silent`, `error`, `info` or `debug`, written to stderr. |
249
+ | Variable | Default | What it does |
250
+ | --------------------------- | -------------------- | ----------------------------------------------------------------------------------- |
251
+ | `RECIPES_USER_AGENT` | the project identity | Names your application to the sites, with an address where a person can be reached. |
252
+ | `RECIPES_MIN_INTERVAL_MS` | `1000` | Gap between two requests to one site, from 500 to 60000. |
253
+ | `RECIPES_TIMEOUT_MS` | `20000` | Deadline for one request, from 1000 to 120000. |
254
+ | `RECIPES_MAX_RETRIES` | `3` | Attempts after a transient failure, from 0 to 8. |
255
+ | `RECIPES_CACHE_TTL_MS` | `900000` | How long an answer stays in memory, from 0 to 86400000. |
256
+ | `RECIPES_CACHE_MAX_ENTRIES` | `200` | Answers held in memory at once, from 1 to 5000. |
257
+ | `RECIPES_LOG_LEVEL` | `error` | `silent`, `error`, `info` or `debug`, written to stderr. |
238
258
 
239
259
  A value outside its range falls back to the default, and the reason is written to
240
260
  stderr.
@@ -258,25 +278,47 @@ so one silent site never hides the other.
258
278
 
259
279
  ## As a library
260
280
 
261
- The layer reading the two sites is published on its own, with its pacing, its
262
- cache and its errors, and with no protocol attached.
281
+ The layer reading the sites is published on its own, with its pacing, its cache
282
+ and its errors, and with no protocol attached.
263
283
 
264
284
  ```ts
265
285
  import { RecipesClient } from "mcp-recipes/client";
266
286
 
267
287
  const client = new RecipesClient();
268
- const read = await client.search({ query: "carbonara", limitPerSource: 3 });
269
- console.log(read.data.results.length);
288
+ const { rows, reports } = await client.searchRecipes("carbonara", 3);
289
+ console.log(
290
+ rows.length,
291
+ reports.map((report) => report.status),
292
+ );
293
+
294
+ const { recipe } = await client.getRecipe(rows[0].id);
270
295
  ```
271
296
 
272
- Each read answers `{ data, cached }`, and throws an error carrying one of the six
273
- codes. Each site keeps its own pace, and the floor holds here as well.
297
+ `searchRecipes(query, limitPerSource, sources?, options?)` answers
298
+ `{ rows, reports }`: one report per source, saying whether it answered and what
299
+ its own count measured, so a source that failed is never read as a source that
300
+ holds nothing. `getRecipe(id)` answers `{ recipe, cached, read }`, and throws an
301
+ error carrying one of the six codes. `client.profiles` lists the sources the
302
+ build registers.
303
+
304
+ The scaler is published separately at `mcp-recipes/scale`, and works offline on
305
+ any list:
306
+
307
+ ```ts
308
+ import { scaleIngredients } from "mcp-recipes/scale";
309
+
310
+ scaleIngredients(["200 g de harina", "4 oeufs", "1 cup milk"], { factor: 2 });
311
+ ```
312
+
313
+ Each site keeps its own pace, and the floors hold here as well.
274
314
 
275
315
  ## Pacing and attribution
276
316
 
277
317
  Each site is paced on its own, one request at a time with at least a second
278
318
  between two, and the floor of half a second holds however the server is
279
- configured. Asking every site at once therefore costs each of them one request,
319
+ configured. Two of the sites ask for more, three seconds between two requests,
320
+ and they get it: a setting posted for every source can raise a site's spacing
321
+ and never lower it. Asking every site at once therefore costs each of them one request,
280
322
  never two. The `User-Agent` always ends with the project identity and an address
281
323
  where a person can be reached.
282
324
 
@@ -284,7 +326,7 @@ Every row carries the address of the recipe's own page and the name of the site
284
326
  that published it. The Cookbook pages are published under
285
327
  [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/), which asks that
286
328
  what is built on them be shared under the same licence. Marmiton, Ptitchef, BBC
287
- Good Food and Supertoinette state no terms on a recipe page, and their recipes
329
+ Good Food, Supertoinette and Pequerecetas state no terms on a recipe page, and their recipes
288
330
  belong to those sites and to the cooks who wrote them. Silence is not a grant, so
289
331
  credit the site and link the page you took a recipe from.
290
332
 
@@ -305,7 +347,8 @@ sites it reads.
305
347
 
306
348
  This server collects nothing about you and sends nothing to its author. It runs
307
349
  on your machine, contacts `www.marmiton.org`, `api.wikimedia.org`,
308
- `www.ptitchef.com`, `www.bbcgoodfood.com` and `www.supertoinette.com` and nothing
350
+ `www.ptitchef.com`, `www.bbcgoodfood.com`, `www.supertoinette.com` and
351
+ `www.pequerecetas.com` and nothing
309
352
  else, holds its answers in memory while it runs,
310
353
  and writes nothing to disk. [PRIVACY.md](PRIVACY.md) states what a request
311
354
  carries and which settings change any of it.
@@ -349,18 +392,15 @@ qu'est une part, et un wiki de cuisine en anglais, avec des listes de matériel
349
392
  une prose pour lesquelles le premier n'a aucun champ. Poser une question à l'un
350
393
  d'eux répond au sujet de l'un d'eux.
351
394
 
352
- Ce serveur en lit cinq à la fois. Trois publient en français :
353
- [Marmiton](https://www.marmiton.org), où des cuisiniers publient,
354
- [Ptitchef](https://www.ptitchef.com), qui range ses recettes sous un arbre
355
- d'ingrédients, et [Supertoinette](https://www.supertoinette.com), qui imprime un
356
- temps de repos à part. Deux publient en anglais : le
357
- [Cookbook des Wikibooks](https://en.wikibooks.org/wiki/Cookbook:Table_of_Contents),
358
- écrit et entretenu à découvert, et
359
- [BBC Good Food](https://www.bbcgoodfood.com), qui groupe une liste d'ingrédients
360
- sous des intertitres. On peut chercher dans les cinq avec une seule question,
361
- lire une recette de n'importe lequel sous une seule forme, mettre plusieurs
362
- versions d'un même plat côte à côte, et adapter n'importe quelle liste
363
- d'ingrédients. Aucune clé d'API, aucun compte.
395
+ Ce serveur en lit six. Trois publient en français,
396
+ [Marmiton](https://www.marmiton.org), [Ptitchef](https://www.ptitchef.com) et
397
+ [Supertoinette](https://www.supertoinette.com) ; deux en anglais, le
398
+ [Cookbook des Wikibooks](https://en.wikibooks.org/wiki/Cookbook:Table_of_Contents)
399
+ et [BBC Good Food](https://www.bbcgoodfood.com) ; un en espagnol,
400
+ [Pequerecetas](https://www.pequerecetas.com). On peut chercher dans les six
401
+ avec une seule question, lire une recette de n'importe lequel sous une seule
402
+ forme, mettre plusieurs versions d'un même plat côte à côte, et adapter
403
+ n'importe quelle liste d'ingrédients. Aucune clé d'API, aucun compte.
364
404
 
365
405
  ## Installation
366
406
 
@@ -398,7 +438,7 @@ renseigner.
398
438
  "mcpServers": {
399
439
  "recipes": {
400
440
  "command": "docker",
401
- "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-recipes:3.0.0"]
441
+ "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-recipes:4.0.0"]
402
442
  }
403
443
  }
404
444
  }
@@ -407,12 +447,12 @@ renseigner.
407
447
  `-i` garde l'entrée standard ouverte, qui est le canal du protocole, et `-t` est
408
448
  omis parce qu'un TTY réécrit le flux. Le conteneur a besoin d'un accès HTTPS
409
449
  sortant vers `www.marmiton.org`, `api.wikimedia.org`, `www.ptitchef.com`,
410
- `www.bbcgoodfood.com` et `www.supertoinette.com`, et de
450
+ `www.bbcgoodfood.com`, `www.supertoinette.com` et `www.pequerecetas.com`, et de
411
451
  rien d'autre : aucun volume, aucun port, aucun identifiant.
412
452
 
413
453
  ### Bundle, sans npm
414
454
 
415
- Téléchargez `mcp-recipes-3.0.0.mcpb` depuis
455
+ Téléchargez `mcp-recipes-4.0.0.mcpb` depuis
416
456
  [la dernière publication](https://github.com/smeet666/mcp-recipes/releases/latest)
417
457
  et ouvrez-le. Un client qui gère les bundles MCP l'installe seul, sans npm et
418
458
  sans fichier de configuration à modifier. Le bundle emporte ses dépendances, donc
@@ -438,20 +478,31 @@ qui nomme sa source, et `get_recipe` le reprend.
438
478
  | `ptitchef` | `www.ptitchef.com` | français |
439
479
  | `goodfood` | `www.bbcgoodfood.com` | anglais |
440
480
  | `supertoinette` | `www.supertoinette.com` | français |
481
+ | `pequerecetas` | `www.pequerecetas.com` | espagnol |
441
482
 
442
483
  L'`id` d'une ligne nomme sa source, donc un identifiant lu dans une réponse
443
484
  retourne vers le bon site. **Les comptes ne sont jamais additionnés entre
444
485
  sources**, et une source qui a échoué est rapportée comme ayant échoué plutôt que
445
486
  comme n'ayant rien trouvé.
446
487
 
488
+ Chaque site est lu à son propre rythme : deux d'entre eux demandent trois
489
+ secondes entre deux requêtes, et un réglage posé pour tous ne peut que rendre ce
490
+ serveur plus patient que ce que le plus lent demande.
491
+
492
+ Deux de ces sites rangent autre chose qu'une recette à l'adresse où vit une
493
+ recette. Le Cookbook des Wikibooks garde des pages sur un ingrédient à côté des
494
+ recettes qui l'emploient, et Pequerecetas publie des articles qui rassemblent
495
+ des recettes. Une recherche le dit, et `get_recipe` dit ce qu'il a lu sur la
496
+ page.
497
+
447
498
  ## Les outils
448
499
 
449
- | Outil | Ce qu'il fait |
450
- | ------------------- | ---------------------------------------------------------- |
451
- | `search_recipes` | Cherche dans toutes les sources avec une seule question. |
452
- | `get_recipe` | Lit une recette de l'une ou l'autre, sous une seule forme. |
453
- | `compare_recipes` | Met plusieurs versions d'un même plat côte à côte. |
454
- | `scale_ingredients` | Adapte n'importe quelle liste d'ingrédients, sans requête. |
500
+ | Outil | Ce qu'il fait |
501
+ | ------------------- | ----------------------------------------------------------------- |
502
+ | `search_recipes` | Cherche dans toutes les sources avec une seule question. |
503
+ | `get_recipe` | Lit une recette de n'importe quelle source, sous une seule forme. |
504
+ | `compare_recipes` | Met plusieurs versions d'un même plat côte à côte. |
505
+ | `scale_ingredients` | Adapte n'importe quelle liste d'ingrédients, sans requête. |
455
506
 
456
507
  ### `search_recipes`
457
508
 
@@ -469,8 +520,11 @@ Cherche dans toutes les sources avec une seule question.
469
520
  `url` ; `image_url` ; et un `excerpt` là où la source en propose un.
470
521
  `per_source` donne un rapport par site avec son `status`, valant `answered` ou
471
522
  `failed`, le `count` qu'il a fourni, et son `reported_total` accompagné de
472
- `reported_total_means`, qui dit ce que ce nombre compte sur ce site. `order` dit
473
- en mots comment la liste a été bâtie.
523
+ `reported_total_means`, qui dit ce que ce nombre compte sur ce site.
524
+ `names_the_dish` dit combien des lignes de ce site portent le plat dans leur
525
+ titre, sur `count` : un index de recherche répond aux mots qu'on lui tend, donc
526
+ un site peut rendre des lignes dont aucune n'est le plat. `order` dit en mots
527
+ comment la liste a été bâtie.
474
528
 
475
529
  ### `get_recipe`
476
530
 
@@ -481,17 +535,26 @@ Lit une recette de n'importe quelle source, sous une seule forme.
481
535
  | `id` | chaîne, 1 à 500 caractères | oui | L'identifiant d'une ligne, tel que `marmiton:44078`. Deux sources adressent une recette par un nombre nu : écrivez l'id avec sa source. |
482
536
  | `servings` | entier, 1 à 500 | non | Adapte les ingrédients à ce nombre de parts. |
483
537
  | `sections` | tableau de `ingredients`, `steps`, `times`, `nutrition`, `tips`, `equipment`, défaut `["ingredients", "steps"]` | non | Les parties à rendre. |
538
+ | `max_gathered` | entier, 1 à 500, défaut `30` | non | Recettes et intertitres rendus pour une adresse qui rassemble des recettes. |
484
539
  | `max_steps` | entier, 1 à 100, défaut `20` | non | Étapes à servir. |
485
540
  | `max_step_chars` | entier, 80 à 4000, défaut `600` | non | Caractères gardés par étape. |
486
541
 
487
- **En retour :** la recette dans la forme où toutes les sources sont rendues, quelle
542
+ **En retour :** `kind` dit ce que l'adresse portait. Une réponse `recipe` porte
543
+ `recipe` et pas de `collection` ; une réponse `collection` porte `collection` et
544
+ pas de `recipe`, et c'est un article rassemblant d'autres recettes, avec les
545
+ `headings` dont il est bâti et les `recipes` vers lesquelles il pointe, chacune
546
+ lisible par `get_recipe`.
547
+
548
+ Une recette vient dans la forme où toutes les sources sont rendues, quelle
488
549
  que soit celle qui l'a publiée : son titre, son adresse, ses ingrédients avec le
489
- `scaling` de chaque ligne, ses étapes, et les parties demandées. Un champ qu'une
550
+ `scaling` et l'`is_equipment` de chaque ligne, ses étapes, et les parties
551
+ demandées. Un champ qu'une
490
552
  source publie et dont une autre n'a pas la notion revient absent plutôt
491
553
  qu'inventé. `rest_minutes` porte le temps de repos d'une source qui l'imprime à
492
554
  part, et il n'entre dans aucun autre temps rendu ici. `steps_as_one_block` dit
493
555
  quand une source a publié sa méthode d'un seul bloc de prose plutôt qu'en étapes.
494
- `withheld` nomme la partie qu'une source réserve à ses abonnés, qui est une
556
+ `scaling_summary` compte les lignes de quatre façons, et les quatre font le
557
+ total de la liste. `withheld` nomme la partie qu'une source réserve à ses abonnés, qui est une
495
558
  partie que la page porte et non une partie illisible. Augmentez `max_step_chars`
496
559
  quand une étape a été coupée au milieu d'une phrase.
497
560
 
@@ -515,22 +578,24 @@ fait une recherche.
515
578
 
516
579
  ### `scale_ingredients`
517
580
 
518
- Adapte n'importe quelle liste d'ingrédients, sans requête à l'un ou l'autre site.
581
+ Adapte n'importe quelle liste d'ingrédients, sans requête à aucun site.
519
582
 
520
- | Argument | Type | Requis | Ce qu'il fait |
521
- | --------------- | ----------------------------------- | ------------- | ----------------------------------------- |
522
- | `ingredients` | tableau de 1 à 200 lignes | oui | Les lignes à adapter. |
523
- | `factor` | nombre, jusqu'à 1000 | l'un des deux | Le multiplicateur à appliquer. |
524
- | `from_servings` | entier, 1 à 500 | l'un des deux | Le nombre de parts de la liste d'origine. |
525
- | `to_servings` | entier, 1 à 500 | l'un des deux | Le nombre de parts voulu. |
526
- | `language` | `auto`, `fr` ou `en`, défaut `auto` | non | Comment chaque ligne est lue. |
583
+ | Argument | Type | Requis | Ce qu'il fait |
584
+ | --------------- | ----------------------------------------- | ------------- | ----------------------------------------- |
585
+ | `ingredients` | tableau de 1 à 200 lignes | oui | Les lignes à adapter. |
586
+ | `factor` | nombre, jusqu'à 1000 | l'un des deux | Le multiplicateur à appliquer. |
587
+ | `from_servings` | entier, 1 à 500 | l'un des deux | Le nombre de parts de la liste d'origine. |
588
+ | `to_servings` | entier, 1 à 500 | l'un des deux | Le nombre de parts voulu. |
589
+ | `language` | `auto`, `fr`, `en` ou `es`, défaut `auto` | non | Comment chaque ligne est lue. |
527
590
 
528
591
  Passez `factor`, ou le couple `from_servings` et `to_servings`. `auto` lit chaque
529
- ligne pour elle-même, ce dont a besoin une liste portant les deux langues ;
592
+ ligne pour elle-même, ce dont a besoin une liste portant plusieurs langues ;
530
593
  nommer une langue lit toutes les lignes ainsi.
531
594
 
532
595
  **En retour :** les lignes adaptées dans la forme que rend `get_recipe`, chacune
533
- avec son `scaling`.
596
+ avec son `scaling` et son `is_equipment`, vrai pour une ligne qui nomme un outil
597
+ et qu'on laisse telle quelle. `scaled_count`, `rounded_count`, `unscaled_count`
598
+ et `equipment_count` font le total des lignes envoyées.
534
599
 
535
600
  ## L'adaptation des quantités
536
601
 
@@ -554,22 +619,23 @@ Chaque réponse rend compte de chaque source séparément. Un site qui a échou
554
619
  que personne n'a interrogé et un qui a répondu vide sont trois choses
555
620
  différentes, et elles sont rapportées comme trois. Un total reste à côté de la
556
621
  source qui l'a publié, avec ce que cette source compte en le disant : l'un compte
557
- une catégorie entière et l'autre compte les lignes qu'il a servies.
622
+ une catégorie entière, un autre compte les lignes qu'il a servies, et un
623
+ troisième ne publie aucun total.
558
624
 
559
625
  ## Configuration
560
626
 
561
627
  Chaque variable est facultative. Elles se posent dans le bloc `env` de la
562
628
  configuration du client.
563
629
 
564
- | Variable | Défaut | Ce qu'elle fait |
565
- | --------------------------- | -------------------- | ---------------------------------------------------------------------------------------- |
566
- | `RECIPES_USER_AGENT` | l'identité du projet | Nomme votre application auprès des deux sites, avec une adresse où joindre une personne. |
567
- | `RECIPES_MIN_INTERVAL_MS` | `1000` | Écart entre deux requêtes vers un même site, de 500 à 60000. |
568
- | `RECIPES_TIMEOUT_MS` | `20000` | Délai d'une requête, de 1000 à 120000. |
569
- | `RECIPES_MAX_RETRIES` | `3` | Tentatives après un échec passager, de 0 à 8. |
570
- | `RECIPES_CACHE_TTL_MS` | `900000` | Durée pendant laquelle une réponse reste en mémoire, de 0 à 86400000. |
571
- | `RECIPES_CACHE_MAX_ENTRIES` | `200` | Réponses gardées en mémoire à la fois, de 1 à 5000. |
572
- | `RECIPES_LOG_LEVEL` | `error` | `silent`, `error`, `info` ou `debug`, écrit sur la sortie d'erreur. |
630
+ | Variable | Défaut | Ce qu'elle fait |
631
+ | --------------------------- | -------------------- | ----------------------------------------------------------------------------------- |
632
+ | `RECIPES_USER_AGENT` | l'identité du projet | Nomme votre application auprès des sites, avec une adresse où joindre une personne. |
633
+ | `RECIPES_MIN_INTERVAL_MS` | `1000` | Écart entre deux requêtes vers un même site, de 500 à 60000. |
634
+ | `RECIPES_TIMEOUT_MS` | `20000` | Délai d'une requête, de 1000 à 120000. |
635
+ | `RECIPES_MAX_RETRIES` | `3` | Tentatives après un échec passager, de 0 à 8. |
636
+ | `RECIPES_CACHE_TTL_MS` | `900000` | Durée pendant laquelle une réponse reste en mémoire, de 0 à 86400000. |
637
+ | `RECIPES_CACHE_MAX_ENTRIES` | `200` | Réponses gardées en mémoire à la fois, de 1 à 5000. |
638
+ | `RECIPES_LOG_LEVEL` | `error` | `silent`, `error`, `info` ou `debug`, écrit sur la sortie d'erreur. |
573
639
 
574
640
  Une valeur hors de sa plage retombe sur le défaut, et la raison est écrite sur la
575
641
  sortie d'erreur.
@@ -593,25 +659,47 @@ toute la réponse, donc un site silencieux n'en cache jamais un autre.
593
659
 
594
660
  ## Comme bibliothèque
595
661
 
596
- La couche qui lit les deux sites est publiée seule, avec son rythme, son cache et
662
+ La couche qui lit les sites est publiée seule, avec son rythme, son cache et
597
663
  ses erreurs, sans protocole attaché.
598
664
 
599
665
  ```ts
600
666
  import { RecipesClient } from "mcp-recipes/client";
601
667
 
602
668
  const client = new RecipesClient();
603
- const read = await client.search({ query: "carbonara", limitPerSource: 3 });
604
- console.log(read.data.results.length);
669
+ const { rows, reports } = await client.searchRecipes("carbonara", 3);
670
+ console.log(
671
+ rows.length,
672
+ reports.map((report) => report.status),
673
+ );
674
+
675
+ const { recipe } = await client.getRecipe(rows[0].id);
676
+ ```
677
+
678
+ `searchRecipes(query, limitPerSource, sources?, options?)` répond
679
+ `{ rows, reports }` : un rapport par source, disant si elle a répondu et ce que
680
+ son propre compte mesure, pour qu'une source en échec ne se lise jamais comme une
681
+ source qui ne détient rien. `getRecipe(id)` répond `{ recipe, cached, read }`, et
682
+ lève une erreur portant un des six codes. `client.profiles` énumère les sources
683
+ que cette construction enregistre.
684
+
685
+ La mise à l'échelle est publiée à part, sous `mcp-recipes/scale`, et travaille
686
+ hors ligne sur n'importe quelle liste :
687
+
688
+ ```ts
689
+ import { scaleIngredients } from "mcp-recipes/scale";
690
+
691
+ scaleIngredients(["200 g de harina", "4 oeufs", "1 cup milk"], { factor: 2 });
605
692
  ```
606
693
 
607
- Chaque lecture répond `{ data, cached }`, et lève une erreur portant un des six
608
- codes. Chaque site garde son propre rythme, et le plancher tient également ici.
694
+ Chaque site garde son propre rythme, et les planchers tiennent également ici.
609
695
 
610
696
  ## Rythme et attribution
611
697
 
612
698
  Chaque site est cadencé pour lui-même, une requête à la fois avec au moins une
613
699
  seconde entre deux, et le plancher d'une demi-seconde tient quelle que soit la
614
- configuration. Les interroger toutes à la fois coûte donc à chacune une requête,
700
+ configuration. Deux des sites en demandent davantage, trois secondes entre deux
701
+ requêtes, et ils l'obtiennent : un réglage posé pour toutes les sources peut
702
+ élargir l'écart d'un site, jamais le réduire. Les interroger toutes à la fois coûte donc à chacune une requête,
615
703
  jamais deux. Le `User-Agent` se termine toujours par l'identité du projet et une
616
704
  adresse où joindre une personne.
617
705
 
@@ -619,7 +707,7 @@ Chaque ligne porte l'adresse de la page de la recette et le nom du site qui l'a
619
707
  publiée. Les pages du Cookbook sont publiées sous
620
708
  [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/deed.fr), qui
621
709
  demande que ce qu'on bâtit dessus soit partagé sous la même licence. Marmiton,
622
- Ptitchef, BBC Good Food et Supertoinette n'énoncent aucune condition sur une page
710
+ Ptitchef, BBC Good Food, Supertoinette et Pequerecetas n'énoncent aucune condition sur une page
623
711
  de recette, et leurs recettes appartiennent à ces sites et aux cuisiniers qui les
624
712
  ont écrites. Le silence n'est pas une autorisation : créditez le site et liez la
625
713
  page d'où vient la recette.
@@ -641,7 +729,8 @@ lit.
641
729
 
642
730
  Ce serveur ne collecte rien sur vous et n'envoie rien à son auteur. Il tourne sur
643
731
  votre machine, ne joint que `www.marmiton.org`, `api.wikimedia.org`,
644
- `www.ptitchef.com`, `www.bbcgoodfood.com` et `www.supertoinette.com`, garde ses réponses en mémoire le temps qu'il tourne, et
732
+ `www.ptitchef.com`, `www.bbcgoodfood.com`, `www.supertoinette.com` et
733
+ `www.pequerecetas.com`, garde ses réponses en mémoire le temps qu'il tourne, et
645
734
  n'écrit rien sur le disque. [PRIVACY.md](PRIVACY.md) dit ce qu'une requête
646
735
  emporte et quels réglages changent cela.
647
736