mcp-recipes 1.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,147 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. The format follows
4
+ [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and the versions follow
5
+ [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
6
+
7
+ ## [Unreleased]
8
+
9
+ ### Changed
10
+
11
+ - How finely a counted thing divides now follows the size of one of them against
12
+ what a recipe puts in, and two families come out of that one comparison. Each
13
+ family is read in both languages, because where a food falls on that
14
+ comparison has nothing to do with the words a page uses for it.
15
+ - A crevette and a shrimp, a gamba, a langoustine, a moule and a mussel, a
16
+ noisette and a hazelnut, a grain de poivre and a peppercorn, a baie de
17
+ genièvre and a juniper berry, an anis étoilé and a star anise are counted
18
+ whole. Each one is already a portion: a recipe counts five, twelve, twenty of
19
+ them, and a smaller recipe puts one fewer in the pan. `12 crevettes` halved
20
+ gave `6 crevettes` and still does, but `5 crevettes` halved gave
21
+ `2 1/2 crevettes` where it now gives `3 crevettes`, and `1 hazelnut` halved
22
+ gave `1/2 hazelnut` where it now keeps the hazelnut.
23
+ - Un gigot and a leg of lamb, une baguette, un camembert, un fromage and a
24
+ cheese, un chorizo, un ananas and a pineapple, une pêche and a peach, un
25
+ abricot and an apricot, un lait and a milk counted without a measure divide as
26
+ far as the quarter. A recipe asks for one or for two, and the share it wants
27
+ is decided by a knife. `1 gigot d'agneau` reduced to a quarter was clamped up
28
+ to `1/2 gigot` and the line was told it no longer held its share; it now comes
29
+ back as `1/4 gigot d'agneau`, exact.
30
+ - Un jus, and a juice, stops at the half, where it used to follow the fruit it
31
+ names down to the quarter. Half the jus of a citron is taken by squeezing half
32
+ the fruit, and a quarter of one has to be poured out and measured back, so
33
+ `1 jus de citron` reduced to a quarter comes back as `1/2 jus de citron`.
34
+ - A counted thing coming down to one now takes the singular of its name.
35
+ `2 clous de girofle` halved read `1 clous de girofle` and `2 kiwis` read
36
+ `1 kiwis`, because a final -s was taken for the ending of a singular such as
37
+ "jus" or "couscous". Both languages now name those words one by one, so the
38
+ two lines read `1 clou de girofle` and `1 kiwi`, while `2 ananas` reads
39
+ `1 ananas` and `1 asparagus` is left as it is. "anise" and "musk" read the
40
+ same whatever the number, so `8 star anise` halved gives `4 star anise`, and
41
+ an "étoilé" following the noun agrees with it in the same pass.
42
+ - A clou de girofle and a zeste are counted whole. `3 clous de girofle` halved
43
+ came back as `1 1/2 clou`, and `1 zeste de citron` halved as `1/2 zeste`.
44
+ Neither names an amount: a clou is a dried bud dropped into the pot and fished
45
+ back out, and a zeste is what comes off one fruit in one go. They now land on
46
+ a whole number, as an oeuf does.
47
+ - A pot, a bouteille, a bottle, a jar and a block divide as far as the quarter.
48
+ All five stopped at the half, so `1 pot de crème fraîche` reduced to a quarter
49
+ was clamped up to `1/2 pot` and the line was told it no longer held its share.
50
+ Each holds enough that a quarter is still a portion someone serves, so the
51
+ answer is now `1/4 pot de crème fraîche`, exact. The word is read wherever it
52
+ stands, so `1 petit pot de crème` gets the same floor.
53
+ - Une gousse, une tranche and a slice divide as far as the quarter. Each is
54
+ already cut off something larger, and the board that produced one takes a
55
+ corner off it in the same gesture, so `1 gousse d'ail` reduced to a quarter
56
+ comes back as `1/4 gousse d'ail` where it came back as a half, and
57
+ `4 gousses d'ail` reads `1 gousse d'ail`.
58
+ - Une pastèque and a watermelon, une pintade and a guinea fowl, un poulet and a
59
+ chicken, un poireau and a leek, une banane and a banana, une mangue and a
60
+ mango, un rôti and a roast, un avocat, un reblochon and une bûche divide as
61
+ far as the quarter, joining the gigot and the ananas. `1 pastèque` and
62
+ `1 watermelon` reduced to a quarter were clamped up to a half and the line was
63
+ told it no longer held its share; each now comes back as `1/4`, exact.
64
+ - Une cuisse, une aile, un pilon, une escalope, un magret, a thigh, a drumstick,
65
+ a wing and a cutlet stop at the half, joining the blanc and the breast. One of
66
+ them is the portion the knife carving the animal already produced, and a
67
+ quarter of one names a piece no one plates. This is what keeps
68
+ `3 cuisses de poulet` at a half now that the whole poulet goes to the quarter.
69
+ - `clove` is read on the line that writes it, having named two foods with one
70
+ answer between them. Garlic in the line makes it the gousse d'ail, which a
71
+ knife takes to a quarter, so `4 cloves garlic, minced` reduced to a quarter
72
+ reads `1 clove garlic, minced`. On its own, or written `whole cloves`, it is
73
+ the clou de girofle dropped into the pot and fished back out: nothing about it
74
+ is measured, so `4 whole cloves` halved reads `2 whole cloves` where it read
75
+ `1 whole clof`. The French words need none of this, each naming one food and
76
+ one only.
77
+ - A zest is counted whole, as a zeste is. `1 lemon zest` halved came back as
78
+ half of one, and a zest is what comes off one fruit in one go, so a share of
79
+ one names no amount a cook stops at.
80
+ - An English plural in -ves is turned back into its singular only for the names
81
+ that carry a -f or a -fe, which are listed one by one. `4 olives` halved read
82
+ `2 olives` and `1 olive` read `1 olif`.
83
+ - A dozen, and a douzaine, states a number of things rather than a measure of
84
+ them. `2 dozen mushrooms` reduced by a quarter came back as
85
+ `1 1/2 dozen mushrooms`, a count no kitchen works with, and the divisibility
86
+ of the line was being read off a word that names no food. The multiplier is
87
+ now folded into the count: the same line comes back as `18 mushrooms`, and it
88
+ divides the way a mushroom does. A line writing the count as a word,
89
+ `a dozen eggs`, is read the same way where it used to carry no quantity.
90
+ - A blanc is divided by which blanc the line names. `1 blanc de poulet` halved
91
+ came back whole, because the reading meant for the white of an oeuf was
92
+ catching every blanc introduced the same way. The white of an oeuf stays
93
+ whole, with the oeuf and the jaune; a blanc de poulet or de dinde is meat and
94
+ halves, as a chicken breast does.
95
+ - `ea` no longer appears in the line that is written back. It is short for
96
+ "each", a marker announcing that the figure counts pieces, and it names no
97
+ measure of any one of them, so `3 ea. tamarind pods` tripled read
98
+ `9 ea tamarind pods` where it now reads `9 tamarind pods`. The count is
99
+ unchanged, and the divisibility now comes from the thing counted, so
100
+ `1 ea. onion` goes to a quarter and `12 ea. eggs` lands on a whole number.
101
+
102
+ ## [1.0.0] - 2026-02-06
103
+
104
+ First release.
105
+
106
+ ### Added
107
+
108
+ - `search_recipes`: asks every registered source at the same time and returns one
109
+ merged list. Every row carries an identifier naming the source it came from.
110
+ Rows alternate one source at a time, and the answer says how the order was
111
+ built.
112
+ - `get_recipe`: reads one recipe from the source its identifier names, optionally
113
+ rescaled to a number of servings. Sections are opt-in and the omitted ones are
114
+ named, a raw identifier is routed by its shape and the answer says how, and a
115
+ page stating no yield comes back as published with the reason.
116
+ - `scale_ingredients`: multiplies a list a caller already holds, offline, with no
117
+ request to any site. Reads French and English lines in one call, each in its
118
+ own language.
119
+ - `compare_recipes`: takes a dish, reads each source's closest version, rescales
120
+ them all to the same yield, and states what differs between them. Where the
121
+ versions agree, it says nothing.
122
+ - A bilingual scaler. An egg stays whole and anything that pours, weighs or cuts
123
+ can halve, a measurement moves to a smaller unit before it is rounded, an
124
+ approximate measure has its count multiplied while the size of one stays the
125
+ cook's, and every branch of a line offering a choice is scaled. Each line
126
+ reports whether the arithmetic was exact, rounded, or impossible.
127
+ - Argument names checked rather than filtered. Every tool refuses an argument it
128
+ does not declare, under the `invalid_input` code, naming the argument and
129
+ offering the declared name when one is close: `limit` on `search_recipes` is
130
+ refused and answered with `limit_per_source`. The schema each tool publishes
131
+ carries `additionalProperties: false`, so a client reads the rule before it
132
+ calls. A name that is read and dropped costs a caller an answer computed on
133
+ the defaults and presented as an answer to what they asked.
134
+ - Per-source reporting on every tool that calls out: which sources answered,
135
+ which failed and why, and what each source's own count means in its own
136
+ terms.
137
+ - A published client entry point (`mcp-recipes/client`) and a published scaler
138
+ entry point (`mcp-recipes/scale`), both usable as plain libraries with no
139
+ protocol attached.
140
+ - Pacing with a floor that configuration cannot go below, and a User-Agent that
141
+ always carries a way to reach a human.
142
+ - A source registry, so adding a corpus is an adapter and an entry rather than a
143
+ branch in every tool.
144
+ - A nightly canary against the real sites, which opens an issue when one of them
145
+ changes something this server reads.
146
+
147
+ [1.0.0]: https://github.com/smeet666/mcp-recipes/releases/tag/v1.0.0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Damien Bouissou
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.