@cyanheads/openfoodfacts-mcp-server 0.3.4 → 0.3.6
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 +12 -9
- package/CLAUDE.md +12 -9
- package/Dockerfile +1 -1
- package/README.md +15 -12
- package/changelog/0.3.x/0.3.5.md +24 -0
- package/changelog/0.3.x/0.3.6.md +26 -0
- package/changelog/template.md +7 -7
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.d.ts +0 -1
- package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.js +2 -7
- package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/compare-products.tool.d.ts +2 -2
- package/dist/mcp-server/tools/definitions/compare-products.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/compare-products.tool.js +10 -9
- package/dist/mcp-server/tools/definitions/compare-products.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/get-product.tool.d.ts +21 -2
- package/dist/mcp-server/tools/definitions/get-product.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/get-product.tool.js +112 -54
- package/dist/mcp-server/tools/definitions/get-product.tool.js.map +1 -1
- package/dist/mcp-server/tools/definitions/index.d.ts +70 -12
- package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-products.tool.d.ts +47 -7
- package/dist/mcp-server/tools/definitions/search-products.tool.d.ts.map +1 -1
- package/dist/mcp-server/tools/definitions/search-products.tool.js +369 -91
- package/dist/mcp-server/tools/definitions/search-products.tool.js.map +1 -1
- package/dist/services/openfoodfacts/analyzer-stop-words.d.ts +70 -0
- package/dist/services/openfoodfacts/analyzer-stop-words.d.ts.map +1 -0
- package/dist/services/openfoodfacts/analyzer-stop-words.js +571 -0
- package/dist/services/openfoodfacts/analyzer-stop-words.js.map +1 -0
- package/dist/services/openfoodfacts/openfoodfacts-service.d.ts +93 -20
- package/dist/services/openfoodfacts/openfoodfacts-service.d.ts.map +1 -1
- package/dist/services/openfoodfacts/openfoodfacts-service.js +338 -91
- package/dist/services/openfoodfacts/openfoodfacts-service.js.map +1 -1
- package/dist/services/openfoodfacts/types.d.ts +72 -6
- package/dist/services/openfoodfacts/types.d.ts.map +1 -1
- package/dist/services/openfoodfacts/types.js +31 -0
- package/dist/services/openfoodfacts/types.js.map +1 -1
- package/dist/services/taxonomy/taxonomy-service.d.ts +79 -1
- package/dist/services/taxonomy/taxonomy-service.d.ts.map +1 -1
- package/dist/services/taxonomy/taxonomy-service.js +179 -7
- package/dist/services/taxonomy/taxonomy-service.js.map +1 -1
- package/package.json +6 -6
- package/server.json +5 -5
package/AGENTS.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** openfoodfacts-mcp-server
|
|
4
|
-
**Version:** 0.3.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 0.3.6
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.6`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/server` ^2.0.0
|
|
8
8
|
**Zod:** ^4.6.5
|
|
@@ -32,17 +32,18 @@
|
|
|
32
32
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
33
33
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
34
34
|
import { getOpenFoodFactsService } from '@/services/openfoodfacts/openfoodfacts-service.js';
|
|
35
|
+
import { BARCODE_PATTERN } from '@/services/openfoodfacts/types.js';
|
|
35
36
|
|
|
36
37
|
export const offGetProduct = tool('off_get_product', {
|
|
37
|
-
description: 'Fetch a packaged food product by barcode (
|
|
38
|
+
description: 'Fetch a packaged food product by barcode (4–40 digits).',
|
|
38
39
|
annotations: { readOnlyHint: true },
|
|
39
40
|
input: z.object({
|
|
40
|
-
barcode: z.string().regex(
|
|
41
|
+
barcode: z.string().regex(BARCODE_PATTERN).describe('Product barcode, digits only: 4–40 digits after any leading zeros.'),
|
|
41
42
|
fields: z.array(z.enum(['product_name', 'brands', 'nutriscore_grade', 'nutriments'])).optional()
|
|
42
43
|
.describe('Subset of fields to return. Omitting returns all standard fields.'),
|
|
43
44
|
}),
|
|
44
45
|
output: z.object({
|
|
45
|
-
barcode: z.string().describe('
|
|
46
|
+
barcode: z.string().describe('The input barcode, echoed back unchanged.'),
|
|
46
47
|
// No `found` flag: a missing record is the thrown not_found error, so a boolean here could
|
|
47
48
|
// only ever be true. Don't advertise a state the handler cannot return — a caller that
|
|
48
49
|
// branches on it never handles the path that actually fires.
|
|
@@ -60,7 +61,9 @@ export const offGetProduct = tool('off_get_product', {
|
|
|
60
61
|
async handler(input, ctx) {
|
|
61
62
|
const svc = getOpenFoodFactsService();
|
|
62
63
|
const product = await svc.getProduct(input.barcode, ctx);
|
|
63
|
-
if (!product)
|
|
64
|
+
if (!product) {
|
|
65
|
+
throw ctx.fail('not_found', `Barcode ${input.barcode} not found`, ctx.recoveryFor('not_found'));
|
|
66
|
+
}
|
|
64
67
|
return { barcode: input.barcode, product };
|
|
65
68
|
},
|
|
66
69
|
|
|
@@ -143,7 +146,7 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
143
146
|
|
|
144
147
|
Handlers throw — the framework catches, classifies, and formats.
|
|
145
148
|
|
|
146
|
-
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire (`data.recovery.hint`, mirrored into `content[]` text); override with an explicit `{ recovery: { hint: '...' } }` when dynamic runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`, `RequestCancelled`) bubble freely and don't need declaring.
|
|
149
|
+
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable?, severity?, thrownBy? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire (`data.recovery.hint`, mirrored into `content[]` text unless the message already contains it verbatim); override with an explicit `{ recovery: { hint: '...' } }` when dynamic runtime context matters. Forwarding it is lint-enforced per throw site (`error-contract-recovery-unforwarded`). Mark an entry the service layer throws with `thrownBy: 'service'` so `error-contract-unthrown` skips it — lint-only metadata, nothing at runtime reads it. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`, `RequestCancelled`) bubble freely and don't need declaring.
|
|
147
150
|
|
|
148
151
|
```ts
|
|
149
152
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
@@ -195,7 +198,7 @@ src/
|
|
|
195
198
|
openfoodfacts-service.ts # Open Food Facts API client (HTTP, rate limiting, retry)
|
|
196
199
|
types.ts # Domain types
|
|
197
200
|
taxonomy/
|
|
198
|
-
taxonomy-service.ts # Tag vocabulary — live resolution, offline sample, merge/fallback policy
|
|
201
|
+
taxonomy-service.ts # Tag vocabulary — live resolution, offline sample, merge/fallback policy, tag-value canonicalization
|
|
199
202
|
utils/
|
|
200
203
|
markdown.ts # Contextual Markdown escaping for crowd-sourced values in content[]
|
|
201
204
|
mcp-server/
|
|
@@ -244,7 +247,7 @@ Available skills:
|
|
|
244
247
|
| `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
|
|
245
248
|
| `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
|
|
246
249
|
| `git-wrapup` | Land working-tree changes as a commit stack — version bump, changelog, verify, commit by concern, release commit on top. No tag, no push to main; opens the release PR when the project declares release PR mode |
|
|
247
|
-
| `release-pr-review` | Review pass on an open release PR — simplifier + correctness review,
|
|
250
|
+
| `release-pr-review` | Review pass on an open release PR — simplifier + correctness review, fixes as ordinary commits on top of the stack, PR body kept in sync. Release PR mode only |
|
|
248
251
|
| `release-and-publish` | Fast-forward merge (release PR mode) + tag + push + npm + MCP Registry + GH Release + Docker. Picks up from `git-wrapup` |
|
|
249
252
|
| `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
|
|
250
253
|
| `orchestrations` | Chain task skills into a gated multi-phase pipeline — build-out, QA-fix, update-ship — when you can spawn sub-agents |
|
package/CLAUDE.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Developer Protocol
|
|
2
2
|
|
|
3
3
|
**Server:** openfoodfacts-mcp-server
|
|
4
|
-
**Version:** 0.3.
|
|
5
|
-
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.
|
|
4
|
+
**Version:** 0.3.6
|
|
5
|
+
**Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.6`
|
|
6
6
|
**Engines:** Bun ≥1.4.0, Node ≥24.0.0
|
|
7
7
|
**MCP SDK:** `@modelcontextprotocol/server` ^2.0.0
|
|
8
8
|
**Zod:** ^4.6.5
|
|
@@ -32,17 +32,18 @@
|
|
|
32
32
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
33
33
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
34
34
|
import { getOpenFoodFactsService } from '@/services/openfoodfacts/openfoodfacts-service.js';
|
|
35
|
+
import { BARCODE_PATTERN } from '@/services/openfoodfacts/types.js';
|
|
35
36
|
|
|
36
37
|
export const offGetProduct = tool('off_get_product', {
|
|
37
|
-
description: 'Fetch a packaged food product by barcode (
|
|
38
|
+
description: 'Fetch a packaged food product by barcode (4–40 digits).',
|
|
38
39
|
annotations: { readOnlyHint: true },
|
|
39
40
|
input: z.object({
|
|
40
|
-
barcode: z.string().regex(
|
|
41
|
+
barcode: z.string().regex(BARCODE_PATTERN).describe('Product barcode, digits only: 4–40 digits after any leading zeros.'),
|
|
41
42
|
fields: z.array(z.enum(['product_name', 'brands', 'nutriscore_grade', 'nutriments'])).optional()
|
|
42
43
|
.describe('Subset of fields to return. Omitting returns all standard fields.'),
|
|
43
44
|
}),
|
|
44
45
|
output: z.object({
|
|
45
|
-
barcode: z.string().describe('
|
|
46
|
+
barcode: z.string().describe('The input barcode, echoed back unchanged.'),
|
|
46
47
|
// No `found` flag: a missing record is the thrown not_found error, so a boolean here could
|
|
47
48
|
// only ever be true. Don't advertise a state the handler cannot return — a caller that
|
|
48
49
|
// branches on it never handles the path that actually fires.
|
|
@@ -60,7 +61,9 @@ export const offGetProduct = tool('off_get_product', {
|
|
|
60
61
|
async handler(input, ctx) {
|
|
61
62
|
const svc = getOpenFoodFactsService();
|
|
62
63
|
const product = await svc.getProduct(input.barcode, ctx);
|
|
63
|
-
if (!product)
|
|
64
|
+
if (!product) {
|
|
65
|
+
throw ctx.fail('not_found', `Barcode ${input.barcode} not found`, ctx.recoveryFor('not_found'));
|
|
66
|
+
}
|
|
64
67
|
return { barcode: input.barcode, product };
|
|
65
68
|
},
|
|
66
69
|
|
|
@@ -143,7 +146,7 @@ Handlers receive a unified `ctx` object. Key properties:
|
|
|
143
146
|
|
|
144
147
|
Handlers throw — the framework catches, classifies, and formats.
|
|
145
148
|
|
|
146
|
-
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire (`data.recovery.hint`, mirrored into `content[]` text); override with an explicit `{ recovery: { hint: '...' } }` when dynamic runtime context matters. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`, `RequestCancelled`) bubble freely and don't need declaring.
|
|
149
|
+
**Recommended: typed error contract.** Declare `errors: [{ reason, code, when, recovery, retryable?, severity?, thrownBy? }]` on `tool()` / `resource()` to receive `ctx.fail(reason, …)` typed against the reason union. TypeScript catches typos at compile time, `data.reason` is auto-populated for observability, linter enforces conformance against the handler body. `recovery` is required (≥ 5 words, lint-validated) — the single source of truth for the agent's next move. Pass `ctx.recoveryFor('reason')` as the throw's data to put it on the wire (`data.recovery.hint`, mirrored into `content[]` text unless the message already contains it verbatim); override with an explicit `{ recovery: { hint: '...' } }` when dynamic runtime context matters. Forwarding it is lint-enforced per throw site (`error-contract-recovery-unforwarded`). Mark an entry the service layer throws with `thrownBy: 'service'` so `error-contract-unthrown` skips it — lint-only metadata, nothing at runtime reads it. Baseline codes (`InternalError`, `ServiceUnavailable`, `Timeout`, `ValidationError`, `SerializationError`, `RequestCancelled`) bubble freely and don't need declaring.
|
|
147
150
|
|
|
148
151
|
```ts
|
|
149
152
|
import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
|
|
@@ -195,7 +198,7 @@ src/
|
|
|
195
198
|
openfoodfacts-service.ts # Open Food Facts API client (HTTP, rate limiting, retry)
|
|
196
199
|
types.ts # Domain types
|
|
197
200
|
taxonomy/
|
|
198
|
-
taxonomy-service.ts # Tag vocabulary — live resolution, offline sample, merge/fallback policy
|
|
201
|
+
taxonomy-service.ts # Tag vocabulary — live resolution, offline sample, merge/fallback policy, tag-value canonicalization
|
|
199
202
|
utils/
|
|
200
203
|
markdown.ts # Contextual Markdown escaping for crowd-sourced values in content[]
|
|
201
204
|
mcp-server/
|
|
@@ -244,7 +247,7 @@ Available skills:
|
|
|
244
247
|
| `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
|
|
245
248
|
| `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
|
|
246
249
|
| `git-wrapup` | Land working-tree changes as a commit stack — version bump, changelog, verify, commit by concern, release commit on top. No tag, no push to main; opens the release PR when the project declares release PR mode |
|
|
247
|
-
| `release-pr-review` | Review pass on an open release PR — simplifier + correctness review,
|
|
250
|
+
| `release-pr-review` | Review pass on an open release PR — simplifier + correctness review, fixes as ordinary commits on top of the stack, PR body kept in sync. Release PR mode only |
|
|
248
251
|
| `release-and-publish` | Fast-forward merge (release PR mode) + tag + push + npm + MCP Registry + GH Release + Docker. Picks up from `git-wrapup` |
|
|
249
252
|
| `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
|
|
250
253
|
| `orchestrations` | Chain task skills into a gated multi-phase pipeline — build-out, QA-fix, update-ship — when you can spawn sub-agents |
|
package/Dockerfile
CHANGED
|
@@ -43,7 +43,7 @@ ARG APP_VERSION
|
|
|
43
43
|
|
|
44
44
|
# OCI image metadata (https://github.com/opencontainers/image-spec/blob/main/annotations.md)
|
|
45
45
|
LABEL org.opencontainers.image.title="openfoodfacts-mcp-server"
|
|
46
|
-
LABEL org.opencontainers.image.description="Look up food products by barcode, search by
|
|
46
|
+
LABEL org.opencontainers.image.description="Look up food products by barcode, search by keyword, tag, allergen, or nutrition filter, compare products side-by-side, and browse the canonical tag vocabulary via MCP. STDIO or Streamable HTTP."
|
|
47
47
|
LABEL org.opencontainers.image.licenses="Apache-2.0"
|
|
48
48
|
LABEL org.opencontainers.image.source="https://github.com/cyanheads/openfoodfacts-mcp-server"
|
|
49
49
|
LABEL org.opencontainers.image.version="${APP_VERSION}"
|
package/README.md
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
<div align="center">
|
|
2
2
|
<h1>@cyanheads/openfoodfacts-mcp-server</h1>
|
|
3
|
-
<p><b>Look up food products by barcode, search by
|
|
3
|
+
<p><b>Look up food products by barcode, search by keyword, tag, allergen, or nutrition filter, compare products side-by-side, and browse the canonical tag vocabulary via MCP. STDIO or Streamable HTTP.</b>
|
|
4
4
|
<div>4 Tools</div>
|
|
5
5
|
</p>
|
|
6
6
|
</div>
|
|
7
7
|
|
|
8
8
|
<div align="center">
|
|
9
9
|
|
|
10
|
-
[](./CHANGELOG.md) [](./LICENSE) [](https://github.com/users/cyanheads/packages/container/package/openfoodfacts-mcp-server) [](https://modelcontextprotocol.io/) [](https://www.npmjs.com/package/@cyanheads/openfoodfacts-mcp-server) [](https://www.typescriptlang.org/) [](https://bun.sh/)
|
|
11
11
|
|
|
12
12
|
</div>
|
|
13
13
|
|
|
@@ -36,7 +36,7 @@ Food product data from Open Food Facts, a crowd-sourced database of 3M+ packaged
|
|
|
36
36
|
| Tool | Description |
|
|
37
37
|
|:-----|:------------|
|
|
38
38
|
| `off_get_product` | Fetch a packaged food product by barcode. Returns name, brand, quantity, ingredients, declared and trace allergens, additives, the vegan/vegetarian/palm-oil analysis, Nutri-Score, NOVA group, Green-Score, nutrition per 100g/serving, categories, labels, countries of sale, and data completeness. |
|
|
39
|
-
| `off_search_products` | Search by text query, structured tag filters (category, brand,
|
|
39
|
+
| `off_search_products` | Search by text query, structured tag filters (category, brand, labels, allergen, trace, vegan/vegetarian/palm-oil verdict, additive, Nutri-Score grade, NOVA group, country), allergen and trace exclusions, and numeric per-100 g nutrient thresholds. Returns summary rows with barcodes for follow-up lookups. |
|
|
40
40
|
| `off_compare_products` | Side-by-side nutrition and scoring comparison for 2–10 products by barcode. Returns a normalized table of energy, macros, salt, Nutri-Score, NOVA, and Green-Score. |
|
|
41
41
|
| `off_browse_taxonomy` | Resolve a human term to the canonical tag ID (categories, labels, allergens, additives, countries, NOVA groups, Nutri-Score grades) that `off_search_products` filters on, against the live Open Food Facts taxonomy. |
|
|
42
42
|
|
|
@@ -44,8 +44,8 @@ Food product data from Open Food Facts, a crowd-sourced database of 3M+ packaged
|
|
|
44
44
|
|
|
45
45
|
### `off_get_product` <sub>tool</sub>
|
|
46
46
|
|
|
47
|
-
- Accepts
|
|
48
|
-
- Returns ingredients (raw text and parsed list with percent estimates, vegan/vegetarian flags), all 14 major allergens as tag IDs, E-number additives, Nutri-Score a
|
|
47
|
+
- Accepts every barcode Open Food Facts serves: digits only, 4–40 digits after any leading zeros — EAN-13, EAN-8, UPC-A, UPC-E, and the shorter and longer codes the database also holds
|
|
48
|
+
- Returns ingredients (raw text and parsed list with percent estimates, vegan/vegetarian flags, and each entry's sub-ingredients nested under it — wheat flour under "cereal", palm oil under "vegetable oils" — up to three levels deep), all 14 major allergens as tag IDs, E-number additives, Nutri-Score (`a`–`e`, `unknown`, `not-applicable`), NOVA 1–4, Green-Score (`a-plus`, `a`–`f`, `unknown`, `not-applicable`), every nutrient Open Food Facts holds per 100g and per serving, the serving size those per-serving figures are measured against, categories/labels/packaging/origins/countries of sale as canonical tag IDs, front image URL, and data completeness score (0–1)
|
|
49
49
|
- `traces_tags` carries the "may contain" allergen warning separately from the declared `allergens_tags`; `["en:none"]` is the label stating no traces, while an empty array means not yet entered — never trace-free
|
|
50
50
|
- `ingredients_analysis_tags` carries the vegan, vegetarian, and palm-oil verdicts Open Food Facts computes itself, including its "maybe" states, rather than leaving the per-ingredient flags to be aggregated by the caller
|
|
51
51
|
- Optional `fields` parameter restricts the response to a subset (e.g., scores only, or nutrition only); a field that cannot be read on its own arrives with what it depends on — `nutriments` brings the serving size its per-serving figures are measured against — and `requested_fields` echoes the full set that was fetched
|
|
@@ -56,15 +56,18 @@ Food product data from Open Food Facts, a crowd-sourced database of 3M+ packaged
|
|
|
56
56
|
|
|
57
57
|
### `off_search_products` <sub>tool</sub>
|
|
58
58
|
|
|
59
|
-
- Full-text `query` plus structured tag filters — `categories_tag`, `brands_tag`, `labels_tag
|
|
59
|
+
- Full-text `query` plus structured tag filters — `categories_tag`, `brands_tag`, `labels_tag` (one label, or an array that must all apply), `allergens_tag`, `traces_tag` (the "may contain" warning), `ingredients_analysis_tag` (one of the 12 vegan, vegetarian, and palm-oil verdicts), `additives_tag`, `nutrition_grade` (a–e), `nova_group` (1–4), `countries_tag` — and numeric `nutrient_filters`, all combining as AND; tag values are canonical IDs, resolved via `off_browse_taxonomy` (`brands_tag` matches an exact slug, not free text)
|
|
60
|
+
- `exclude_allergens` and `exclude_traces` drop products that declare an allergen or warn of a trace, on both paths. Each value must be an allergen tag the Open Food Facts vocabulary confirms — an unrecognized one would exclude nothing, so it is rejected before any search is sent. A product with no allergen or trace data entered passes an exclusion, and every response carrying one says so and points to `off_get_product` for a per-product check
|
|
61
|
+
- Every word of `query` must match a product's name, generic name, categories, labels, or brand (ingredients and quantity are not searched), in any of the 31 languages the text index analyzes, so a product named only in French or Russian is found by that name; stop words of English, French, Spanish, German, and Italian ("with", "the", "de", "mit") are not required, and `query` takes at most 24 words
|
|
62
|
+
- On a search carrying `query` or `nutrient_filters`, each tag value is resolved to its canonical form before it is sent — a brand name is slugged (`Nutella` → `nutella`), and a case variant, synonym, or singular resolves where the Open Food Facts vocabulary confirms it (`US` → `en:united-states`, `en:peanut` → `en:peanuts`); anything unconfirmed is matched exactly, and an empty result names which values were
|
|
60
63
|
- Numeric `nutrient_filters` express per-100 g thresholds over `energy-kcal`, `fat`, `saturated-fat`, `carbohydrates`, `sugars`, `fiber`, `proteins`, `salt`, and `sodium` — each a `{ nutrient, operator, value }` triple with `lt` / `lte` / `gt` / `gte`; pair two entries on one nutrient for a range. They AND with every other filter and are served by the text backend, so supplying one routes the search there even without `query`
|
|
61
64
|
- `additives_tag` filters only on searches carrying neither `query` nor `nutrient_filters` — both route to a backend with no additives field, so the pairing is rejected up front rather than silently returning zero hits
|
|
62
|
-
- Pagination via `page` (1-based) and `page_size` (1–50, default 20); text searches serve only the first 10,000 results (`page * page_size` beyond that is rejected
|
|
65
|
+
- Pagination via `page` (1-based) and `page_size` (1–50, default 20); tag-only searches are served through page 10, and text searches serve only the first 10,000 results (`page * page_size` beyond that); a request past either bound is rejected before it is sent, and `last_page` reports the deepest page that can be requested
|
|
63
66
|
- `total` is exact on tag-only searches; text searches stop counting at 10,000 and set `total_is_lower_bound: true` with the count rendered as `10000+`
|
|
64
67
|
- The two paths read different indexes: a search carrying `query` is answered by a text index that lags the live database, and says so on both response surfaces; a tag-only search reads the live database. A recently contributed product can be missing from the first and present in the second
|
|
65
68
|
- `sort_by` (`last_modified_t`, `unique_scans_n`, `created_t`, `popularity_key`) orders newest or highest first on both paths; omitting it leaves text searches relevance-ranked
|
|
66
69
|
- A page past the end of a result set is reported as an exhausted page naming the deepest page that holds products, not as a zero-match search — the broaden-the-filters guidance appears only when nothing matched
|
|
67
|
-
- Returns summary rows (barcode, name, brand, Nutri-Score, NOVA, categories) — chain to `off_get_product` for full label data; counts reflect contributed products, not the market
|
|
70
|
+
- Returns summary rows (barcode, name, brand, Nutri-Score, NOVA, categories) — chain to `off_get_product` for full label data; counts reflect contributed products, not the market. Every returned barcode is one `off_get_product` accepts: a match Open Food Facts stores under a code it cannot serve (`00000636`) is left off the page and counted in `omitted`
|
|
68
71
|
- Own client-side budget of ~10 requests/min, kept well inside what Open Food Facts asks of clients
|
|
69
72
|
|
|
70
73
|
---
|
|
@@ -80,7 +83,7 @@ Food product data from Open Food Facts, a crowd-sourced database of 3M+ packaged
|
|
|
80
83
|
|
|
81
84
|
### `off_browse_taxonomy` <sub>tool</sub>
|
|
82
85
|
|
|
83
|
-
- Facets `categories`, `labels`, `allergens`, `additives`, `countries` resolve live against the Open Food Facts taxonomy (case-insensitive substring match on tag ID, display name, or a common synonym — "shellfish" resolves to `en:crustaceans`); upstream tags are often plural, so pass the returned `id` through unchanged
|
|
86
|
+
- Facets `categories`, `labels`, `allergens`, `additives`, `countries` resolve live against the Open Food Facts taxonomy (case-insensitive substring match on tag ID, display name, or a common synonym — "shellfish" resolves to `en:crustaceans`); upstream tags are often plural, so pass the returned `id` through unchanged. Among the live matches, the tag spelling the term itself ranks first (`lentil` → `en:lentils` ahead of `en:lentil-soups`), so a small `limit` does not cut it
|
|
84
87
|
- `nova_groups` and `nutrition_grades` are closed vocabularies, returned complete, with bare `"1"`–`"4"` / `"a"`–`"e"` ids
|
|
85
88
|
- Live lookups fall back to a small in-process sample when Open Food Facts is unreachable or the budget is spent, and say so rather than failing; omitting `search` returns only that sample, since Open Food Facts can't enumerate a full facet — no `total_in_facet` is reported for the open facets
|
|
86
89
|
- `limit` controls results (1–100, default 20); there is no offset or page — narrow the search term instead
|
|
@@ -94,7 +97,7 @@ Open Food Facts-specific:
|
|
|
94
97
|
|
|
95
98
|
- No API key required — the identifying `User-Agent` header (required by OFF terms) is baked into the service layer
|
|
96
99
|
- Token-bucket rate limiting per endpoint class: product reads (~15/min), search (~10/min), taxonomy resolution (~10/min). The product and search defaults are the per-IP ceilings Open Food Facts publishes; lower them on a shared outbound IP. Budgets count upstream requests, so a retried request spends its own slot and a budget exhausted mid-retry surfaces as `rate_limited` rather than sending. A local refusal says so — it never reports itself as an Open Food Facts rate limit
|
|
97
|
-
- Automatic retry (4 attempts, 500ms base) for transient failures only — 5xx, timeouts, and 429 (honoring `Retry-After`), with HTML error page detection for 503 during high load.
|
|
100
|
+
- Automatic retry (4 attempts, 500ms base) for transient failures only — 5xx other than 501, timeouts, and 429 (honoring `Retry-After`), with HTML error page detection for 503 during high load. The HTTP status decides: a 4xx or a 501 is sent once and never retried, and the upstream's own explanation is surfaced instead — a rendered error page served with a refusal is reported as a refusal, not as load
|
|
98
101
|
- Nutriments normalized from raw hyphenated keys (`energy-kcal_100g`) to underscore form — the `_100g` and `_serving` variants of every nutrient on the record, with the macros as named fields and the rest in an open map that carries each nutrient's own unit (micronutrients are reported in grams, so calcium `0.071` is 71 mg)
|
|
99
102
|
- Live tag resolution for `off_browse_taxonomy` against the Open Food Facts taxonomy, merged behind a small in-process sample that covers offline operation and is authoritative for E-number lookups, which the upstream suggester answers poorly
|
|
100
103
|
|
|
@@ -226,7 +229,7 @@ All configuration is validated at startup via Zod schemas in `src/config/server-
|
|
|
226
229
|
| `OFF_BASE_URL` | Open Food Facts API base URL. Override for local testing against a mock server. | `https://world.openfoodfacts.org` |
|
|
227
230
|
| `OFF_RATE_LIMIT_PRODUCT` | Product read rate limit (requests/min). Matches the 15 req/min/IP Open Food Facts documents for product reads. | `15` |
|
|
228
231
|
| `OFF_RATE_LIMIT_SEARCH` | Search rate limit (requests/min). | `10` |
|
|
229
|
-
| `OFF_RATE_LIMIT_TAXONOMY` | Taxonomy resolution rate limit (requests/min). A spent budget falls back to the offline sample rather than failing. | `10` |
|
|
232
|
+
| `OFF_RATE_LIMIT_TAXONOMY` | Taxonomy resolution rate limit (requests/min), shared by `off_browse_taxonomy`, tag-value resolution on text searches, and the check on allergen and trace exclusions. A spent budget falls back to the offline sample, or to the tag value as normalized, rather than failing — except that an exclusion it could not check is refused as retryable. | `10` |
|
|
230
233
|
| `MCP_TRANSPORT_TYPE` | Transport: `stdio` or `http`. | `stdio` |
|
|
231
234
|
| `MCP_HTTP_PORT` | HTTP server port. | `3010` |
|
|
232
235
|
| `MCP_AUTH_MODE` | Auth mode: `none`, `jwt`, or `oauth`. | `none` |
|
|
@@ -277,7 +280,7 @@ The Dockerfile defaults to HTTP transport, stateless session mode, and logs to `
|
|
|
277
280
|
| `src/config` | Server-specific environment variable parsing and validation with Zod. |
|
|
278
281
|
| `src/mcp-server/tools` | Tool definitions (`*.tool.ts`). |
|
|
279
282
|
| `src/services/openfoodfacts` | Open Food Facts API client — HTTP, rate limiting, retry, field normalization. |
|
|
280
|
-
| `src/services/taxonomy` | Tag vocabulary service
|
|
283
|
+
| `src/services/taxonomy` | Tag vocabulary service — live resolution, offline sample, merge and fallback policy for `off_browse_taxonomy`, and tag-value canonicalization for text searches. |
|
|
281
284
|
| `tests/` | Unit and integration tests mirroring `src/`. |
|
|
282
285
|
|
|
283
286
|
## Development guide
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "The HTTP status now decides retryability, off_get_product carries nested sub-ingredients up to three levels, off_browse_taxonomy ranks the exact-term tag first, and four output descriptions are corrected."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.3.5 — 2026-09-22
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`off_browse_taxonomy` ranks the exact-term tag first** — among live suggestions, the tag spelling the search term itself (`en:lentils` for "lentil") now sorts ahead of compounds instead of being cut by a small `limit`; the live pool is requested in full to make the ranking possible (#42).
|
|
12
|
+
|
|
13
|
+
## Fixed
|
|
14
|
+
|
|
15
|
+
- **The HTTP status decides retryability, not the body** — a 501 is now rejected once as `upstream_rejected` instead of retried four times, and an HTML-bodied 4xx is described as a refusal rather than blamed on load shedding (#37).
|
|
16
|
+
- **`off_get_product` parsed ingredients keep their sub-ingredients** — nested entries (wheat flour under "cereal", milk under cheddar) are now carried under their parent up to three levels deep instead of being dropped; an entry nested deeper upstream is listed at the third level, directly after its ancestor (#40).
|
|
17
|
+
- **Output descriptions corrected** — `off_get_product`'s `barcode` now describes the echoed input rather than "returned by the API"; the Nutri-Score and Green-Score descriptions name their full grade vocabularies (`unknown`, `not-applicable`, `a-plus`); `off_browse_taxonomy` no longer advertises a `tags[].products` count no backend ever supplies (#43).
|
|
18
|
+
|
|
19
|
+
## Dependencies
|
|
20
|
+
|
|
21
|
+
- `@cyanheads/mcp-ts-core` ^0.13.3 → ^0.13.6
|
|
22
|
+
- `@biomejs/biome` ^2.5.13 → ^2.5.14
|
|
23
|
+
- `@types/node` ^26.2.0 → ^26.6.2
|
|
24
|
+
- `vitest` ^4.1.11 → ^5.0.1
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
---
|
|
2
|
+
summary: "off_search_products now requires every query word to match across 31 languages, gains allergen/trace exclusions and a vegan/vegetarian/palm-oil filter, and off_get_product accepts the full range of barcodes Open Food Facts serves."
|
|
3
|
+
breaking: false
|
|
4
|
+
security: false
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
# 0.3.6 — 2026-09-22
|
|
8
|
+
|
|
9
|
+
## Added
|
|
10
|
+
|
|
11
|
+
- **`off_search_products` gains `traces_tag`, `exclude_allergens`, `exclude_traces`, and `ingredients_analysis_tag`** — the last a closed enum of the 12 vegan/vegetarian/palm-oil verdicts Open Food Facts computes; `labels_tag` also takes an array of up to 10 values that must all apply. An exclusion the allergen vocabulary cannot confirm is refused as `unrecognized_exclusion`, and every response carrying an exclusion gets an `exclusion_coverage` caveat, since a product with no allergen or trace data entered passes it (#41).
|
|
12
|
+
|
|
13
|
+
## Changed
|
|
14
|
+
|
|
15
|
+
- **`query` is capped at 24 words** — a longer one is refused as `query_too_long` before it is sent, since past that the per-word requirement exceeds the text backend's clause ceiling.
|
|
16
|
+
- **`OFF_RATE_LIMIT_TAXONOMY` also budgets tag-value resolution on text searches and exclusion checks on every search**, not only `off_browse_taxonomy` lookups.
|
|
17
|
+
- Package tagline corrected from "search by ingredient" to "search by keyword, tag, allergen, or nutrition filter" — `off_search_products` never filtered on ingredient text.
|
|
18
|
+
|
|
19
|
+
## Fixed
|
|
20
|
+
|
|
21
|
+
- **`off_search_products` text queries require every word to match** instead of counting products that match any one word, and match names in the 31 languages the text index analyzes rather than English only — a product named only in French or Russian is now found by that name (#38, #47).
|
|
22
|
+
- **Tag filter values on the text path are canonicalized** before being sent as exact-match clauses — a case variant, synonym, or singular resolves to its canonical ID the way `/api/v2/search` already does, and an empty result names each value no vocabulary confirmed (#39).
|
|
23
|
+
- **Tag-only searches stop at page 10**, the deepest page Open Food Facts serves an anonymous client: a deeper page is refused as `page_out_of_range` before it is sent instead of coming back as `upstream_rejected`, and `last_page` reports the reachable depth (#44).
|
|
24
|
+
- **`off_get_product` and `off_compare_products` accept every barcode Open Food Facts serves** (4–40 digits after leading zeros), not just 8–14-digit codes — a 7-digit code returned by `off_search_products` previously had no way back into `off_get_product` (#46).
|
|
25
|
+
- **`off_search_products` drops rows stored under a barcode Open Food Facts cannot serve** instead of returning one `off_get_product` would reject; `omitted` discloses how many were left off the page (#35).
|
|
26
|
+
- **Text-search failures are reported, not read as results** — a search-engine error served inside an HTTP 200 is raised as `upstream_error` instead of being read as zero matches, and the messages of a 422 validation `detail` list are surfaced in the error.
|
package/changelog/template.md
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
# Required. One-line GitHub Release-style headline. 350 character cap — a
|
|
8
8
|
# ceiling, not a target. Default short and scannable. Don't pad, don't stitch
|
|
9
|
-
# unrelated changes with commas/semicolons into an inventory — pick the
|
|
10
|
-
# headline
|
|
9
|
+
# unrelated changes with commas/semicolons into an inventory — pick the one
|
|
10
|
+
# headline the release is about. Quotes required: unquoted YAML treats
|
|
11
11
|
# `: ` inside the value as a key separator and fails GitHub's strict parser.
|
|
12
12
|
summary: ""
|
|
13
13
|
|
|
@@ -119,11 +119,11 @@ security: false
|
|
|
119
119
|
TAG ANNOTATIONS — the annotated tag body renders as the GitHub Release body
|
|
120
120
|
via `gh release create --notes-from-tag`. It is a condensed digest of this
|
|
121
121
|
entry, never a copy, and its format is owned by the `release-and-publish`
|
|
122
|
-
skill (step 4, "Create the annotated tag"):
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
122
|
+
skill (step 4, "Create the annotated tag"): a short subject line without the
|
|
123
|
+
version, flat headline bullets — no Keep-a-Changelog section headers, no
|
|
124
|
+
gates line — at most one deps line, issue backlinks, and the changelog link
|
|
125
|
+
last. In release-PR mode the `git-wrapup` skill authors those bullets as the
|
|
126
|
+
PR body's `## Changes` and the tag copies them.
|
|
127
127
|
-->
|
|
128
128
|
|
|
129
129
|
## Added
|
package/dist/index.js
CHANGED
|
@@ -11,7 +11,7 @@ await createApp({
|
|
|
11
11
|
name: 'openfoodfacts-mcp-server',
|
|
12
12
|
title: 'openfoodfacts-mcp-server',
|
|
13
13
|
tools: allToolDefinitions,
|
|
14
|
-
instructions: 'Query Open Food Facts, a free crowd-sourced database of 3M+ packaged foods: off_get_product looks up one product by
|
|
14
|
+
instructions: 'Query Open Food Facts, a free crowd-sourced database of 3M+ packaged foods: off_get_product looks up one product by barcode (4–40 digits), off_search_products finds products by text or tag filters, off_compare_products puts several side by side on nutrition, and off_browse_taxonomy resolves a human term to the canonical tag ID the other tools filter on — so start there when you have a category or label rather than a barcode. Every field is contributor-entered, so a missing one means "not yet recorded" rather than absent, and the computed Nutri-Score, NOVA, and Green-Score grades carry regional caveats. No API key is required; the data is ODbL 1.0, so cite Open Food Facts wherever you pass it on.',
|
|
15
15
|
sessionMode: 'stateless',
|
|
16
16
|
setup() {
|
|
17
17
|
initOpenFoodFactsService();
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,mDAAmD,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAE9E,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,0BAA0B;IAChC,KAAK,EAAE,0BAA0B;IACjC,KAAK,EAAE,kBAAkB;IACzB,YAAY,EACV
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;GAGG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AAC7E,OAAO,EAAE,wBAAwB,EAAE,MAAM,mDAAmD,CAAC;AAC7F,OAAO,EAAE,mBAAmB,EAAE,MAAM,yCAAyC,CAAC;AAE9E,MAAM,SAAS,CAAC;IACd,IAAI,EAAE,0BAA0B;IAChC,KAAK,EAAE,0BAA0B;IACjC,KAAK,EAAE,kBAAkB;IACzB,YAAY,EACV,ksBAAksB;IACpsB,WAAW,EAAE,WAAW;IACxB,KAAK;QACH,wBAAwB,EAAE,CAAC;QAC3B,mBAAmB,EAAE,CAAC;IACxB,CAAC;CACF,CAAC,CAAC"}
|
|
@@ -20,7 +20,6 @@ export declare const offBrowseTaxonomyTool: import("@cyanheads/mcp-ts-core").Too
|
|
|
20
20
|
tags: z.ZodArray<z.ZodObject<{
|
|
21
21
|
id: z.ZodString;
|
|
22
22
|
name: z.ZodString;
|
|
23
|
-
products: z.ZodOptional<z.ZodNumber>;
|
|
24
23
|
}, z.core.$strip>>;
|
|
25
24
|
total_in_facet: z.ZodOptional<z.ZodNumber>;
|
|
26
25
|
}, z.core.$strip>, undefined, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browse-taxonomy.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/browse-taxonomy.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAIjD,eAAO,MAAM,qBAAqB
|
|
1
|
+
{"version":3,"file":"browse-taxonomy.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/browse-taxonomy.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAIjD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;EA2IhC,CAAC"}
|
|
@@ -35,7 +35,7 @@ export const offBrowseTaxonomyTool = tool('off_browse_taxonomy', {
|
|
|
35
35
|
.min(1)
|
|
36
36
|
.max(100)
|
|
37
37
|
.default(20)
|
|
38
|
-
.describe('Maximum entries to return (1–100, default 20). There is no offset or page input: Open Food Facts
|
|
38
|
+
.describe('Maximum entries to return (1–100, default 20). There is no offset or page input: Open Food Facts offers no cursor for this lookup, so narrow the search term rather than paging. The tag spelling the term itself (e.g. "lentil" → en:lentils) is listed first among the live matches, so it is not the one a small limit cuts.'),
|
|
39
39
|
}),
|
|
40
40
|
output: z.object({
|
|
41
41
|
facet: z.string().describe('The facet name that was queried (echoes the input).'),
|
|
@@ -46,10 +46,6 @@ export const offBrowseTaxonomyTool = tool('off_browse_taxonomy', {
|
|
|
46
46
|
.string()
|
|
47
47
|
.describe('Canonical tag ID (e.g. "en:organic"; bare "1"–"4" for NOVA groups, bare "a"–"e" for Nutri-Score grades). Pass this value through to the matching off_search_products filter parameter unchanged.'),
|
|
48
48
|
name: z.string().describe('Human-readable display name (e.g. "Organic").'),
|
|
49
|
-
products: z
|
|
50
|
-
.number()
|
|
51
|
-
.optional()
|
|
52
|
-
.describe('Approximate count of products with this tag. Not available for all facets.'),
|
|
53
49
|
})
|
|
54
50
|
.describe('A single taxonomy tag entry with its canonical ID and display name.'))
|
|
55
51
|
.describe('Matching tag entries.'),
|
|
@@ -113,10 +109,9 @@ export const offBrowseTaxonomyTool = tool('off_browse_taxonomy', {
|
|
|
113
109
|
return [{ type: 'text', text: lines.join('\n') }];
|
|
114
110
|
}
|
|
115
111
|
for (const tag of result.tags) {
|
|
116
|
-
const products = tag.products !== undefined ? ` (~${tag.products.toLocaleString()} products)` : '';
|
|
117
112
|
// A backtick in a tag ID would close a single-backtick span and render the rest of the ID as
|
|
118
113
|
// prose, so the span's delimiter is sized past whatever the ID carries.
|
|
119
|
-
lines.push(`- ${mdInlineCode(tag.id)} — ${mdInline(tag.name)}
|
|
114
|
+
lines.push(`- ${mdInlineCode(tag.id)} — ${mdInline(tag.name)}`);
|
|
120
115
|
}
|
|
121
116
|
lines.push('\n*Pass an `id` through to off_search_products exactly as shown — "en:organic" for most facets, bare "1"–"4" for NOVA groups, bare "a"–"e" for Nutri-Score grades.*');
|
|
122
117
|
return [{ type: 'text', text: lines.join('\n') }];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"browse-taxonomy.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/browse-taxonomy.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAc,kBAAkB,EAAE,MAAM,yCAAyC,CAAC;AACzF,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAE7D,MAAM,CAAC,MAAM,qBAAqB,GAAG,IAAI,CAAC,qBAAqB,EAAE;IAC/D,KAAK,EAAE,4BAA4B;IACnC,WAAW,EACT,6yBAA6yB;IAC/yB,WAAW,EAAE;QACX,YAAY,EAAE,IAAI;QAClB,cAAc,EAAE,IAAI;QACpB,aAAa,EAAE,IAAI;KACpB;IAED,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,KAAK,EAAE,CAAC;aACL,IAAI,CAAC;YACJ,YAAY;YACZ,QAAQ;YACR,WAAW;YACX,WAAW;YACX,WAAW;YACX,aAAa;YACb,kBAAkB;SACnB,CAAC;aACD,QAAQ,CACP,gbAAgb,CACjb;QACH,MAAM,EAAE,CAAC;aACN,MAAM,EAAE;aACR,QAAQ,EAAE;aACV,QAAQ,CACP,4ZAA4Z,CAC7Z;QACH,KAAK,EAAE,CAAC;aACL,MAAM,EAAE;aACR,GAAG,EAAE;aACL,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,GAAG,CAAC;aACR,OAAO,CAAC,EAAE,CAAC;aACX,QAAQ,CACP,
|
|
1
|
+
{"version":3,"file":"browse-taxonomy.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/browse-taxonomy.tool.ts"],"names":[],"mappings":"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"}
|
|
@@ -34,7 +34,7 @@ export declare const offCompareProductsTool: import("@cyanheads/mcp-ts-core").To
|
|
|
34
34
|
}, z.core.$strip>, readonly [{
|
|
35
35
|
readonly reason: "upstream_error";
|
|
36
36
|
readonly code: JsonRpcErrorCode.ServiceUnavailable;
|
|
37
|
-
readonly when: "Open Food Facts returns 5xx, serves an HTML error page, or is unreachable — surfaced per barcode in failed[]";
|
|
37
|
+
readonly when: "Open Food Facts returns a 5xx other than 501, serves an HTML error page with a 2xx or 5xx status, or is unreachable — surfaced per barcode in failed[]";
|
|
38
38
|
readonly retryable: true;
|
|
39
39
|
readonly recovery: "Retry the barcodes listed in failed after a brief pause. Rows that already resolved are kept, so only the failures need repeating.";
|
|
40
40
|
}, {
|
|
@@ -46,7 +46,7 @@ export declare const offCompareProductsTool: import("@cyanheads/mcp-ts-core").To
|
|
|
46
46
|
}, {
|
|
47
47
|
readonly reason: "upstream_rejected";
|
|
48
48
|
readonly code: JsonRpcErrorCode.InvalidParams;
|
|
49
|
-
readonly when: "Open Food Facts answers 4xx for a barcode — surfaced per barcode in failed[]";
|
|
49
|
+
readonly when: "Open Food Facts answers 4xx or 501 Not Implemented for a barcode — surfaced per barcode in failed[]";
|
|
50
50
|
readonly retryable: false;
|
|
51
51
|
readonly recovery: "Do not retry unchanged. Check the digits of the barcodes listed in failed, then look them up individually with off_get_product.";
|
|
52
52
|
}, {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare-products.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/compare-products.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAY,MAAM,+BAA+B,CAAC;
|
|
1
|
+
{"version":3,"file":"compare-products.tool.d.ts","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/compare-products.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAQ,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAY,MAAM,+BAA+B,CAAC;AAsI3E,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cAqRjC,CAAC"}
|
|
@@ -5,6 +5,7 @@
|
|
|
5
5
|
import { tool, z } from '@cyanheads/mcp-ts-core';
|
|
6
6
|
import { JsonRpcErrorCode, McpError } from '@cyanheads/mcp-ts-core/errors';
|
|
7
7
|
import { getOpenFoodFactsService } from '../../../services/openfoodfacts/openfoodfacts-service.js';
|
|
8
|
+
import { BARCODE_PATTERN, BARCODE_PATTERN_MESSAGE, } from '../../../services/openfoodfacts/types.js';
|
|
8
9
|
import { mdInline, mdTableCell } from '../../../utils/markdown.js';
|
|
9
10
|
/** Fields needed for comparison — narrower than full product fetch. */
|
|
10
11
|
const COMPARE_FIELDS = 'product_name,brands,nutriscore_grade,nova_group,ecoscore_grade,nutriments,completeness';
|
|
@@ -111,8 +112,8 @@ export const offCompareProductsTool = tool('off_compare_products', {
|
|
|
111
112
|
barcodes: z
|
|
112
113
|
.array(z
|
|
113
114
|
.string()
|
|
114
|
-
.regex(
|
|
115
|
-
.describe('
|
|
115
|
+
.regex(BARCODE_PATTERN, BARCODE_PATTERN_MESSAGE)
|
|
116
|
+
.describe('Product barcode, digits only: 4–40 digits after any leading zeros.'))
|
|
116
117
|
.min(2)
|
|
117
118
|
.max(10)
|
|
118
119
|
.describe('2–10 barcodes to compare, returned as one row each in input order. Example: ["3017620422003", "7622210100146"].'),
|
|
@@ -121,7 +122,7 @@ export const offCompareProductsTool = tool('off_compare_products', {
|
|
|
121
122
|
products: z
|
|
122
123
|
.array(z
|
|
123
124
|
.object({
|
|
124
|
-
barcode: z.string().describe('
|
|
125
|
+
barcode: z.string().describe('Barcode, echoed exactly as provided in input.'),
|
|
125
126
|
product_name: z
|
|
126
127
|
.string()
|
|
127
128
|
.optional()
|
|
@@ -134,7 +135,7 @@ export const offCompareProductsTool = tool('off_compare_products', {
|
|
|
134
135
|
nutriscore_grade: z
|
|
135
136
|
.string()
|
|
136
137
|
.optional()
|
|
137
|
-
.describe('Nutri-Score
|
|
138
|
+
.describe('Nutri-Score grade: "a" through "e", "unknown" when the nutrition data entered is not enough to compute it, or "not-applicable" for product categories the score does not cover. Absent when Open Food Facts sent none.'),
|
|
138
139
|
nova_group: z
|
|
139
140
|
.number()
|
|
140
141
|
.optional()
|
|
@@ -142,7 +143,7 @@ export const offCompareProductsTool = tool('off_compare_products', {
|
|
|
142
143
|
ecoscore_grade: z
|
|
143
144
|
.string()
|
|
144
145
|
.optional()
|
|
145
|
-
.describe('Green-Score
|
|
146
|
+
.describe('Green-Score (formerly Eco-Score) environmental impact grade: "a-plus" (lowest impact), then "a" through "f"; "unknown" when the data it needs is missing, or "not-applicable" for product categories the score does not cover. Often absent.'),
|
|
146
147
|
energy_kcal_100g: z
|
|
147
148
|
.number()
|
|
148
149
|
.optional()
|
|
@@ -180,12 +181,12 @@ export const offCompareProductsTool = tool('off_compare_products', {
|
|
|
180
181
|
.describe('Comparison rows in input order — one per barcode whose fetch completed, whether or not a record exists. Barcodes whose fetch failed have no row here; they appear in failed.'),
|
|
181
182
|
succeeded: z.number().describe('Number of barcodes that resolved to a found product.'),
|
|
182
183
|
not_found: z
|
|
183
|
-
.array(z.string().describe('
|
|
184
|
+
.array(z.string().describe('Barcode with no contributor record, as provided in input.'))
|
|
184
185
|
.describe('Barcodes Open Food Facts answered for, confirming no contributor record exists. Not an error — the product may exist but not yet be entered. Never used for a fetch that failed.'),
|
|
185
186
|
failed: z
|
|
186
187
|
.array(z
|
|
187
188
|
.object({
|
|
188
|
-
barcode: z.string().describe('
|
|
189
|
+
barcode: z.string().describe('Barcode whose fetch failed, as provided in input.'),
|
|
189
190
|
reason: z
|
|
190
191
|
.string()
|
|
191
192
|
.describe('Declared failure reason — one of upstream_error, upstream_timeout, upstream_rejected, rate_limited.'),
|
|
@@ -199,7 +200,7 @@ export const offCompareProductsTool = tool('off_compare_products', {
|
|
|
199
200
|
{
|
|
200
201
|
reason: 'upstream_error',
|
|
201
202
|
code: JsonRpcErrorCode.ServiceUnavailable,
|
|
202
|
-
when: 'Open Food Facts returns 5xx, serves an HTML error page, or is unreachable — surfaced per barcode in failed[]',
|
|
203
|
+
when: 'Open Food Facts returns a 5xx other than 501, serves an HTML error page with a 2xx or 5xx status, or is unreachable — surfaced per barcode in failed[]',
|
|
203
204
|
retryable: true,
|
|
204
205
|
recovery: 'Retry the barcodes listed in failed after a brief pause. Rows that already resolved are kept, so only the failures need repeating.',
|
|
205
206
|
},
|
|
@@ -213,7 +214,7 @@ export const offCompareProductsTool = tool('off_compare_products', {
|
|
|
213
214
|
{
|
|
214
215
|
reason: 'upstream_rejected',
|
|
215
216
|
code: JsonRpcErrorCode.InvalidParams,
|
|
216
|
-
when: 'Open Food Facts answers 4xx for a barcode — surfaced per barcode in failed[]',
|
|
217
|
+
when: 'Open Food Facts answers 4xx or 501 Not Implemented for a barcode — surfaced per barcode in failed[]',
|
|
217
218
|
retryable: false,
|
|
218
219
|
recovery: 'Do not retry unchanged. Check the digits of the barcodes listed in failed, then look them up individually with off_get_product.',
|
|
219
220
|
},
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compare-products.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/compare-products.tool.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,IAAI,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AACjD,OAAO,EAAE,gBAAgB,EAAE,QAAQ,EAAE,MAAM,+BAA+B,CAAC;AAC3E,OAAO,EAAE,uBAAuB,EAAE,MAAM,mDAAmD,CAAC;AAE5F,OAAO,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAE5D,uEAAuE;AACvE,MAAM,cAAc,GAClB,wFAAwF,CAAC;AAoB3F,2DAA2D;AAC3D,SAAS,CAAC,CAAC,GAAgD,EAAE,GAAW;IACtE,MAAM,CAAC,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;IACnB,OAAO,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAC/C,CAAC;AAQD;;;;;GAKG;AACH,SAAS,eAAe,CAAC,OAAe,EAAE,KAAc;IACtD,IAAI,KAAK,YAAY,QAAQ,EAAE,CAAC;QAC9B,MAAM,MAAM,GAAG,OAAO,KAAK,CAAC,IAAI,EAAE,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,gBAAgB,CAAC;QAC7F,MAAM,IAAI,GAAI,KAAK,CAAC,IAAI,EAAE,QAA0C,EAAE,IAAI,CAAC;QAC3E,MAAM,OAAO,GAAG,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,KAAK,CAAC,OAAO,GAAG,CAAC;QACnF,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,GAAG,OAAO,IAAI,IAAI,EAAE,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;IAC3E,CAAC;IACD,OAAO;QACL,OAAO;QACP,MAAM,EAAE,gBAAgB;QACxB,KAAK,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC;KAC9D,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,gBAAgB,EAAE,kBAAkB,EAAE,cAAc,CAAC,CAAC,CAAC;AAE1F;;;;;GAKG;AACH,SAAS,gBAAgB,CAAC,QAAkB,EAAE,MAAqB;IACjE,MAAM,WAAW,GAAG,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC;IACtC,MAAM,OAAO,GAAG,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC;IAEpC,IAAI,WAAW,IAAI,OAAO,EAAE,CAAC;QAC3B,OAAO,CACL,qFAAqF,QAAQ,CAAC,MAAM,GAAG;YACvG,gBAAgB,MAAM,CAAC,MAAM,wDAAwD,CACtF,CAAC;IACJ,CAAC;IAED,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;YAClE,CAAC,CAAC,qDAAqD;YACvD,CAAC,CAAC,yGAAyG,CAAC;QAC9G,OAAO,kGAAkG,QAAQ,EAAE,CAAC;IACtH,CAAC;IAED,OAAO,CACL,8FAA8F;QAC9F,qHAAqH,CACtH,CAAC;AACJ,CAAC;AAED,iDAAiD;AACjD,SAAS,eAAe,CAAC,OAAe,EAAE,GAAsB;IAC9D,IAAI,CAAC,GAAG;QAAE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;IAE3C,MAAM,GAAG,GAAe,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;IAEjD,IAAI,GAAG,CAAC,YAAY;QAAE,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;IAC1D,IAAI,GAAG,CAAC,MAAM;QAAE,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,CAAC;IACxC,IAAI,GAAG,CAAC,gBAAgB;QAAE,GAAG,CAAC,gBAAgB,GAAG,GAAG,CAAC,gBAAgB,CAAC;IACtE,IAAI,OAAO,GAAG,CAAC,UAAU,KAAK,QAAQ;QAAE,GAAG,CAAC,UAAU,GAAG,GAAG,CAAC,UAAU,CAAC;IACxE,IAAI,GAAG,CAAC,cAAc;QAAE,GAAG,CAAC,cAAc,GAAG,GAAG,CAAC,cAAc,CAAC;IAChE,IAAI,OAAO,GAAG,CAAC,YAAY,KAAK,QAAQ;QAAE,GAAG,CAAC,YAAY,GAAG,GAAG,CAAC,YAAY,CAAC;IAE9E,IAAI,GAAG,CAAC,UAAU,EAAE,CAAC;QACnB,MAAM,EAAE,GAAG,GAAG,CAAC,UAAU,CAAC;QAC1B,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,kBAAkB,CAAC,CAAC;QACzC,IAAI,MAAM,KAAK,SAAS;YAAE,GAAG,CAAC,gBAAgB,GAAG,MAAM,CAAC;QACxD,MAAM,GAAG,GAAG,CAAC,CAAC,EAAE,EAAE,UAAU,CAAC,CAAC;QAC9B,IAAI,GAAG,KAAK,SAAS;YAAE,GAAG,CAAC,QAAQ,GAAG,GAAG,CAAC;QAC1C,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,oBAAoB,CAAC,CAAC;QAC3C,IAAI,MAAM,KAAK,SAAS;YAAE,GAAG,CAAC,kBAAkB,GAAG,MAAM,CAAC;QAC1D,MAAM,MAAM,GAAG,CAAC,CAAC,EAAE,EAAE,aAAa,CAAC,CAAC;QACpC,IAAI,MAAM,KAAK,SAAS;YAAE,GAAG,CAAC,WAAW,GAAG,MAAM,CAAC;QACnD,MAAM,IAAI,GAAG,CAAC,CAAC,EAAE,EAAE,WAAW,CAAC,CAAC;QAChC,IAAI,IAAI,KAAK,SAAS;YAAE,GAAG,CAAC,SAAS,GAAG,IAAI,CAAC;QAC7C,MAAM,QAAQ,GAAG,CAAC,CAAC,EAAE,EAAE,eAAe,CAAC,CAAC;QACxC,IAAI,QAAQ,KAAK,SAAS;YAAE,GAAG,CAAC,aAAa,GAAG,QAAQ,CAAC;QACzD,MAAM,KAAK,GAAG,CAAC,CAAC,EAAE,EAAE,YAAY,CAAC,CAAC;QAClC,IAAI,KAAK,KAAK,SAAS;YAAE,GAAG,CAAC,UAAU,GAAG,KAAK,CAAC;IAClD,CAAC;IAED,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,CAAC,MAAM,sBAAsB,GAAG,IAAI,CAAC,sBAAsB,EAAE;IACjE,KAAK,EAAE,oCAAoC;IAC3C,WAAW,EACT,0rBAA0rB;IAC5rB,WAAW,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,aAAa,EAAE,IAAI,EAAE;IAE9E,KAAK,EAAE,CAAC,CAAC,MAAM,CAAC;QACd,QAAQ,EAAE,CAAC;aACR,KAAK,CACJ,CAAC;aACE,MAAM,EAAE;aACR,KAAK,CAAC,YAAY,CAAC;aACnB,QAAQ,CAAC,sCAAsC,CAAC,CACpD;aACA,GAAG,CAAC,CAAC,CAAC;aACN,GAAG,CAAC,EAAE,CAAC;aACP,QAAQ,CACP,iHAAiH,CAClH;KACJ,CAAC;IAEF,MAAM,EAAE,CAAC,CAAC,MAAM,CAAC;QACf,QAAQ,EAAE,CAAC;aACR,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;YAC/E,YAAY,EAAE,CAAC;iBACZ,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,4DAA4D,CAAC;YACzE,MAAM,EAAE,CAAC;iBACN,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,8DAA8D,CAAC;YAC3E,KAAK,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,CAAC,iDAAiD,CAAC;YAC9E,gBAAgB,EAAE,CAAC;iBAChB,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,qDAAqD,CAAC;YAClE,UAAU,EAAE,CAAC;iBACV,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,wDAAwD,CAAC;YACrE,cAAc,EAAE,CAAC;iBACd,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,yDAAyD,CAAC;YACtE,gBAAgB,EAAE,CAAC;iBAChB,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,mDAAmD,CAAC;YAChE,QAAQ,EAAE,CAAC;iBACR,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,uDAAuD,CAAC;YACpE,kBAAkB,EAAE,CAAC;iBAClB,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,2DAA2D,CAAC;YACxE,WAAW,EAAE,CAAC;iBACX,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,0DAA0D,CAAC;YACvE,SAAS,EAAE,CAAC;iBACT,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,kDAAkD,CAAC;YAC/D,aAAa,EAAE,CAAC;iBACb,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,qDAAqD,CAAC;YAClE,UAAU,EAAE,CAAC;iBACV,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,gDAAgD,CAAC;YAC7D,YAAY,EAAE,CAAC;iBACZ,MAAM,EAAE;iBACR,QAAQ,EAAE;iBACV,QAAQ,CAAC,iEAAiE,CAAC;SAC/E,CAAC;aACD,QAAQ,CAAC,kCAAkC,CAAC,CAChD;aACA,QAAQ,CACP,8KAA8K,CAC/K;QACH,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,sDAAsD,CAAC;QACtF,SAAS,EAAE,CAAC;aACT,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,mDAAmD,CAAC,CAAC;aAC/E,QAAQ,CACP,kLAAkL,CACnL;QACH,MAAM,EAAE,CAAC;aACN,KAAK,CACJ,CAAC;aACE,MAAM,CAAC;YACN,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2CAA2C,CAAC;YACzE,MAAM,EAAE,CAAC;iBACN,MAAM,EAAE;iBACR,QAAQ,CACP,qGAAqG,CACtG;YACH,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,2DAA2D,CAAC;SACxF,CAAC;aACD,QAAQ,CAAC,sCAAsC,CAAC,CACpD;aACA,QAAQ,EAAE;aACV,QAAQ,CACP,8OAA8O,CAC/O;KACJ,CAAC;IAEF,MAAM,EAAE;QACN;YACE,MAAM,EAAE,gBAAgB;YACxB,IAAI,EAAE,gBAAgB,CAAC,kBAAkB;YACzC,IAAI,EAAE,8GAA8G;YACpH,SAAS,EAAE,IAAI;YACf,QAAQ,EACN,oIAAoI;SACvI;QACD;YACE,MAAM,EAAE,kBAAkB;YAC1B,IAAI,EAAE,gBAAgB,CAAC,OAAO;YAC9B,IAAI,EAAE,+FAA+F;YACrG,SAAS,EAAE,IAAI;YACf,QAAQ,EACN,uHAAuH;SAC1H;QACD;YACE,MAAM,EAAE,mBAAmB;YAC3B,IAAI,EAAE,gBAAgB,CAAC,aAAa;YACpC,IAAI,EAAE,8EAA8E;YACpF,SAAS,EAAE,KAAK;YAChB,QAAQ,EACN,iIAAiI;SACpI;QACD;YACE,MAAM,EAAE,cAAc;YACtB,IAAI,EAAE,gBAAgB,CAAC,WAAW;YAClC,IAAI,EAAE,yHAAyH;YAC/H,SAAS,EAAE,IAAI;YACf,QAAQ,EACN,wIAAwI;SAC3I;KACF;IAED,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG;QACtB,MAAM,GAAG,GAAG,uBAAuB,EAAE,CAAC;QAEtC,iCAAiC;QACjC,MAAM,WAAW,GAAG,MAAM,OAAO,CAAC,UAAU,CAC1C,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CAAC,GAAG,CAAC,gBAAgB,CAAC,OAAO,EAAE,cAAc,EAAE,GAAG,CAAC,CAAC,CACpF,CAAC;QAEF,MAAM,QAAQ,GAAiB,EAAE,CAAC;QAClC,MAAM,SAAS,GAAa,EAAE,CAAC;QAC/B,MAAM,MAAM,GAAkB,EAAE,CAAC;QACjC,IAAI,SAAS,GAAG,CAAC,CAAC;QAElB,+FAA+F;QAC/F,+FAA+F;QAC/F,2FAA2F;QAC3F,8EAA8E;QAC9E,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC/C,MAAM,OAAO,GAAG,KAAK,CAAC,QAAQ,CAAC,CAAC,CAAW,CAAC;YAC5C,MAAM,MAAM,GAAG,WAAW,CAAC,CAAC,CAA4C,CAAC;YAEzE,IAAI,MAAM,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;gBACjC,MAAM,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;gBACrD,SAAS;YACX,CAAC;YAED,MAAM,GAAG,GAAG,MAAM,CAAC,KAAK,CAAC;YACzB,IAAI,CAAC,GAAG,EAAE,CAAC;gBACT,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;gBACzC,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAC1B,CAAC;iBAAM,CAAC;gBACN,QAAQ,CAAC,IAAI,CAAC,eAAe,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC;gBAC7C,SAAS,EAAE,CAAC;YACd,CAAC;QACH,CAAC;QAED,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,8BAA8B,EAAE;YAC3C,KAAK,EAAE,KAAK,CAAC,QAAQ,CAAC,MAAM;YAC5B,SAAS;YACT,SAAS,EAAE,SAAS,CAAC,MAAM;YAC3B,MAAM,EAAE,MAAM,CAAC,MAAM;SACtB,CAAC,CAAC;QAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,SAAS,EAAE,GAAG,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,CAAC;IAClF,CAAC;IAED,MAAM,EAAE,CAAC,MAAM,EAAE,EAAE;QACjB,MAAM,SAAS,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,IAAI,CAAC,CAAC,CAAC;QACxE,MAAM,KAAK,GAAa,CAAC,0BAA0B,MAAM,CAAC,SAAS,IAAI,SAAS,WAAW,CAAC,CAAC;QAE7F,IAAI,MAAM,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,KAAK,CAAC,IAAI,CACR,kBAAkB,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,yCAAyC,CACvF,CAAC;QACJ,CAAC;QAED,IAAI,MAAM,CAAC,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC9C,KAAK,CAAC,IAAI,CAAC,4EAA4E,CAAC,CAAC;YACzF,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAC9B,yFAAyF;gBACzF,8BAA8B;gBAC9B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,MAAM,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,CAAC,CAAC;YACnE,CAAC;YACD,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QACjB,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QACrD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,KAAK,CAAC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,SAAS,EAAE,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC,CAAC;YACpE,OAAO,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7D,CAAC;QAED,yDAAyD;QACzD,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QACzB,KAAK,CAAC,IAAI,CAAC,+EAA+E,CAAC,CAAC;QAC5F,KAAK,CAAC,IAAI,CAAC,+EAA+E,CAAC,CAAC;QAC5F,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;YAChC,0FAA0F;YAC1F,yFAAyF;YACzF,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY;gBACzB,CAAC,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,WAAW,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBAClF,CAAC,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;YAC3B,0FAA0F;YAC1F,sFAAsF;YACtF,MAAM,YAAY,GAChB,CAAC,CAAC,YAAY,KAAK,SAAS;gBAC1B,CAAC,CAAC,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,YAAY,GAAG;gBAC5D,CAAC,CAAC,KAAK,CAAC;YACZ,MAAM,KAAK,GAAG,CAAC,KAAyB,EAAE,EAAE,CAC1C,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,WAAW,CAAC,KAAK,CAAC,CAAC;YACnD,KAAK,CAAC,IAAI,CACR,KAAK,IAAI,MAAM,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,CAAC,CAAC,UAAU,IAAI,KAAK,MAAM,KAAK,CAAC,CAAC,CAAC,cAAc,CAAC,MAAM,YAAY,IAAI,CACnJ,CAAC;QACJ,CAAC;QAED,kBAAkB;QAClB,KAAK,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;QACvC,KAAK,CAAC,IAAI,CACR,wGAAwG,CACzG,CAAC;QACF,KAAK,CAAC,IAAI,CACR,uGAAuG,CACxG,CAAC;QACF,KAAK,MAAM,CAAC,IAAI,KAAK,EAAE,CAAC;YACtB,MAAM,IAAI,GACR,CAAC,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC;YACtF,MAAM,GAAG,GAAG,CAAC,CAAqB,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC;YAC7E,KAAK,CAAC,IAAI,CACR,KAAK,IAAI,MAAM,GAAG,CAAC,CAAC,CAAC,gBAAgB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,kBAAkB,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,WAAW,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,aAAa,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,UAAU,CAAC,IAAI,CAC9L,CAAC;QACJ,CAAC;QAED,uBAAuB;QACvB,MAAM,eAAe,GAAG,KAAK,CAAC,MAAM,CAClC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,YAAY,KAAK,SAAS,IAAI,CAAC,CAAC,YAAY,GAAG,GAAG,CAC5D,CAAC;QACF,IAAI,eAAe,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC/B,KAAK,CAAC,IAAI,CACR,gCAAgC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,iCAAiC,CAC9I,CAAC;QACJ,CAAC;QAED,KAAK,CAAC,IAAI,CAAC,gFAAgF,CAAC,CAAC;QAE7F,OAAO,CAAC,EAAE,IAAI,EAAE,MAAe,EAAE,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7D,CAAC;CACF,CAAC,CAAC"}
|
|
1
|
+
{"version":3,"file":"compare-products.tool.js","sourceRoot":"","sources":["../../../../src/mcp-server/tools/definitions/compare-products.tool.ts"],"names":[],"mappings":"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"}
|