mcp-marmiton 1.8.0 → 2.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/CHANGELOG.md ADDED
@@ -0,0 +1,330 @@
1
+ # Changelog
2
+
3
+ ## 2.0.0
4
+
5
+ - **This server now needs node 24 or later.** Node 20 reached its end of
6
+ support on 2026-04-30 and node 22 is no longer what this code is built and
7
+ typed against. That is what makes this a major version: an install on an
8
+ older node is refused rather than left to fail somewhere later.
9
+ - **Every refusal of an argument opens with `invalid_input`.** A value outside
10
+ its bounds, of the wrong type, or outside the set an argument reads used to
11
+ come back in the validator's own words, with no code to branch on.
12
+ - **A container image is published for each version**, on ghcr, for amd64 and
13
+ arm64. The readme carries the configuration that runs it.
14
+ - The published package carries its changelog, and the entry point it declares
15
+ for the package root now publishes its types.
16
+
17
+ ## 1.8.1
18
+
19
+ - The README carries the same badge row as every server here: npm, CI, the
20
+ licence, the MCP registry entry, the Glama score, and one-click installs for
21
+ Cursor and VS Code. Each install link encodes this package. npm serves the
22
+ README frozen at publish time, so a release is what puts it there.
23
+
24
+ ## 1.8.0
25
+
26
+ - A mass stated behind the thing counted is read as the size of one of them.
27
+ "1 dinde de 3 kg" names one bird and says what it weighs, and multiplying the
28
+ count answered a Christmas dinner for twelve with a bird and a half. Lines of
29
+ that shape come back as the page published them, with a note saying the figure
30
+ gives a size and that more people means a bigger bird. A container keeps
31
+ counting: "2 boîtes de 400 g de tomates" states what one boîte holds and goes
32
+ on to name what is in it, and an equivalence such as "450 g (1 livre) de
33
+ spaghetti" restates one quantity twice and is scaled on both sides.
34
+
35
+ - A search whose wording matches nothing is an absence rather than a failure.
36
+ Marmiton serves a 404 on its results page when no recipe matches, and that was
37
+ handed back as a failed read, so a caller was told Marmiton could not be
38
+ reached for a search Marmiton had answered. Such a search now returns an empty
39
+ list with the note that says so, and a recipe page that is not there is still
40
+ reported as not_found.
41
+
42
+ - A page of results carrying none of the words asked for says so. Marmiton ranks
43
+ a title on the letters it opens with, so "chameau farci" comes back with a
44
+ chapeau and three gâteaux château. When no title returned carries a word of
45
+ the query, the answer names that, and the rows read as candidates to check.
46
+
47
+ ## 1.7.0
48
+
49
+ - Read the shapes a Marmiton line actually takes. A page that restates a weight
50
+ in brackets or after a slash, offers a choice with "ou", writes a mixed number
51
+ as "3 ¼", or marks a plural it does not know with "cuillère(s)" was answered
52
+ with a number that had lost part of itself: the second branch of a choice kept
53
+ the figure the page printed, the quarter of "3 ¼" travelled into the name of
54
+ the ingredient, and "8 cuillère(s)s" was not a word. Each of these is now read,
55
+ scaled and written back the way the line offered it.
56
+
57
+ - Stop multiplying a figure that was never a count. An amount stated per person
58
+ already carries the change the factor asks for, and doubling it puts twice as
59
+ much on every plate; a number joined to a word by a hyphen gives the size of
60
+ one thing rather than how many; and a number grouped the way French never
61
+ groups one has two readings a thousand apart. All three come back as the page
62
+ published them, with a note saying which of the three it is, rather than with
63
+ the note about a line that carries no quantity, which was untrue of every one
64
+ of them.
65
+
66
+ - Read the quantity behind the word that hid it. "environ 6 citrons" and
67
+ "~1 verre d'eau" carried an amount that was answered as if the line had none;
68
+ "1 grosse pincée de sel" lost the pincée, and with it the fact that a pincée is
69
+ held to no better than the hand. Both now read through to the figure and the
70
+ measure, and put the word and the sign back where the page had them.
71
+
72
+ - Round a mass or a volume to the tenth between one and ten, where the step was
73
+ half a unit. A unit in that range can be a kilo as readily as a gram, and
74
+ halving 2,5 kg de figues gave 1,5 kg: two hundred grams more than the recipe
75
+ asked for, reported as though it were the product itself. A recipe made
76
+ smaller also never comes out asking for more than the page published, where
77
+ reducing a line by one percent could raise it by one.
78
+
79
+ - Express a share of a cuillère à soupe or of a tasse in the smaller spoon. A
80
+ quarter of a cuillère à soupe exists on no measuring set, and the answer is
81
+ three quarters of a cuillère à café.
82
+
83
+ - Put both ends of a range in one unit, chosen from the lower one, so
84
+ "450 à 1000 g" no longer comes back as "450 à 1 kg". Where both ends land on
85
+ the same amount the line states that amount once and says the range collapsed,
86
+ and `amount` now reports the lower bound with `amountMax` beside it, where it
87
+ reported the upper bound and offered no way to reach the other.
88
+
89
+ - Say more about what happened to a line. A range whose two ends moved names each
90
+ of them with its own direction; a line carrying a second quantity after the
91
+ first says that only the first was scaled; a quantity below what a kitchen
92
+ scale resolves says so; and an approximate measure names what a kitchen usually
93
+ takes one to be, instead of a sentence that named none. A factor of one now
94
+ returns the line untouched, where it rewrote "178 ml" as "180 ml".
95
+
96
+ - Take a gousse d'ail to the half and no finer, and count a baie de genévrier and
97
+ une étoile de badiane whole, as the person who cooks these recipes has them.
98
+
99
+ ## 1.6.0
100
+
101
+ - Refuse an argument the schema does not declare, rather than dropping it in
102
+ silence. The schema already announced that it accepted no others, and a caller
103
+ who misspells one was answered from the defaults as though the call had been
104
+ understood. The refusal names the argument, suggests the real one when it is
105
+ close, and lists what the tool takes.
106
+
107
+ - Rewrite the rule that decides how far a counted thing can be divided. It read
108
+ the packaging, so a tin of tomatoes was never halved although half a tin of
109
+ apricots in syrup is poured out and the rest kept. What decides is the size of
110
+ one unit against what a recipe puts in: a crevette, a moule, a grain de poivre
111
+ is already a portion, counted by the dozen, and a smaller recipe puts one fewer
112
+ in the pan; a gigot, a camembert, an ananas is asked for by the one and shared
113
+ out with a knife. An oeuf, a jaune and a blanc d'oeuf stay whole, since halving
114
+ one means beating it and weighing the result. A jus stops at the half, which is
115
+ half a fruit squeezed rather than a quarter poured and measured back.
116
+
117
+ - Read a douzaine as the twelve it stands for. Two douzaines d'escargots taken
118
+ down a quarter now asks for eighteen escargots.
119
+
120
+ - Tell a blanc d'oeuf from a blanc de volaille, which the same word names and
121
+ which divide differently.
122
+
123
+ - Agree a counted noun with the number that precedes it in more places. Words
124
+ ending in -as, -is, -us and -ous were taken for singulars, so two clous came
125
+ back as "1 clous", and an adjective following the noun stayed plural.
126
+
127
+ ## 1.5.0
128
+
129
+ - Read an approximate measure from the shape of the line as well as from the
130
+ vocabulary. A noun standing between the amount and the partitive that
131
+ introduces what is measured names a container or a gesture whose size belongs
132
+ to the cook: `un bouchon de rhum` scaled sixfold comes back as
133
+ `6 bouchons de rhum`, and so does a container no list carries, such as
134
+ `un ramequin de crème fraîche`. The line came back untouched and flagged
135
+ `unscaled` with "No quantity given" before, which was false: a bouchon is an
136
+ amount.
137
+ - Add `bouchon`, `larme`, `doigt`, `nuage`, `louche`, `lichette` and `pointe` to
138
+ the vocabulary of approximate measures.
139
+ - An article written in place of a digit is read before any measure, not only an
140
+ approximate one, so `un sachet de levure` and `un litre de lait` scale like
141
+ the lines that open on a figure. The note says which word the figure was read
142
+ from. An article before a bare countable thing, as in `un oignon`, still
143
+ leaves the line as published.
144
+ - Take the article with the amount it belongs to when a line states a share of
145
+ one thing: `2/3 d'un flacon de fleur d'oranger` scaled sixfold reads
146
+ `4 flacons de fleur d'oranger`, with the plural agreed, instead of leaving the
147
+ article stranded in front of the count.
148
+ - A counted noun in -eau or -al takes the plural French gives it, so
149
+ `1 morceau de beurre` multiplied reads `6 morceaux de beurre`.
150
+ - `scaling` reports what the arithmetic did rather than what the unit is.
151
+ `scaled` means the value is the product itself, which a count of eggs, spoons
152
+ or pinches reaches as readily as a mass in grams: one pinch multiplied by six
153
+ is six pinches, exactly. `rounded` is kept for a value that had to be moved,
154
+ whether to a whole unit or to a step a scale can show, so a measurement
155
+ rounded from 133.4 g to 135 g reports it.
156
+
157
+ ## 1.4.0
158
+
159
+ - Scale approximate French measures instead of returning them untouched. A pinch,
160
+ a handful, a drizzle, a knob, a dash, a drop or a hint is a quantity, and the
161
+ proportion of the recipe lives in how many of them a line asks for, so the
162
+ count is now multiplied in whole units: `une pincée de bicarbonate de soude`
163
+ taken from 6 servings to 25 comes back as `4 pincées de bicarbonate de soude`,
164
+ flagged `rounded`, with a note saying the measure is approximate. Previously
165
+ the line came back unchanged, flagged `unscaled`, with the note "No quantity
166
+ given; adjust to taste." That was wrong twice over: the line does carry a
167
+ quantity, and tasting cannot rescue a batter raised by a single pinch of
168
+ bicarbonate for four times the flour.
169
+ - No approximate measure is converted into grams or spoons. Published
170
+ equivalences for a pinch span a fourfold range, so any such figure would be a
171
+ number the recipe never carried; an order of magnitude belongs in a note.
172
+ - Read the article a recipe writes in place of a digit before such a measure:
173
+ `une`, `un` and `quelques`, the last read as three, with the word it came from
174
+ reported in the note. An article before a countable thing, as in `un oignon`,
175
+ still leaves the line as published.
176
+ - Add `noix` and `soupçon` to the vocabulary of approximate measures, alongside
177
+ `pincée`, `poignée`, `trait`, `filet` and `goutte`.
178
+ - `unscaled` now means one thing only: the line carries no quantity at all, as in
179
+ `sel` or `coriandre`, and that is where the note "No quantity given" remains.
180
+ - Agree a trailing adjective with the count on a counted item, so
181
+ `1 piment de Cayenne entier` multiplied reads `4 piments de Cayenne entiers`. A
182
+ trailing word outside a short list of common recipe adjectives is left as the
183
+ recipe wrote it, since a brand or a proper noun takes no plural mark.
184
+
185
+ ## 1.3.1
186
+
187
+ - Stop published text from producing a line shaped like one this server writes.
188
+ The text block ends with lines opening "Note:" and "Source:", and anyone who
189
+ publishes on the site can put those same words at the start of a line in a
190
+ title or a description, where a reader has no way to tell the two apart. Such
191
+ a line is indented in the text block. The structured output carries the text
192
+ exactly as published, as it did.
193
+
194
+ ## 1.3.0
195
+
196
+ - Ship a `.mcpb` bundle on every release, so the server can be installed by
197
+ opening a file rather than by having npm and a client configuration. The
198
+ dependencies are compiled into a single file, which makes the bundle 164 kB
199
+ and five files instead of 3 MB and two thousand: a bundle is unpacked, not
200
+ resolved, so a copy of `node_modules` would only be dead weight. The npm build
201
+ still keeps its dependencies external, and the two builds are separate
202
+ configurations for that reason.
203
+ - Declare the bundle in `server.json`, with the hash the registry requires
204
+ computed from the released file at publish time rather than committed as a
205
+ value that goes stale on every build.
206
+
207
+ ## 1.2.1
208
+
209
+ Housekeeping, with no change to what any tool returns.
210
+
211
+ - Declare the tool schemas as objects rather than as the raw shape the SDK now
212
+ deprecates. The emitted `tools/list` is byte for byte what it was.
213
+ - Add an icon and a `websiteUrl` to `server.json`, so the registry has something
214
+ to show next to the entry.
215
+ - `scale_ingredients` no longer claims an open world. It does arithmetic on the
216
+ arguments it was handed and contacts nothing, so the same list and the same
217
+ factor give the same answer whatever Marmiton publishes.
218
+
219
+ ## 1.2.0
220
+
221
+ Quantities that were arithmetically right and uncookable, which is a wrong
222
+ answer here because the caller acts on it.
223
+
224
+ - Scale both ends of a range. "2 à 3 gousses" doubled returned "4 à 3", an
225
+ inverted range, and shrunk it returned "2/3 à 3", a line still asking for
226
+ three cloves when the whole point was to ask for fewer. Ranges written with
227
+ "à", "ou" or a dash are read as one quantity and scaled together, and the
228
+ upper bound is what `amount` reports, since that is what a cook buys.
229
+ - Round a countable item back to a whole one. One egg times 0.9 answered "3/4
230
+ oeuf", and three eggs times 0.33 did the same, because a whole was not among
231
+ the values below one that a fraction could snap to. It is now, with a ceiling
232
+ that keeps a shrunk recipe from ever asking for more than the original.
233
+ - Say when a quantity was clamped. Below a quarter there is nothing a kitchen
234
+ can measure, so the amount is clamped up, and that line no longer holds its
235
+ share of the recipe: half a sachet of baking powder against three pots of
236
+ flour comes out four times too strong. The line and the response now both say
237
+ so instead of leaving the caller to discover it in the oven.
238
+ - Convert before rounding, not after. A kilo divided by a thousand rounded to
239
+ "0 kg", stating the recipe needs none of it, and a quarter of a millilitre
240
+ came back three tenths, a fifth too much. Every rounding now happens in a unit
241
+ large enough to survive it.
242
+ - Count the quantities that were actually moved. Every response claimed the same
243
+ number of roundings whatever the factor, including factors where every result
244
+ landed exact. Each ingredient carries `adjusted` for the same question.
245
+ - Carry the steps and the notes into the text block. A client rendering only
246
+ text got a recipe with no cooking steps, no warning that the numbers had been
247
+ rounded, and calorie figures with nothing to say they describe the recipe as
248
+ published rather than the amounts printed above them.
249
+ - Stop labelling every line "(non ajusté)" when no rescaling was requested. The
250
+ flag answers "why is this unchanged", which is only a question when something
251
+ was meant to change.
252
+ - Say when `factor` and the `from_servings`/`to_servings` pair are both given.
253
+ The factor won silently, so a caller asking for 4 to 12 could be served a
254
+ different multiplier without being told.
255
+ - Print the factor that was applied. `factor: 0.001` was shown as "Facteur 0",
256
+ which states that nothing was applied to quantities divided by a thousand.
257
+ - Write "25 pots" rather than "25 pot", and "d'huile" rather than "de huile".
258
+
259
+ ## 1.1.0
260
+
261
+ - Cache a response only once it has been read successfully. The cache stored
262
+ the raw response before parsing, so a page Marmiton served but this client could
263
+ not understand stayed pinned for the cache lifetime and was replayed on every
264
+ retry: the tool could not recover even after the site was healthy again. It
265
+ now holds the parsed result, which also keeps the raw payload out of memory.
266
+
267
+ ## 1.0.4
268
+
269
+ - Claim a pacing slot per request instead of per task. A task runs a whole
270
+ retry chain, so stamping only its start let the next task follow the chain's
271
+ last request with no gap, below the interval the configuration promises.
272
+ - Honour `Retry-After` when Marmiton sends one, in both its seconds and its
273
+ HTTP-date form, instead of guessing a delay. The wait is spent between
274
+ attempts rather than after the last one, where nobody would use it.
275
+ - Treat HTTP 403 as a refusal to back off from. It was reported as a plain
276
+ error, so the client kept its pace in the one situation where slowing down is
277
+ the remedy.
278
+ - Bound the pacing wait by the interval. A clock stepped backwards, by NTP or a
279
+ resumed virtual machine, made the next request wait for the size of the step,
280
+ and the queue is serial so every pending call waited behind it.
281
+ - Enforce the pacing floor and the identifying User-Agent in the client rather
282
+ than only when reading the environment. The client is published through the
283
+ `./client` export and accepts a caller-built config, so both promises were
284
+ previously optional for anyone importing the library.
285
+
286
+ ## 1.0.3
287
+
288
+ - Refresh the packaged README, which now carries one-click install links for
289
+ Cursor and VS Code and a link to the entry in the official MCP registry.
290
+ - Keep LICENSE to the plain MIT text. License detectors match the file against
291
+ the canonical template, so the trailing scope note made the package read as
292
+ unlicensed; that note lives in the README. It also described lyrics rather
293
+ than recipes.
294
+
295
+ ## 1.0.2
296
+
297
+ - Keep a scaled mass or volume at a human size. Multiplying a recipe for a
298
+ canteen returned "8335 g de sucre", which is correct and unusable; it now reads
299
+ "8,34 kg". Amounts climb to the unit above at a full unit of it, and come back
300
+ down below one, so half a litre reads "50 cl" rather than "1/2 l".
301
+ - Write mass and volume as decimals rather than fractions. Fractions belong to
302
+ things a cook counts or spoons out: "8 1/3 kg" is not how anyone weighs sugar.
303
+
304
+ Note that `amount` is expressed in `unit`, which may now differ from the unit
305
+ the recipe used. Read the two together: 200 g scaled tenfold reports an amount
306
+ of 2 with a unit of kg, so the bare number shrinks while the quantity grows.
307
+
308
+ ## 1.0.1
309
+
310
+ - Make a counted ingredient agree with its amount when scaling **up**, not only
311
+ when scaling down. Tripling a recipe returned "3 brioche" and "3 orange"
312
+ alongside a correct "30 oeufs", because the agreement helper only knew how to
313
+ remove a plural mark. Nouns that take no plural mark, and those whose singular
314
+ already ends in -s, are still left untouched.
315
+
316
+ ## 1.0.0
317
+
318
+ First stable release. The tool contracts are settled: tool names, their parameters
319
+ and the shape of their structured output will only change in a future major
320
+ version.
321
+
322
+ Every tool has been exercised end to end against the live site, including the
323
+ paths that are easy to get wrong: scaling down without ever asking for more than
324
+ the original, scaling without ever rounding an ingredient away to nothing,
325
+ recipes that state no yield, and a page that loads without structured recipe data.
326
+
327
+ ## 0.1.0
328
+
329
+ Initial release. Three read-only tools over stdio, no API key: `search_recipes`,
330
+ `get_recipe` (with optional rescaling) and `scale_ingredients` (offline).
package/LICENSE CHANGED
@@ -1,6 +1,6 @@
1
1
  MIT License
