@cyanheads/openfoodfacts-mcp-server 0.1.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/AGENTS.md +335 -0
- package/CLAUDE.md +335 -0
- package/Dockerfile +99 -0
- package/LICENSE +201 -0
- package/README.md +290 -0
- package/changelog/0.1.x/0.1.0.md +15 -0
- package/changelog/template.md +127 -0
- package/dist/config/server-config.d.ts +15 -0
- package/dist/config/server-config.d.ts.map +1 -0
- package/dist/config/server-config.js +35 -0
- package/dist/config/server-config.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.d.ts +27 -0
- package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.js +91 -0
- package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/compare-products.tool.d.ts +36 -0
- package/dist/mcp-server/tools/definitions/compare-products.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/compare-products.tool.js +228 -0
- package/dist/mcp-server/tools/definitions/compare-products.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/get-product.tool.d.ts +83 -0
- package/dist/mcp-server/tools/definitions/get-product.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/get-product.tool.js +420 -0
- package/dist/mcp-server/tools/definitions/get-product.tool.js.map +1 -0
- package/dist/mcp-server/tools/definitions/index.d.ts +175 -0
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/index.js +15 -0
- package/dist/mcp-server/tools/definitions/index.js.map +1 -0
- package/dist/mcp-server/tools/definitions/search-products.tool.d.ts +54 -0
- package/dist/mcp-server/tools/definitions/search-products.tool.d.ts.map +1 -0
- package/dist/mcp-server/tools/definitions/search-products.tool.js +219 -0
- package/dist/mcp-server/tools/definitions/search-products.tool.js.map +1 -0
- package/dist/services/openfoodfacts/openfoodfacts-service.d.ts +54 -0
- package/dist/services/openfoodfacts/openfoodfacts-service.d.ts.map +1 -0
- package/dist/services/openfoodfacts/openfoodfacts-service.js +308 -0
- package/dist/services/openfoodfacts/openfoodfacts-service.js.map +1 -0
- package/dist/services/openfoodfacts/types.d.ts +89 -0
- package/dist/services/openfoodfacts/types.d.ts.map +1 -0
- package/dist/services/openfoodfacts/types.js +7 -0
- package/dist/services/openfoodfacts/types.js.map +1 -0
- package/dist/services/taxonomy/taxonomy-service.d.ts +24 -0
- package/dist/services/taxonomy/taxonomy-service.d.ts.map +1 -0
- package/dist/services/taxonomy/taxonomy-service.js +271 -0
- package/dist/services/taxonomy/taxonomy-service.js.map +1 -0
- package/package.json +102 -0
- package/server.json +141 -0
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Tool definition for fetching a food product by barcode from Open Food Facts.
|
|
3
|
+
* @module mcp-server/tools/definitions/get-product
|
|
4
|
+
*/
|
|
5
|
+
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
|
+
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
7
|
+
import { getOpenFoodFactsService } from '../../../services/openfoodfacts/openfoodfacts-service.js';
|
|
8
|
+
/** Maps raw hyphenated nutriment keys → output schema keys. */
|
|
9
|
+
const NUTRIMENT_MAP = [
|
|
10
|
+
['energy-kcal_100g', 'energy_kcal_100g'],
|
|
11
|
+
['fat_100g', 'fat_100g'],
|
|
12
|
+
['saturated-fat_100g', 'saturated_fat_100g'],
|
|
13
|
+
['carbohydrates_100g', 'carbohydrates_100g'],
|
|
14
|
+
['sugars_100g', 'sugars_100g'],
|
|
15
|
+
['fiber_100g', 'fiber_100g'],
|
|
16
|
+
['proteins_100g', 'proteins_100g'],
|
|
17
|
+
['salt_100g', 'salt_100g'],
|
|
18
|
+
['sodium_100g', 'sodium_100g'],
|
|
19
|
+
['energy-kcal_serving', 'energy_kcal_serving'],
|
|
20
|
+
['fat_serving', 'fat_serving'],
|
|
21
|
+
['sugars_serving', 'sugars_serving'],
|
|
22
|
+
];
|
|
23
|
+
/** Normalize the raw hyphenated nutriments map to the output schema shape. */
|
|
24
|
+
function normalizeNutriments(raw) {
|
|
25
|
+
if (!raw)
|
|
26
|
+
return;
|
|
27
|
+
const result = {};
|
|
28
|
+
for (const [rawKey, outKey] of NUTRIMENT_MAP) {
|
|
29
|
+
const v = raw[rawKey];
|
|
30
|
+
if (typeof v === 'number')
|
|
31
|
+
result[outKey] = v;
|
|
32
|
+
}
|
|
33
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
34
|
+
}
|
|
35
|
+
/** Format a completeness score with a human-readable label. */
|
|
36
|
+
function completenessLabel(score) {
|
|
37
|
+
if (score >= 0.8)
|
|
38
|
+
return `${Math.round(score * 100)}% (high)`;
|
|
39
|
+
if (score >= 0.5)
|
|
40
|
+
return `${Math.round(score * 100)}% (moderate)`;
|
|
41
|
+
return `${Math.round(score * 100)}% (low — many fields missing)`;
|
|
42
|
+
}
|
|
43
|
+
export const offGetProductTool = tool('off_get_product', {
|
|
44
|
+
title: 'Get Food Product by Barcode',
|
|
45
|
+
description: 'Fetch a packaged food product by barcode (EAN-13 or UPC) from Open Food Facts. Returns the product name, brand, quantity, ingredients (raw text and parsed list), allergens, additives, computed scores (Nutri-Score a–e, NOVA 1–4, Green-Score), nutrition per 100g and per serving, categories, labels, packaging, origins, image URL, and data completeness. Open Food Facts is a crowd-sourced database — a missing field means "not yet entered by contributors," not that the attribute is absent from the actual product. Computed scores carry regional formula caveats and are indicators, not absolute rankings. Data is under ODbL 1.0 — cite Open Food Facts in downstream use.',
|
|
46
|
+
annotations: { readOnlyHint: true, idempotentHint: true, openWorldHint: true },
|
|
47
|
+
input: z.object({
|
|
48
|
+
barcode: z
|
|
49
|
+
.string()
|
|
50
|
+
.regex(/^\d{8,14}$/)
|
|
51
|
+
.describe('EAN-13 or UPC barcode (8–14 digits). The primary key for Open Food Facts. Example: "3017620422003" (Nutella FR).'),
|
|
52
|
+
fields: z
|
|
53
|
+
.array(z
|
|
54
|
+
.enum([
|
|
55
|
+
'product_name',
|
|
56
|
+
'brands',
|
|
57
|
+
'quantity',
|
|
58
|
+
'ingredients_text',
|
|
59
|
+
'ingredients',
|
|
60
|
+
'allergens_tags',
|
|
61
|
+
'additives_tags',
|
|
62
|
+
'nutriscore_grade',
|
|
63
|
+
'nova_group',
|
|
64
|
+
'ecoscore_grade',
|
|
65
|
+
'nutriments',
|
|
66
|
+
'categories_tags',
|
|
67
|
+
'labels_tags',
|
|
68
|
+
'packaging_tags',
|
|
69
|
+
'origins_tags',
|
|
70
|
+
'image_url',
|
|
71
|
+
'completeness',
|
|
72
|
+
'data_quality_tags',
|
|
73
|
+
])
|
|
74
|
+
.describe('A specific product field to include in the response.'))
|
|
75
|
+
.optional()
|
|
76
|
+
.describe('Subset of fields to return. Omitting returns all standard fields. Use to reduce payload when only scores or ingredients are needed.'),
|
|
77
|
+
}),
|
|
78
|
+
output: z.object({
|
|
79
|
+
barcode: z.string().describe('Barcode as returned by the API.'),
|
|
80
|
+
found: z
|
|
81
|
+
.boolean()
|
|
82
|
+
.describe('False when the barcode exists in no contributor record (status:0). A false result means no contributor has entered this product yet — not that the product does not exist.'),
|
|
83
|
+
product: z
|
|
84
|
+
.object({
|
|
85
|
+
product_name: z
|
|
86
|
+
.string()
|
|
87
|
+
.optional()
|
|
88
|
+
.describe('Product name. May be absent if not yet entered by contributors.'),
|
|
89
|
+
brands: z.string().optional().describe('Brand name(s), comma-separated.'),
|
|
90
|
+
quantity: z
|
|
91
|
+
.string()
|
|
92
|
+
.optional()
|
|
93
|
+
.describe('Net quantity as printed on packaging (e.g. "400g").'),
|
|
94
|
+
ingredients_text: z
|
|
95
|
+
.string()
|
|
96
|
+
.optional()
|
|
97
|
+
.describe('Raw ingredients text from the label, in the source language.'),
|
|
98
|
+
ingredients: z
|
|
99
|
+
.array(z
|
|
100
|
+
.object({
|
|
101
|
+
id: z
|
|
102
|
+
.string()
|
|
103
|
+
.optional()
|
|
104
|
+
.describe('Canonical ingredient ID (e.g. "en:sugar", "en:salt").'),
|
|
105
|
+
text: z.string().describe('Ingredient name as it appears in the list.'),
|
|
106
|
+
percent_estimate: z
|
|
107
|
+
.number()
|
|
108
|
+
.optional()
|
|
109
|
+
.describe('Estimated percentage of this ingredient.'),
|
|
110
|
+
vegan: z
|
|
111
|
+
.string()
|
|
112
|
+
.optional()
|
|
113
|
+
.describe('"yes", "no", or "maybe" — absent when unknown.'),
|
|
114
|
+
vegetarian: z
|
|
115
|
+
.string()
|
|
116
|
+
.optional()
|
|
117
|
+
.describe('"yes", "no", or "maybe" — absent when unknown.'),
|
|
118
|
+
})
|
|
119
|
+
.describe('A single parsed ingredient entry.'))
|
|
120
|
+
.optional()
|
|
121
|
+
.describe('Parsed ingredient list. Absent when not yet parsed by contributors.'),
|
|
122
|
+
allergens_tags: z
|
|
123
|
+
.array(z.string().describe('Canonical allergen tag ID (e.g. "en:milk", "en:gluten").'))
|
|
124
|
+
.optional()
|
|
125
|
+
.describe('Canonical allergen tag IDs. Absence means not yet entered — not that the product is allergen-free.'),
|
|
126
|
+
additives_tags: z
|
|
127
|
+
.array(z.string().describe('E-number additive tag ID (e.g. "en:e322", "en:e322i").'))
|
|
128
|
+
.optional()
|
|
129
|
+
.describe('E-number additive tag IDs. Absence means not yet entered.'),
|
|
130
|
+
nutriscore_grade: z
|
|
131
|
+
.string()
|
|
132
|
+
.optional()
|
|
133
|
+
.describe('Nutri-Score letter (a–e, lowercase). "a" is highest nutritional quality. Absent when not enough nutrition data to compute. Regional formula variants exist.'),
|
|
134
|
+
nova_group: z
|
|
135
|
+
.number()
|
|
136
|
+
.optional()
|
|
137
|
+
.describe('NOVA food processing class (1=unprocessed, 2=culinary ingredients, 3=processed, 4=ultra-processed). Absent when not enough data.'),
|
|
138
|
+
ecoscore_grade: z
|
|
139
|
+
.string()
|
|
140
|
+
.optional()
|
|
141
|
+
.describe('Green-Score/Eco-Score environmental impact letter (a–e, or "unknown"). Highly variable — depends on packaging, origins, and transport data completeness.'),
|
|
142
|
+
nutriments: z
|
|
143
|
+
.object({
|
|
144
|
+
energy_kcal_100g: z.number().optional().describe('Energy per 100g in kcal.'),
|
|
145
|
+
fat_100g: z.number().optional().describe('Total fat per 100g in grams.'),
|
|
146
|
+
saturated_fat_100g: z.number().optional().describe('Saturated fat per 100g in grams.'),
|
|
147
|
+
carbohydrates_100g: z
|
|
148
|
+
.number()
|
|
149
|
+
.optional()
|
|
150
|
+
.describe('Total carbohydrates per 100g in grams.'),
|
|
151
|
+
sugars_100g: z.number().optional().describe('Total sugars per 100g in grams.'),
|
|
152
|
+
fiber_100g: z
|
|
153
|
+
.number()
|
|
154
|
+
.optional()
|
|
155
|
+
.describe('Dietary fiber per 100g in grams. Often absent.'),
|
|
156
|
+
proteins_100g: z.number().optional().describe('Protein per 100g in grams.'),
|
|
157
|
+
salt_100g: z.number().optional().describe('Salt per 100g in grams.'),
|
|
158
|
+
sodium_100g: z.number().optional().describe('Sodium per 100g in grams.'),
|
|
159
|
+
energy_kcal_serving: z
|
|
160
|
+
.number()
|
|
161
|
+
.optional()
|
|
162
|
+
.describe('Energy per serving in kcal. Absent when serving size not defined.'),
|
|
163
|
+
fat_serving: z
|
|
164
|
+
.number()
|
|
165
|
+
.optional()
|
|
166
|
+
.describe('Total fat per serving in grams. Absent when serving size not defined.'),
|
|
167
|
+
sugars_serving: z
|
|
168
|
+
.number()
|
|
169
|
+
.optional()
|
|
170
|
+
.describe('Sugars per serving in grams. Absent when serving size not defined.'),
|
|
171
|
+
})
|
|
172
|
+
.optional()
|
|
173
|
+
.describe('Nutrition figures normalized to underscore keys. All values may be absent when nutrition data not yet entered.'),
|
|
174
|
+
categories_tags: z
|
|
175
|
+
.array(z.string().describe('Canonical category tag ID (e.g. "en:spreads").'))
|
|
176
|
+
.optional()
|
|
177
|
+
.describe('Category tag IDs in canonical form. Use as filter values for off_search_products.'),
|
|
178
|
+
labels_tags: z
|
|
179
|
+
.array(z.string().describe('Canonical label/certification tag ID (e.g. "en:organic").'))
|
|
180
|
+
.optional()
|
|
181
|
+
.describe('Label/certification tag IDs. Absence means not yet entered.'),
|
|
182
|
+
packaging_tags: z
|
|
183
|
+
.array(z.string().describe('Packaging material tag ID (e.g. "en:cardboard").'))
|
|
184
|
+
.optional()
|
|
185
|
+
.describe('Packaging material tag IDs. Often absent.'),
|
|
186
|
+
origins_tags: z
|
|
187
|
+
.array(z.string().describe('Ingredient origin tag ID (e.g. "en:france").'))
|
|
188
|
+
.optional()
|
|
189
|
+
.describe('Ingredient origin tag IDs. Frequently empty.'),
|
|
190
|
+
image_url: z.string().optional().describe('Front image URL (CDN-hosted JPEG).'),
|
|
191
|
+
completeness: z
|
|
192
|
+
.number()
|
|
193
|
+
.optional()
|
|
194
|
+
.describe('Data completeness score from 0–1. Below 0.5 indicates many fields are missing.'),
|
|
195
|
+
data_quality_tags: z
|
|
196
|
+
.array(z
|
|
197
|
+
.string()
|
|
198
|
+
.describe('Crowd-sourced data quality flag (e.g. "en:nutrition-completed", "en:ingredients-completed-at-least-for-one-language").'))
|
|
199
|
+
.optional()
|
|
200
|
+
.describe('Crowd-sourced data quality flags. Absence means not yet checked.'),
|
|
201
|
+
})
|
|
202
|
+
.optional()
|
|
203
|
+
.describe('Product data. Absent when found is false.'),
|
|
204
|
+
}),
|
|
205
|
+
errors: [
|
|
206
|
+
{
|
|
207
|
+
reason: 'not_found',
|
|
208
|
+
code: JsonRpcErrorCode.NotFound,
|
|
209
|
+
when: 'Barcode status:0 — not present in any contributor record',
|
|
210
|
+
recovery: 'Try off_search_products with the product name or brand to find the correct barcode, or check that the barcode digits are correct.',
|
|
211
|
+
},
|
|
212
|
+
{
|
|
213
|
+
reason: 'upstream_error',
|
|
214
|
+
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
215
|
+
when: 'Open Food Facts API returns 5xx or is unreachable',
|
|
216
|
+
retryable: true,
|
|
217
|
+
recovery: 'Retry after a brief pause. If persistent, the Open Food Facts service may be experiencing high load.',
|
|
218
|
+
},
|
|
219
|
+
],
|
|
220
|
+
async handler(input, ctx) {
|
|
221
|
+
const svc = getOpenFoodFactsService();
|
|
222
|
+
// When the caller requests a specific field subset, pass it to the service to scope the API
|
|
223
|
+
// request. The service has a default full-field set; using getProductFields() overrides it.
|
|
224
|
+
const product = input.fields && input.fields.length > 0
|
|
225
|
+
? await svc.getProductFields(input.barcode, input.fields.join(','), ctx)
|
|
226
|
+
: await svc.getProduct(input.barcode, ctx);
|
|
227
|
+
if (!product) {
|
|
228
|
+
throw ctx.fail('not_found', `Barcode ${input.barcode} not found in Open Food Facts`, {
|
|
229
|
+
barcode: input.barcode,
|
|
230
|
+
...ctx.recoveryFor('not_found'),
|
|
231
|
+
});
|
|
232
|
+
}
|
|
233
|
+
ctx.log.info('Product fetched', {
|
|
234
|
+
barcode: input.barcode,
|
|
235
|
+
product_name: product.product_name,
|
|
236
|
+
completeness: product.completeness,
|
|
237
|
+
});
|
|
238
|
+
const result = buildProductOutput(input.barcode, product);
|
|
239
|
+
return result;
|
|
240
|
+
},
|
|
241
|
+
format: (result) => {
|
|
242
|
+
if (!result.found || !result.product) {
|
|
243
|
+
return [
|
|
244
|
+
{
|
|
245
|
+
type: 'text',
|
|
246
|
+
text: `**Barcode ${result.barcode}** — Not found in Open Food Facts. No contributor has entered this product yet. Try off_search_products with the product name or brand.`,
|
|
247
|
+
},
|
|
248
|
+
];
|
|
249
|
+
}
|
|
250
|
+
const p = result.product;
|
|
251
|
+
const lines = [];
|
|
252
|
+
lines.push(`## ${p.product_name ?? 'Unknown product'}`);
|
|
253
|
+
lines.push(`**Barcode:** ${result.barcode} | **Found:** ${result.found}`);
|
|
254
|
+
if (p.brands)
|
|
255
|
+
lines.push(`**Brand:** ${p.brands}`);
|
|
256
|
+
if (p.quantity)
|
|
257
|
+
lines.push(`**Quantity:** ${p.quantity}`);
|
|
258
|
+
// Scores
|
|
259
|
+
const scores = [];
|
|
260
|
+
if (p.nutriscore_grade)
|
|
261
|
+
scores.push(`Nutri-Score: ${p.nutriscore_grade}`);
|
|
262
|
+
if (p.nova_group !== undefined)
|
|
263
|
+
scores.push(`NOVA: ${p.nova_group}`);
|
|
264
|
+
if (p.ecoscore_grade)
|
|
265
|
+
scores.push(`Eco-Score: ${p.ecoscore_grade}`);
|
|
266
|
+
if (scores.length > 0)
|
|
267
|
+
lines.push(`**Scores:** ${scores.join(' | ')}`);
|
|
268
|
+
// Nutrition
|
|
269
|
+
if (p.nutriments) {
|
|
270
|
+
const n = p.nutriments;
|
|
271
|
+
lines.push('\n### Nutrition per 100g');
|
|
272
|
+
if (n.energy_kcal_100g !== undefined)
|
|
273
|
+
lines.push(`**Energy:** ${n.energy_kcal_100g} kcal`);
|
|
274
|
+
if (n.fat_100g !== undefined)
|
|
275
|
+
lines.push(`**Fat:** ${n.fat_100g}g`);
|
|
276
|
+
if (n.saturated_fat_100g !== undefined)
|
|
277
|
+
lines.push(` - Saturated fat: ${n.saturated_fat_100g}g`);
|
|
278
|
+
if (n.carbohydrates_100g !== undefined)
|
|
279
|
+
lines.push(`**Carbohydrates:** ${n.carbohydrates_100g}g`);
|
|
280
|
+
if (n.sugars_100g !== undefined)
|
|
281
|
+
lines.push(` - Sugars: ${n.sugars_100g}g`);
|
|
282
|
+
if (n.fiber_100g !== undefined)
|
|
283
|
+
lines.push(`**Fiber:** ${n.fiber_100g}g`);
|
|
284
|
+
if (n.proteins_100g !== undefined)
|
|
285
|
+
lines.push(`**Protein:** ${n.proteins_100g}g`);
|
|
286
|
+
if (n.salt_100g !== undefined)
|
|
287
|
+
lines.push(`**Salt:** ${n.salt_100g}g`);
|
|
288
|
+
if (n.sodium_100g !== undefined)
|
|
289
|
+
lines.push(`**Sodium:** ${n.sodium_100g}g`);
|
|
290
|
+
if (n.energy_kcal_serving !== undefined ||
|
|
291
|
+
n.fat_serving !== undefined ||
|
|
292
|
+
n.sugars_serving !== undefined) {
|
|
293
|
+
lines.push('\n### Nutrition per serving');
|
|
294
|
+
if (n.energy_kcal_serving !== undefined)
|
|
295
|
+
lines.push(`**Energy:** ${n.energy_kcal_serving} kcal`);
|
|
296
|
+
if (n.fat_serving !== undefined)
|
|
297
|
+
lines.push(`**Fat:** ${n.fat_serving}g`);
|
|
298
|
+
if (n.sugars_serving !== undefined)
|
|
299
|
+
lines.push(`**Sugars:** ${n.sugars_serving}g`);
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
else {
|
|
303
|
+
lines.push('\n**Nutrition:** Not available');
|
|
304
|
+
}
|
|
305
|
+
// Ingredients — fenced to prevent crowd-sourced text from being interpreted as markdown/instructions
|
|
306
|
+
if (p.ingredients_text) {
|
|
307
|
+
lines.push(`\n### Ingredients\n\`\`\`\n${p.ingredients_text}\n\`\`\``);
|
|
308
|
+
}
|
|
309
|
+
else {
|
|
310
|
+
lines.push('\n**Ingredients:** Not available');
|
|
311
|
+
}
|
|
312
|
+
if (p.ingredients && p.ingredients.length > 0) {
|
|
313
|
+
lines.push('\n**Parsed ingredients:**');
|
|
314
|
+
for (const ing of p.ingredients.slice(0, 20)) {
|
|
315
|
+
const attrs = [];
|
|
316
|
+
if (ing.id)
|
|
317
|
+
attrs.push(`id: ${ing.id}`);
|
|
318
|
+
if (ing.percent_estimate !== undefined)
|
|
319
|
+
attrs.push(`~${ing.percent_estimate.toFixed(1)}%`);
|
|
320
|
+
if (ing.vegan && ing.vegan !== 'maybe')
|
|
321
|
+
attrs.push(`vegan: ${ing.vegan}`);
|
|
322
|
+
if (ing.vegetarian && ing.vegetarian !== 'maybe')
|
|
323
|
+
attrs.push(`vegetarian: ${ing.vegetarian}`);
|
|
324
|
+
lines.push(`- ${ing.text}${attrs.length > 0 ? ` (${attrs.join(', ')})` : ''}`);
|
|
325
|
+
}
|
|
326
|
+
if (p.ingredients.length > 20) {
|
|
327
|
+
lines.push(`- *(${p.ingredients.length - 20} more ingredients)*`);
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
// Allergens
|
|
331
|
+
if (p.allergens_tags && p.allergens_tags.length > 0) {
|
|
332
|
+
lines.push(`\n**Allergens:** ${p.allergens_tags.join(', ')}`);
|
|
333
|
+
}
|
|
334
|
+
else {
|
|
335
|
+
lines.push('\n**Allergens:** Not entered (absence does not mean allergen-free)');
|
|
336
|
+
}
|
|
337
|
+
// Additives
|
|
338
|
+
if (p.additives_tags && p.additives_tags.length > 0) {
|
|
339
|
+
lines.push(`**Additives:** ${p.additives_tags.join(', ')}`);
|
|
340
|
+
}
|
|
341
|
+
// Data quality
|
|
342
|
+
if (p.data_quality_tags && p.data_quality_tags.length > 0) {
|
|
343
|
+
lines.push(`**Data quality tags:** ${p.data_quality_tags.join(', ')}`);
|
|
344
|
+
}
|
|
345
|
+
// Categories / labels
|
|
346
|
+
if (p.categories_tags && p.categories_tags.length > 0) {
|
|
347
|
+
lines.push(`\n**Categories:** ${p.categories_tags.slice(0, 5).join(', ')}`);
|
|
348
|
+
}
|
|
349
|
+
if (p.labels_tags && p.labels_tags.length > 0) {
|
|
350
|
+
lines.push(`**Labels:** ${p.labels_tags.join(', ')}`);
|
|
351
|
+
}
|
|
352
|
+
if (p.packaging_tags && p.packaging_tags.length > 0) {
|
|
353
|
+
lines.push(`**Packaging:** ${p.packaging_tags.join(', ')}`);
|
|
354
|
+
}
|
|
355
|
+
if (p.origins_tags && p.origins_tags.length > 0) {
|
|
356
|
+
lines.push(`**Origins:** ${p.origins_tags.join(', ')}`);
|
|
357
|
+
}
|
|
358
|
+
// Image
|
|
359
|
+
if (p.image_url)
|
|
360
|
+
lines.push(`\n**Image:** ${p.image_url}`);
|
|
361
|
+
// Completeness
|
|
362
|
+
if (p.completeness !== undefined) {
|
|
363
|
+
lines.push(`\n**Data completeness:** ${completenessLabel(p.completeness)}`);
|
|
364
|
+
}
|
|
365
|
+
lines.push('\n*Data: Open Food Facts (ODbL 1.0) — crowd-sourced. Missing fields = not yet entered.*');
|
|
366
|
+
return [{ type: 'text', text: lines.join('\n') }];
|
|
367
|
+
},
|
|
368
|
+
});
|
|
369
|
+
/** Build the normalized output object from a raw product. */
|
|
370
|
+
function buildProductOutput(barcode, raw) {
|
|
371
|
+
const product = {};
|
|
372
|
+
if (raw.product_name)
|
|
373
|
+
product.product_name = raw.product_name;
|
|
374
|
+
if (raw.brands)
|
|
375
|
+
product.brands = raw.brands;
|
|
376
|
+
if (raw.quantity)
|
|
377
|
+
product.quantity = raw.quantity;
|
|
378
|
+
if (raw.ingredients_text)
|
|
379
|
+
product.ingredients_text = raw.ingredients_text;
|
|
380
|
+
if (raw.ingredients && raw.ingredients.length > 0) {
|
|
381
|
+
product.ingredients = raw.ingredients.map((ing) => ({
|
|
382
|
+
...(ing.id && { id: ing.id }),
|
|
383
|
+
text: ing.text ?? '',
|
|
384
|
+
...(typeof ing.percent_estimate === 'number' && {
|
|
385
|
+
percent_estimate: ing.percent_estimate,
|
|
386
|
+
}),
|
|
387
|
+
...(ing.vegan && { vegan: ing.vegan }),
|
|
388
|
+
...(ing.vegetarian && { vegetarian: ing.vegetarian }),
|
|
389
|
+
}));
|
|
390
|
+
}
|
|
391
|
+
if (raw.allergens_tags)
|
|
392
|
+
product.allergens_tags = raw.allergens_tags;
|
|
393
|
+
if (raw.additives_tags)
|
|
394
|
+
product.additives_tags = raw.additives_tags;
|
|
395
|
+
if (raw.nutriscore_grade)
|
|
396
|
+
product.nutriscore_grade = raw.nutriscore_grade;
|
|
397
|
+
if (typeof raw.nova_group === 'number')
|
|
398
|
+
product.nova_group = raw.nova_group;
|
|
399
|
+
if (raw.ecoscore_grade)
|
|
400
|
+
product.ecoscore_grade = raw.ecoscore_grade;
|
|
401
|
+
const nutriments = normalizeNutriments(raw.nutriments);
|
|
402
|
+
if (nutriments)
|
|
403
|
+
product.nutriments = nutriments;
|
|
404
|
+
if (raw.categories_tags)
|
|
405
|
+
product.categories_tags = raw.categories_tags;
|
|
406
|
+
if (raw.labels_tags)
|
|
407
|
+
product.labels_tags = raw.labels_tags;
|
|
408
|
+
if (raw.packaging_tags)
|
|
409
|
+
product.packaging_tags = raw.packaging_tags;
|
|
410
|
+
if (raw.origins_tags)
|
|
411
|
+
product.origins_tags = raw.origins_tags;
|
|
412
|
+
if (raw.image_url)
|
|
413
|
+
product.image_url = raw.image_url;
|
|
414
|
+
if (typeof raw.completeness === 'number')
|
|
415
|
+
product.completeness = raw.completeness;
|
|
416
|
+
if (raw.data_quality_tags)
|
|
417
|
+
product.data_quality_tags = raw.data_quality_tags;
|
|
418
|
+
return { barcode, found: true, product };
|
|
419
|
+
}
|
|
420
|
+
//# sourceMappingURL=get-product.tool.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get-product.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/get-product.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Barrel export for all Open Food Facts tool definitions.
|
|
3
|
+
* @module mcp-server/tools/definitions
|
|
4
|
+
*/
|
|
5
|
+
export declare const allToolDefinitions: (import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
6
|
+
facet: import("zod").ZodEnum<{
|
|
7
|
+
categories: "categories";
|
|
8
|
+
labels: "labels";
|
|
9
|
+
allergens: "allergens";
|
|
10
|
+
additives: "additives";
|
|
11
|
+
countries: "countries";
|
|
12
|
+
nova_groups: "nova_groups";
|
|
13
|
+
nutrition_grades: "nutrition_grades";
|
|
14
|
+
}>;
|
|
15
|
+
search: import("zod").ZodOptional<import("zod").ZodString>;
|
|
16
|
+
limit: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
17
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
18
|
+
facet: import("zod").ZodString;
|
|
19
|
+
tags: import("zod").ZodArray<import("zod").ZodObject<{
|
|
20
|
+
id: import("zod").ZodString;
|
|
21
|
+
name: import("zod").ZodString;
|
|
22
|
+
products: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
23
|
+
}, import("zod/v4/core").$strip>>;
|
|
24
|
+
total_in_facet: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
25
|
+
}, import("zod/v4/core").$strip>, undefined, undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
26
|
+
barcodes: import("zod").ZodArray<import("zod").ZodString>;
|
|
27
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
28
|
+
products: import("zod").ZodArray<import("zod").ZodObject<{
|
|
29
|
+
barcode: import("zod").ZodString;
|
|
30
|
+
product_name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
31
|
+
brands: import("zod").ZodOptional<import("zod").ZodString>;
|
|
32
|
+
found: import("zod").ZodBoolean;
|
|
33
|
+
nutriscore_grade: import("zod").ZodOptional<import("zod").ZodString>;
|
|
34
|
+
nova_group: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
35
|
+
ecoscore_grade: import("zod").ZodOptional<import("zod").ZodString>;
|
|
36
|
+
energy_kcal_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
37
|
+
fat_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
38
|
+
saturated_fat_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
39
|
+
sugars_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
40
|
+
salt_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
41
|
+
proteins_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
42
|
+
fiber_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
43
|
+
completeness: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
44
|
+
}, import("zod/v4/core").$strip>>;
|
|
45
|
+
succeeded: import("zod").ZodNumber;
|
|
46
|
+
not_found: import("zod").ZodArray<import("zod").ZodString>;
|
|
47
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
48
|
+
readonly reason: "upstream_error";
|
|
49
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
50
|
+
readonly when: "Open Food Facts API returns 5xx or is unreachable for one or more barcodes";
|
|
51
|
+
readonly retryable: true;
|
|
52
|
+
readonly recovery: "Retry after a brief pause. Partial failures surface individual barcodes in not_found — verify those barcodes with off_get_product.";
|
|
53
|
+
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
54
|
+
barcode: import("zod").ZodString;
|
|
55
|
+
fields: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodEnum<{
|
|
56
|
+
categories_tags: "categories_tags";
|
|
57
|
+
labels_tags: "labels_tags";
|
|
58
|
+
product_name: "product_name";
|
|
59
|
+
brands: "brands";
|
|
60
|
+
quantity: "quantity";
|
|
61
|
+
ingredients_text: "ingredients_text";
|
|
62
|
+
ingredients: "ingredients";
|
|
63
|
+
allergens_tags: "allergens_tags";
|
|
64
|
+
additives_tags: "additives_tags";
|
|
65
|
+
nutriscore_grade: "nutriscore_grade";
|
|
66
|
+
nova_group: "nova_group";
|
|
67
|
+
ecoscore_grade: "ecoscore_grade";
|
|
68
|
+
nutriments: "nutriments";
|
|
69
|
+
packaging_tags: "packaging_tags";
|
|
70
|
+
origins_tags: "origins_tags";
|
|
71
|
+
image_url: "image_url";
|
|
72
|
+
completeness: "completeness";
|
|
73
|
+
data_quality_tags: "data_quality_tags";
|
|
74
|
+
}>>>;
|
|
75
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
76
|
+
barcode: import("zod").ZodString;
|
|
77
|
+
found: import("zod").ZodBoolean;
|
|
78
|
+
product: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
79
|
+
product_name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
80
|
+
brands: import("zod").ZodOptional<import("zod").ZodString>;
|
|
81
|
+
quantity: import("zod").ZodOptional<import("zod").ZodString>;
|
|
82
|
+
ingredients_text: import("zod").ZodOptional<import("zod").ZodString>;
|
|
83
|
+
ingredients: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodObject<{
|
|
84
|
+
id: import("zod").ZodOptional<import("zod").ZodString>;
|
|
85
|
+
text: import("zod").ZodString;
|
|
86
|
+
percent_estimate: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
87
|
+
vegan: import("zod").ZodOptional<import("zod").ZodString>;
|
|
88
|
+
vegetarian: import("zod").ZodOptional<import("zod").ZodString>;
|
|
89
|
+
}, import("zod/v4/core").$strip>>>;
|
|
90
|
+
allergens_tags: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
91
|
+
additives_tags: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
92
|
+
nutriscore_grade: import("zod").ZodOptional<import("zod").ZodString>;
|
|
93
|
+
nova_group: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
94
|
+
ecoscore_grade: import("zod").ZodOptional<import("zod").ZodString>;
|
|
95
|
+
nutriments: import("zod").ZodOptional<import("zod").ZodObject<{
|
|
96
|
+
energy_kcal_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
97
|
+
fat_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
98
|
+
saturated_fat_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
99
|
+
carbohydrates_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
100
|
+
sugars_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
101
|
+
fiber_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
102
|
+
proteins_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
103
|
+
salt_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
104
|
+
sodium_100g: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
105
|
+
energy_kcal_serving: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
106
|
+
fat_serving: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
107
|
+
sugars_serving: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
108
|
+
}, import("zod/v4/core").$strip>>;
|
|
109
|
+
categories_tags: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
110
|
+
labels_tags: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
111
|
+
packaging_tags: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
112
|
+
origins_tags: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
113
|
+
image_url: import("zod").ZodOptional<import("zod").ZodString>;
|
|
114
|
+
completeness: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
115
|
+
data_quality_tags: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
116
|
+
}, import("zod/v4/core").$strip>>;
|
|
117
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
118
|
+
readonly reason: "not_found";
|
|
119
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.NotFound;
|
|
120
|
+
readonly when: "Barcode status:0 — not present in any contributor record";
|
|
121
|
+
readonly recovery: "Try off_search_products with the product name or brand to find the correct barcode, or check that the barcode digits are correct.";
|
|
122
|
+
}, {
|
|
123
|
+
readonly reason: "upstream_error";
|
|
124
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
125
|
+
readonly when: "Open Food Facts API returns 5xx or is unreachable";
|
|
126
|
+
readonly retryable: true;
|
|
127
|
+
readonly recovery: "Retry after a brief pause. If persistent, the Open Food Facts service may be experiencing high load.";
|
|
128
|
+
}], undefined> | import("@cyanheads/mcp-ts-core").ToolDefinition<import("zod").ZodObject<{
|
|
129
|
+
query: import("zod").ZodOptional<import("zod").ZodString>;
|
|
130
|
+
categories_tag: import("zod").ZodOptional<import("zod").ZodString>;
|
|
131
|
+
brands_tag: import("zod").ZodOptional<import("zod").ZodString>;
|
|
132
|
+
labels_tag: import("zod").ZodOptional<import("zod").ZodString>;
|
|
133
|
+
nutrition_grade: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
134
|
+
a: "a";
|
|
135
|
+
b: "b";
|
|
136
|
+
c: "c";
|
|
137
|
+
d: "d";
|
|
138
|
+
e: "e";
|
|
139
|
+
}>>;
|
|
140
|
+
nova_group: import("zod").ZodOptional<import("zod").ZodEnum<{
|
|
141
|
+
1: "1";
|
|
142
|
+
2: "2";
|
|
143
|
+
3: "3";
|
|
144
|
+
4: "4";
|
|
145
|
+
}>>;
|
|
146
|
+
countries_tag: import("zod").ZodOptional<import("zod").ZodString>;
|
|
147
|
+
page: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
148
|
+
page_size: import("zod").ZodDefault<import("zod").ZodNumber>;
|
|
149
|
+
}, import("zod/v4/core").$strip>, import("zod").ZodObject<{
|
|
150
|
+
total: import("zod").ZodNumber;
|
|
151
|
+
page: import("zod").ZodNumber;
|
|
152
|
+
page_count: import("zod").ZodNumber;
|
|
153
|
+
products: import("zod").ZodArray<import("zod").ZodObject<{
|
|
154
|
+
barcode: import("zod").ZodString;
|
|
155
|
+
product_name: import("zod").ZodOptional<import("zod").ZodString>;
|
|
156
|
+
brands: import("zod").ZodOptional<import("zod").ZodString>;
|
|
157
|
+
nutriscore_grade: import("zod").ZodOptional<import("zod").ZodString>;
|
|
158
|
+
nova_group: import("zod").ZodOptional<import("zod").ZodNumber>;
|
|
159
|
+
categories_tags: import("zod").ZodOptional<import("zod").ZodArray<import("zod").ZodString>>;
|
|
160
|
+
}, import("zod/v4/core").$strip>>;
|
|
161
|
+
}, import("zod/v4/core").$strip>, readonly [{
|
|
162
|
+
readonly reason: "no_filters";
|
|
163
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.InvalidParams;
|
|
164
|
+
readonly when: "No search query or filter was provided";
|
|
165
|
+
readonly recovery: "Provide at least one of: query, categories_tag, brands_tag, labels_tag, nutrition_grade, nova_group, or countries_tag.";
|
|
166
|
+
}, {
|
|
167
|
+
readonly reason: "upstream_error";
|
|
168
|
+
readonly code: import("@cyanheads/mcp-ts-core/errors").JsonRpcErrorCode.ServiceUnavailable;
|
|
169
|
+
readonly when: "Open Food Facts API returns 5xx or is unreachable";
|
|
170
|
+
readonly retryable: true;
|
|
171
|
+
readonly recovery: "Retry after a brief pause. The Open Food Facts service may be rate-limiting or experiencing high load.";
|
|
172
|
+
}], {
|
|
173
|
+
readonly notice: import("zod").ZodOptional<import("zod").ZodString>;
|
|
174
|
+
}>)[];
|
|
175
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;KAK9B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Barrel export for all Open Food Facts tool definitions.
|
|
3
|
+
* @module mcp-server/tools/definitions
|
|
4
|
+
*/
|
|
5
|
+
import { offBrowseTaxonomyTool } from './browse-taxonomy.tool.js';
|
|
6
|
+
import { offCompareProductsTool } from './compare-products.tool.js';
|
|
7
|
+
import { offGetProductTool } from './get-product.tool.js';
|
|
8
|
+
import { offSearchProductsTool } from './search-products.tool.js';
|
|
9
|
+
export const allToolDefinitions = [
|
|
10
|
+
offGetProductTool,
|
|
11
|
+
offSearchProductsTool,
|
|
12
|
+
offCompareProductsTool,
|
|
13
|
+
offBrowseTaxonomyTool,
|
|
14
|
+
];
|
|
15
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/index.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAAE,sBAAsB,EAAE,MAAM,4BAA4B,CAAC;AACpE,OAAO,EAAE,iBAAiB,EAAE,MAAM,uBAAuB,CAAC;AAC1D,OAAO,EAAE,qBAAqB,EAAE,MAAM,2BAA2B,CAAC;AAElE,MAAM,CAAC,MAAM,kBAAkB,GAAG;IAChC,iBAAiB;IACjB,qBAAqB;IACrB,sBAAsB;IACtB,qBAAqB;CACtB,CAAC"}
|