2
2
 
3
- Copyright (c) 2026 smeet666
3
+ Copyright (c) 2026 Damien Bouissou
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining a copy
6
6
  of this software and associated documentation files (the "Software"), to deal
package/README.md CHANGED
@@ -5,6 +5,10 @@
5
5
  [![license](https://img.shields.io/npm/l/mcp-marmiton.svg)](./LICENSE)
6
6
  [![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-6E56CF)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.smeet666/mcp-marmiton)
7
7
  [![Glama](https://glama.ai/mcp/servers/smeet666/mcp-marmiton/badges/score.svg)](https://glama.ai/mcp/servers/smeet666/mcp-marmiton)
8
+ [![M8ven](https://m8ven.ai/badge/mcp/smeet666-mcp-marmiton-1f9qvs?variant=verified)](https://m8ven.ai/mcp/smeet666-mcp-marmiton-1f9qvs)
9
+ [![Install in Cursor](https://cursor.com/deeplink/mcp-install-dark.svg)](https://cursor.com/en/install-mcp?name=marmiton&config=eyJjb21tYW5kIjoibnB4IiwiYXJncyI6WyIteSIsIm1jcC1tYXJtaXRvbiJdfQ%3D%3D)
10
+ [![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=marmiton&config=%7B%22name%22%3A%22marmiton%22%2C%22command%22%3A%22npx%22%2C%22args%22%3A%5B%22-y%22%2C%22mcp-marmiton%22%5D%7D)
11
+ <!-- m8ven-verify: 67179fe5844dc3b97dbd373300cca0e0 -->
8
12
 
9
13
  An [MCP](https://modelcontextprotocol.io) server for [Marmiton](https://www.marmiton.org),
10
14
  the French recipe site. Search recipes, read their ingredients and steps, and
@@ -41,6 +45,23 @@ claude mcp add marmiton -- npx -y mcp-marmiton
41
45
  }
42
46
  ```
43
47
 
48
+ ### With Docker
49
+
50
+ ```json
51
+ {
52
+ "mcpServers": {
53
+ "marmiton": {
54
+ "command": "docker",
55
+ "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-marmiton:2.0.0"]
56
+ }
57
+ }
58
+ }
59
+ ```
60
+
61
+ `-i` keeps stdin open, which is where the protocol travels, and no `-t` is
62
+ passed: a TTY rewrites the stream and breaks it. The container needs outbound
63
+ HTTPS to `www.marmiton.org`, and nothing else: no volume, no port, no environment variable, no credential.
64
+
44
65
  **Bundle, without npm**
45
66
 
46
67
  Download `mcp-marmiton-<version>.mcpb` from
@@ -283,6 +304,24 @@ claude mcp add marmiton -- npx -y mcp-marmiton
283
304
  }
284
305
  ```
285
306
 
307
+ ### Avec Docker
308
+
309
+ ```json
310
+ {
311
+ "mcpServers": {
312
+ "marmiton": {
313
+ "command": "docker",
314
+ "args": ["run", "-i", "--rm", "ghcr.io/smeet666/mcp-marmiton:2.0.0"]
315
+ }
316
+ }
317
+ }
318
+ ```
319
+
320
+ `-i` garde l'entrée standard ouverte, qui est le canal du protocole, et aucun
321
+ `-t` n'est passé : un terminal réécrit le flux et le casse. Le conteneur a besoin
322
+ d'un accès HTTPS sortant vers `www.marmiton.org`, et de rien d'autre :
323
+ aucun volume, aucun port, aucune variable d'environnement, aucun identifiant.
324
+
286
325
  **Bundle, sans npm**
287
326
 
288
327
  Téléchargez `mcp-marmiton-<version>.mcpb` depuis