@cyanheads/openfoodfacts-mcp-server 0.3.3 → 0.3.5

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.
Files changed (45) hide show
  1. package/AGENTS.md +10 -6
  2. package/CLAUDE.md +10 -6
  3. package/README.md +9 -7
  4. package/changelog/0.3.x/0.3.4.md +19 -0
  5. package/changelog/0.3.x/0.3.5.md +24 -0
  6. package/changelog/template.md +7 -7
  7. package/dist/config/server-config.d.ts +6 -0
  8. package/dist/config/server-config.d.ts.map +1 -1
  9. package/dist/config/server-config.js +6 -0
  10. package/dist/config/server-config.js.map +1 -1
  11. package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.d.ts +0 -1
  12. package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.d.ts.map +1 -1
  13. package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.js +5 -7
  14. package/dist/mcp-server/tools/definitions/browse-taxonomy.tool.js.map +1 -1
  15. package/dist/mcp-server/tools/definitions/compare-products.tool.d.ts +2 -2
  16. package/dist/mcp-server/tools/definitions/compare-products.tool.d.ts.map +1 -1
  17. package/dist/mcp-server/tools/definitions/compare-products.tool.js +44 -10
  18. package/dist/mcp-server/tools/definitions/compare-products.tool.js.map +1 -1
  19. package/dist/mcp-server/tools/definitions/get-product.tool.d.ts +27 -2
  20. package/dist/mcp-server/tools/definitions/get-product.tool.d.ts.map +1 -1
  21. package/dist/mcp-server/tools/definitions/get-product.tool.js +220 -77
  22. package/dist/mcp-server/tools/definitions/get-product.tool.js.map +1 -1
  23. package/dist/mcp-server/tools/definitions/index.d.ts +39 -8
  24. package/dist/mcp-server/tools/definitions/index.d.ts.map +1 -1
  25. package/dist/mcp-server/tools/definitions/search-products.tool.d.ts +10 -3
  26. package/dist/mcp-server/tools/definitions/search-products.tool.d.ts.map +1 -1
  27. package/dist/mcp-server/tools/definitions/search-products.tool.js +21 -11
  28. package/dist/mcp-server/tools/definitions/search-products.tool.js.map +1 -1
  29. package/dist/services/openfoodfacts/openfoodfacts-service.d.ts +7 -0
  30. package/dist/services/openfoodfacts/openfoodfacts-service.d.ts.map +1 -1
  31. package/dist/services/openfoodfacts/openfoodfacts-service.js +112 -31
  32. package/dist/services/openfoodfacts/openfoodfacts-service.js.map +1 -1
  33. package/dist/services/openfoodfacts/types.d.ts +17 -1
  34. package/dist/services/openfoodfacts/types.d.ts.map +1 -1
  35. package/dist/services/openfoodfacts/types.js.map +1 -1
  36. package/dist/services/taxonomy/taxonomy-service.d.ts +0 -1
  37. package/dist/services/taxonomy/taxonomy-service.d.ts.map +1 -1
  38. package/dist/services/taxonomy/taxonomy-service.js +31 -6
  39. package/dist/services/taxonomy/taxonomy-service.js.map +1 -1
  40. package/dist/utils/markdown.d.ts +42 -0
  41. package/dist/utils/markdown.d.ts.map +1 -0
  42. package/dist/utils/markdown.js +67 -0
  43. package/dist/utils/markdown.js.map +1 -0
  44. package/package.json +5 -5
  45. package/server.json +3 -3
package/AGENTS.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Developer Protocol
2
2
 
3
3
  **Server:** openfoodfacts-mcp-server
4
- **Version:** 0.3.3
5
- **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.3`
4
+ **Version:** 0.3.5
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
@@ -42,7 +42,7 @@ export const offGetProduct = tool('off_get_product', {
42
42
  .describe('Subset of fields to return. Omitting returns all standard fields.'),
43
43
  }),
44
44
  output: z.object({
45
- barcode: z.string().describe('Barcode as returned by the API.'),
45
+ barcode: z.string().describe('The input barcode, echoed back unchanged.'),
46
46
  // No `found` flag: a missing record is the thrown not_found error, so a boolean here could
47
47
  // only ever be true. Don't advertise a state the handler cannot return — a caller that
48
48
  // branches on it never handles the path that actually fires.
@@ -60,7 +60,9 @@ export const offGetProduct = tool('off_get_product', {
60
60
  async handler(input, ctx) {
61
61
  const svc = getOpenFoodFactsService();
62
62
  const product = await svc.getProduct(input.barcode, ctx);
63
- if (!product) throw ctx.fail('not_found', `Barcode ${input.barcode} not found`);
63
+ if (!product) {
64
+ throw ctx.fail('not_found', `Barcode ${input.barcode} not found`, ctx.recoveryFor('not_found'));
65
+ }
64
66
  return { barcode: input.barcode, product };
65
67
  },
66
68
 
@@ -143,7 +145,7 @@ Handlers receive a unified `ctx` object. Key properties:
143
145
 
144
146
  Handlers throw — the framework catches, classifies, and formats.
145
147
 
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.
148
+ **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
149
 
148
150
  ```ts
149
151
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
@@ -196,6 +198,8 @@ src/
196
198
  types.ts # Domain types
197
199
  taxonomy/
198
200
  taxonomy-service.ts # Tag vocabulary — live resolution, offline sample, merge/fallback policy
201
+ utils/
202
+ markdown.ts # Contextual Markdown escaping for crowd-sourced values in content[]
199
203
  mcp-server/
200
204
  tools/definitions/
201
205
  get-product.tool.ts # off_get_product
@@ -242,7 +246,7 @@ Available skills:
242
246
  | `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
243
247
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
244
248
  | `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 |
245
- | `release-pr-review` | Review pass on an open release PR — simplifier + correctness review, fixup commits autosquashed into the stack, PR body kept in sync. Release PR mode only |
249
+ | `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 |
246
250
  | `release-and-publish` | Fast-forward merge (release PR mode) + tag + push + npm + MCP Registry + GH Release + Docker. Picks up from `git-wrapup` |
247
251
  | `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
248
252
  | `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.3
5
- **Framework:** [@cyanheads/mcp-ts-core](https://www.npmjs.com/package/@cyanheads/mcp-ts-core) `^0.13.3`
4
+ **Version:** 0.3.5
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
@@ -42,7 +42,7 @@ export const offGetProduct = tool('off_get_product', {
42
42
  .describe('Subset of fields to return. Omitting returns all standard fields.'),
43
43
  }),
44
44
  output: z.object({
45
- barcode: z.string().describe('Barcode as returned by the API.'),
45
+ barcode: z.string().describe('The input barcode, echoed back unchanged.'),
46
46
  // No `found` flag: a missing record is the thrown not_found error, so a boolean here could
47
47
  // only ever be true. Don't advertise a state the handler cannot return — a caller that
48
48
  // branches on it never handles the path that actually fires.
@@ -60,7 +60,9 @@ export const offGetProduct = tool('off_get_product', {
60
60
  async handler(input, ctx) {
61
61
  const svc = getOpenFoodFactsService();
62
62
  const product = await svc.getProduct(input.barcode, ctx);
63
- if (!product) throw ctx.fail('not_found', `Barcode ${input.barcode} not found`);
63
+ if (!product) {
64
+ throw ctx.fail('not_found', `Barcode ${input.barcode} not found`, ctx.recoveryFor('not_found'));
65
+ }
64
66
  return { barcode: input.barcode, product };
65
67
  },
66
68
 
@@ -143,7 +145,7 @@ Handlers receive a unified `ctx` object. Key properties:
143
145
 
144
146
  Handlers throw — the framework catches, classifies, and formats.
145
147
 
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.
148
+ **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
149
 
148
150
  ```ts
149
151
  import { JsonRpcErrorCode } from '@cyanheads/mcp-ts-core/errors';
@@ -196,6 +198,8 @@ src/
196
198
  types.ts # Domain types
197
199
  taxonomy/
198
200
  taxonomy-service.ts # Tag vocabulary — live resolution, offline sample, merge/fallback policy
201
+ utils/
202
+ markdown.ts # Contextual Markdown escaping for crowd-sourced values in content[]
199
203
  mcp-server/
200
204
  tools/definitions/
201
205
  get-product.tool.ts # off_get_product
@@ -242,7 +246,7 @@ Available skills:
242
246
  | `code-simplifier` | Post-session cleanup against `git diff` — modernize syntax, consolidate duplication, align with the codebase |
243
247
  | `polish-docs-meta` | Finalize docs, README, metadata, and agent protocol for shipping |
244
248
  | `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 |
245
- | `release-pr-review` | Review pass on an open release PR — simplifier + correctness review, fixup commits autosquashed into the stack, PR body kept in sync. Release PR mode only |
249
+ | `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 |
246
250
  | `release-and-publish` | Fast-forward merge (release PR mode) + tag + push + npm + MCP Registry + GH Release + Docker. Picks up from `git-wrapup` |
247
251
  | `maintenance` | Investigate changelogs, adopt upstream changes, sync skills to agent dirs |
248
252
  | `orchestrations` | Chain task skills into a gated multi-phase pipeline — build-out, QA-fix, update-ship — when you can spawn sub-agents |
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
 
8
8
  <div align="center">
9
9
 
10
- [![Version](https://img.shields.io/badge/Version-0.3.3-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/openfoodfacts-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.0.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/openfoodfacts-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/openfoodfacts-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.4.0-blueviolet.svg?style=flat-square)](https://bun.sh/)
10
+ [![Version](https://img.shields.io/badge/Version-0.3.5-blue.svg?style=flat-square)](./CHANGELOG.md) [![License](https://img.shields.io/badge/License-Apache%202.0-orange.svg?style=flat-square)](./LICENSE) [![Docker](https://img.shields.io/badge/Docker-ghcr.io-2496ED?style=flat-square&logo=docker&logoColor=white)](https://github.com/users/cyanheads/packages/container/package/openfoodfacts-mcp-server) [![MCP SDK](https://img.shields.io/badge/MCP%20SDK-^2.0.0-green.svg?style=flat-square)](https://modelcontextprotocol.io/) [![npm](https://img.shields.io/npm/v/@cyanheads/openfoodfacts-mcp-server?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@cyanheads/openfoodfacts-mcp-server) [![TypeScript](https://img.shields.io/badge/TypeScript-^7.0.2-3178C6.svg?style=flat-square)](https://www.typescriptlang.org/) [![Bun](https://img.shields.io/badge/Bun-v1.4.0-blueviolet.svg?style=flat-square)](https://bun.sh/)
11
11
 
12
12
  </div>
13
13
 
@@ -35,7 +35,7 @@ Food product data from Open Food Facts, a crowd-sourced database of 3M+ packaged
35
35
 
36
36
  | Tool | Description |
37
37
  |:-----|:------------|
38
- | `off_get_product` | Fetch a packaged food product by barcode. Returns name, brand, quantity, ingredients, allergens, additives, Nutri-Score, NOVA group, Green-Score, nutrition per 100g/serving, categories, labels, and data completeness. |
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
39
  | `off_search_products` | Search by text query, structured tag filters (category, brand, label, allergen, additive, Nutri-Score grade, NOVA group, country), 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. |
@@ -45,8 +45,10 @@ Food product data from Open Food Facts, a crowd-sourced database of 3M+ packaged
45
45
  ### `off_get_product` <sub>tool</sub>
46
46
 
47
47
  - Accepts 8–14 digit barcodes (EAN-13, EAN-8, UPC-A, UPC-E)
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–e, NOVA 1–4, Green-Score/Eco-Score, 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 as canonical tag IDs, front image URL, and data completeness score (0–1)
49
- - Optional `fields` parameter restricts the response to a subset (e.g., scores only, or nutrition only)
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
+ - `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
+ - `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
+ - 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
50
52
  - Open Food Facts is crowd-sourced — a missing field means "not yet entered by contributors," not that the attribute is absent from the actual product
51
53
  - A barcode no contributor has recorded raises the `not_found` error carrying a recovery hint — it is never returned as an empty result
52
54
 
@@ -78,7 +80,7 @@ Food product data from Open Food Facts, a crowd-sourced database of 3M+ packaged
78
80
 
79
81
  ### `off_browse_taxonomy` <sub>tool</sub>
80
82
 
81
- - 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
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. 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
82
84
  - `nova_groups` and `nutrition_grades` are closed vocabularies, returned complete, with bare `"1"`–`"4"` / `"a"`–`"e"` ids
83
85
  - 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
84
86
  - `limit` controls results (1–100, default 20); there is no offset or page — narrow the search term instead
@@ -91,8 +93,8 @@ Built on [`@cyanheads/mcp-ts-core`](https://github.com/cyanheads/mcp-ts-core): s
91
93
  Open Food Facts-specific:
92
94
 
93
95
  - No API key required — the identifying `User-Agent` header (required by OFF terms) is baked into the service layer
94
- - 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. A local refusal says so — it never reports itself as an Open Food Facts rate limit
95
- - Automatic retry (3 attempts, 500ms base) for transient failures only — 5xx, timeouts, and 429 (honoring `Retry-After`), with HTML error page detection for 503 during high load. A 4xx is never retried; the upstream's own explanation is surfaced instead
96
+ - 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 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
96
98
  - 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)
97
99
  - 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
98
100
 
@@ -0,0 +1,19 @@
1
+ ---
2
+ summary: "Field-subset dependency expansion, three new product fields, escaped Markdown rendering, per-request rate-limit charging, and a trimmed error-data contract on off_get_product."
3
+ breaking: false
4
+ security: false
5
+ ---
6
+
7
+ # 0.3.4 — 2026-09-17
8
+
9
+ ## Added
10
+
11
+ - **`traces_tags`, `ingredients_analysis_tags`, `countries_tags` on `off_get_product`** — the "may contain" allergen warning, the computed vegan/vegetarian/palm-oil verdict, and countries of sale, each resolvable through `fields` subsets like every other field (#32).
12
+
13
+ ## Fixed
14
+
15
+ - **`off_get_product` field subsets now fetch their dependencies** — requesting `nutriments` also fetches `serving_size`/`serving_quantity`/`serving_quantity_unit` so per-serving figures carry a denominator, and `serving_quantity_unit` fetches the quantity it describes. The heading no longer reads `## Unknown product` when `product_name` was simply outside the requested subset (#23).
16
+ - **`off_compare_products` no longer reports an all-failed batch as "no products found"** — the zero-found summary now distinguishes barcodes that failed to fetch from barcodes Open Food Facts confirmed missing, and skips the retry suggestion when every failure is a non-retryable `upstream_rejected` (#29).
17
+ - **Crowd-sourced text is escaped before it reaches `content[]`** — product names, ingredient text, tag IDs, and grades can carry Markdown metacharacters that previously altered the rendered structure (headings, table columns, an unterminated code fence). `structuredContent` is unaffected; a new `src/utils/markdown.ts` holds one escaper per rendering context (#27).
18
+ - **Rate limiters now charge one budget slot per upstream HTTP attempt, not per tool call** — a charge previously covered the retry boundary's up-to-4 attempts, so a failing upstream could send 4x the configured per-minute ceiling before the limiter noticed. A budget exhausted mid-retry now fails fast with `rate_limited` instead of sleeping out the retry window (#25).
19
+ - **`structuredContent.error.data` no longer carries `body`, `responseBody`, `statusCode`, `statusText`, or `errorSource`** — these mirrored a spread of the framework's raw fetch-error diagnostics, including the upstream response body twice, and could hand a client a rendered Open Food Facts error page. The published contract is now an explicit allowlist (`status`, `retryAfter`, `retryAttempts`, `operation`, plus per-call context); a client reading the dropped fields sees them disappear. The upstream explanation carried in `message` is bounded to 200 characters and stripped of angle brackets on every path, where a JSON `detail` string previously passed through verbatim at any length (#26).
@@ -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
@@ -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, like a tag's theme line. Quotes required: unquoted YAML treats
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"): the entry's `summary:` as the
123
- theme line without the version, flat headline bullets — no Keep-a-Changelog
124
- section headers, no gates line — at most one deps line, issue backlinks,
125
- and the changelog link last. In release-PR mode the `git-wrapup` skill
126
- authors that digest as the PR body's `## Changes` and the tag copies it.
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
@@ -11,6 +11,12 @@ import { z } from '@cyanheads/mcp-ts-core';
11
11
  * published one — that is what the env vars are for, alongside operators running their own Product
12
12
  * Opener instance who can raise them.
13
13
  *
14
+ * Each number counts upstream HTTP requests, not tool calls: a slot is charged per attempt from
15
+ * inside the retry boundary, so a retried request spends its own slot and the configured figure is
16
+ * what Open Food Facts can actually see from this server. When a budget runs out mid-sequence the
17
+ * retries stop and the caller gets the declared `rate_limited` failure with the wait until a slot
18
+ * frees.
19
+ *
14
20
  * The taxonomy tier is covered by neither published figure: it calls search.openfoodfacts.org
15
21
  * (search-a-licious), a separate deployment the published limits do not name and for which no limit
16
22
  * is documented. Its default matches the search tier as a conservative stand-in.
@@ -1 +1 @@
1
- {"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,kBAAkB;;;;;iBAuBtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,4DAA4D;AAC5D,wBAAgB,eAAe,IAAI,YAAY,CAQ9C"}
1
+ {"version":3,"file":"server-config.d.ts","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAG3C;;;;;;;;;;;;;;;;;GAiBG;AACH,QAAA,MAAM,kBAAkB;;;;;iBAuBtB,CAAC;AAEH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAI9D,4DAA4D;AAC5D,wBAAgB,eAAe,IAAI,YAAY,CAQ9C"}
@@ -12,6 +12,12 @@ import { parseEnvConfig } from '@cyanheads/mcp-ts-core/config';
12
12
  * published one — that is what the env vars are for, alongside operators running their own Product
13
13
  * Opener instance who can raise them.
14
14
  *
15
+ * Each number counts upstream HTTP requests, not tool calls: a slot is charged per attempt from
16
+ * inside the retry boundary, so a retried request spends its own slot and the configured figure is
17
+ * what Open Food Facts can actually see from this server. When a budget runs out mid-sequence the
18
+ * retries stop and the caller gets the declared `rate_limited` failure with the wait until a slot
19
+ * frees.
20
+ *
15
21
  * The taxonomy tier is covered by neither published figure: it calls search.openfoodfacts.org
16
22
  * (search-a-licious), a separate deployment the published limits do not name and for which no limit
17
23
  * is documented. Its default matches the search tier as a conservative stand-in.
@@ -1 +1 @@
1
- {"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D;;;;;;;;;;;GAWG;AACH,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,OAAO,CAAC,iCAAiC,CAAC;SAC1C,QAAQ,CAAC,8BAA8B,CAAC;IAC3C,gBAAgB,EAAE,CAAC,CAAC,MAAM;SACvB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,wCAAwC,CAAC;IACrD,eAAe,EAAE,CAAC,CAAC,MAAM;SACtB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,kCAAkC,CAAC;IAC/C,iBAAiB,EAAE,CAAC,CAAC,MAAM;SACxB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,+CAA+C,CAAC;CAC7D,CAAC,CAAC;AAIH,IAAI,OAAiC,CAAC;AAEtC,4DAA4D;AAC5D,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,cAAc,CAAC,kBAAkB,EAAE;QAC7C,OAAO,EAAE,cAAc;QACvB,gBAAgB,EAAE,wBAAwB;QAC1C,eAAe,EAAE,uBAAuB;QACxC,iBAAiB,EAAE,yBAAyB;KAC7C,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,CAAC"}
1
+ {"version":3,"file":"server-config.js","sourceRoot":"","sources":["../../src/config/server-config.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,CAAC,EAAE,MAAM,wBAAwB,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IAClC,OAAO,EAAE,CAAC;SACP,MAAM,EAAE;SACR,OAAO,CAAC,iCAAiC,CAAC;SAC1C,QAAQ,CAAC,8BAA8B,CAAC;IAC3C,gBAAgB,EAAE,CAAC,CAAC,MAAM;SACvB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,wCAAwC,CAAC;IACrD,eAAe,EAAE,CAAC,CAAC,MAAM;SACtB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,kCAAkC,CAAC;IAC/C,iBAAiB,EAAE,CAAC,CAAC,MAAM;SACxB,MAAM,EAAE;SACR,GAAG,EAAE;SACL,GAAG,CAAC,CAAC,CAAC;SACN,OAAO,CAAC,EAAE,CAAC;SACX,QAAQ,CAAC,+CAA+C,CAAC;CAC7D,CAAC,CAAC;AAIH,IAAI,OAAiC,CAAC;AAEtC,4DAA4D;AAC5D,MAAM,UAAU,eAAe;IAC7B,OAAO,KAAK,cAAc,CAAC,kBAAkB,EAAE;QAC7C,OAAO,EAAE,cAAc;QACvB,gBAAgB,EAAE,wBAAwB;QAC1C,eAAe,EAAE,uBAAuB;QACxC,iBAAiB,EAAE,yBAAyB;KAC7C,CAAC,CAAC;IACH,OAAO,OAAO,CAAC;AACjB,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;AAGjD,eAAO,MAAM,qBAAqB;;;;;;;;;;;;;;;;;;;;;;;;;EAiJhC,CAAC"}
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"}
@@ -4,6 +4,7 @@
4
4
  */
5
5
  import { tool, z } from '@cyanheads/mcp-ts-core';
6
6
  import { getTaxonomyService } from '../../../services/taxonomy/taxonomy-service.js';
7
+ import { mdInline, mdInlineCode } from '../../../utils/markdown.js';
7
8
  export const offBrowseTaxonomyTool = tool('off_browse_taxonomy', {
8
9
  title: 'Browse Food Facts Taxonomy',
9
10
  description: 'Resolve a human term to the canonical Open Food Facts tag ID that off_search_products filters on. Covers categories, labels/certifications, allergens, additives, countries, NOVA groups, and Nutri-Score grades. Pass a search term to resolve against the Open Food Facts vocabulary, which holds tens of thousands of tags; omitting it returns only a small reference list for each facet except NOVA groups and Nutri-Score grades, which are complete. Most tag IDs use the "en:" prefix (e.g. "en:organic", "en:no-gluten", "en:crustaceans"); NOVA groups return bare digits "1"-"4" and Nutri-Score grades bare letters "a"-"e". Pass the id through to off_search_products exactly as returned. Category tags are frequently plural ("kombucha" resolves to "en:kombuchas"), so use the returned id rather than constructing one.',
@@ -34,7 +35,7 @@ export const offBrowseTaxonomyTool = tool('off_browse_taxonomy', {
34
35
  .min(1)
35
36
  .max(100)
36
37
  .default(20)
37
- .describe('Maximum entries to return (1–100, default 20). There is no offset or page input: Open Food Facts returns only the first `limit` matches for a term and offers no cursor, so narrow the search term rather than paging.'),
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.'),
38
39
  }),
39
40
  output: z.object({
40
41
  facet: z.string().describe('The facet name that was queried (echoes the input).'),
@@ -45,10 +46,6 @@ export const offBrowseTaxonomyTool = tool('off_browse_taxonomy', {
45
46
  .string()
46
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.'),
47
48
  name: z.string().describe('Human-readable display name (e.g. "Organic").'),
48
- products: z
49
- .number()
50
- .optional()
51
- .describe('Approximate count of products with this tag. Not available for all facets.'),
52
49
  })
53
50
  .describe('A single taxonomy tag entry with its canonical ID and display name.'))
54
51
  .describe('Matching tag entries.'),
@@ -112,8 +109,9 @@ export const offBrowseTaxonomyTool = tool('off_browse_taxonomy', {
112
109
  return [{ type: 'text', text: lines.join('\n') }];
113
110
  }
114
111
  for (const tag of result.tags) {
115
- const products = tag.products !== undefined ? ` (~${tag.products.toLocaleString()} products)` : '';
116
- lines.push(`- \`${tag.id}\` — ${tag.name}${products}`);
112
+ // A backtick in a tag ID would close a single-backtick span and render the rest of the ID as
113
+ // prose, so the span's delimiter is sized past whatever the ID carries.
114
+ lines.push(`- ${mdInlineCode(tag.id)} — ${mdInline(tag.name)}`);
117
115
  }
118
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.*');
119
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":"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"}
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;AA4F3E,eAAO,MAAM,sBAAsB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;cA0QjC,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;AAkI3E,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 { mdInline, mdTableCell } from '../../../utils/markdown.js';
8
9
  /** Fields needed for comparison — narrower than full product fetch. */
9
10
  const COMPARE_FIELDS = 'product_name,brands,nutriscore_grade,nova_group,ecoscore_grade,nutriments,completeness';
10
11
  /** Extract a numeric value from the raw nutriments map. */
@@ -31,6 +32,34 @@ function describeFailure(barcode, error) {
31
32
  error: error instanceof Error ? error.message : String(error),
32
33
  };
33
34
  }
35
+ /**
36
+ * Reasons whose declared contract says a repeat of the same request can succeed. `upstream_rejected`
37
+ * is the one that cannot — the tool's own contract for it says the request will be refused again —
38
+ * so an all-rejected batch is never told to wait and retry.
39
+ */
40
+ const RETRYABLE_REASONS = new Set(['upstream_error', 'upstream_timeout', 'rate_limited']);
41
+ /**
42
+ * The closing line of a batch in which no barcode resolved to a product. The structured result
43
+ * already separates the two settlements — a fetch that failed taught nothing about its barcode,
44
+ * while a `not_found` barcode was answered for — so the text reads them off rather than flattening
45
+ * both into one "no products found" that fits neither.
46
+ */
47
+ function zeroFoundSummary(notFound, failed) {
48
+ const uncheckable = failed.length > 0;
49
+ const missing = notFound.length > 0;
50
+ if (uncheckable && missing) {
51
+ return (`No barcode resolved to a product: Open Food Facts holds no contributor record for ${notFound.length} ` +
52
+ `of them, and ${failed.length} could not be checked at all because the fetch failed.`);
53
+ }
54
+ if (uncheckable) {
55
+ const recovery = failed.some((f) => RETRYABLE_REASONS.has(f.reason))
56
+ ? 'Retry them once Open Food Facts is answering again.'
57
+ : 'Open Food Facts refused every request as formed, so check the barcode digits before sending them again.';
58
+ return `No barcode could be checked — every fetch failed, so nothing was learned about these products. ${recovery}`;
59
+ }
60
+ return ('Open Food Facts answered for every barcode and holds no contributor record for any of them. ' +
61
+ 'The products may exist without being entered yet — check the digits, or find them by name with off_search_products.');
62
+ }
34
63
  /** Build a comparison row from a raw product. */
35
64
  function buildCompareRow(barcode, raw) {
36
65
  if (!raw)
@@ -105,7 +134,7 @@ export const offCompareProductsTool = tool('off_compare_products', {
105
134
  nutriscore_grade: z
106
135
  .string()
107
136
  .optional()
108
- .describe('Nutri-Score letter (a–e). Absent when not computed.'),
137
+ .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.'),
109
138
  nova_group: z
110
139
  .number()
111
140
  .optional()
@@ -113,7 +142,7 @@ export const offCompareProductsTool = tool('off_compare_products', {
113
142
  ecoscore_grade: z
114
143
  .string()
115
144
  .optional()
116
- .describe('Green-Score/Eco-Score (a–e or "unknown"). Often absent.'),
145
+ .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.'),
117
146
  energy_kcal_100g: z
118
147
  .number()
119
148
  .optional()
@@ -170,7 +199,7 @@ export const offCompareProductsTool = tool('off_compare_products', {
170
199
  {
171
200
  reason: 'upstream_error',
172
201
  code: JsonRpcErrorCode.ServiceUnavailable,
173
- when: 'Open Food Facts returns 5xx, serves an HTML error page, or is unreachable — surfaced per barcode in failed[]',
202
+ 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[]',
174
203
  retryable: true,
175
204
  recovery: 'Retry the barcodes listed in failed after a brief pause. Rows that already resolved are kept, so only the failures need repeating.',
176
205
  },
@@ -184,7 +213,7 @@ export const offCompareProductsTool = tool('off_compare_products', {
184
213
  {
185
214
  reason: 'upstream_rejected',
186
215
  code: JsonRpcErrorCode.InvalidParams,
187
- when: 'Open Food Facts answers 4xx for a barcode — surfaced per barcode in failed[]',
216
+ when: 'Open Food Facts answers 4xx or 501 Not Implemented for a barcode — surfaced per barcode in failed[]',
188
217
  retryable: false,
189
218
  recovery: 'Do not retry unchanged. Check the digits of the barcodes listed in failed, then look them up individually with off_get_product.',
190
219
  },
@@ -242,13 +271,15 @@ export const offCompareProductsTool = tool('off_compare_products', {
242
271
  if (result.failed && result.failed.length > 0) {
243
272
  lines.push('**Fetch failed** — these barcodes were not checked, not confirmed missing:');
244
273
  for (const f of result.failed) {
245
- lines.push(`- ${f.barcode} (${f.reason}): ${f.error}`);
274
+ // The upstream's own explanation rides in `error`, so it is escaped like any other value
275
+ // this server did not author.
276
+ lines.push(`- ${f.barcode} (${f.reason}): ${mdInline(f.error)}`);
246
277
  }
247
278
  lines.push('');
248
279
  }
249
280
  const found = result.products.filter((p) => p.found);
250
281
  if (found.length === 0) {
251
- lines.push('No products found. Try off_get_product on individual barcodes to verify.');
282
+ lines.push(zeroFoundSummary(result.not_found, result.failed ?? []));
252
283
  return [{ type: 'text', text: lines.join('\n') }];
253
284
  }
254
285
  // Scores table — includes all products with found status
@@ -256,29 +287,32 @@ export const offCompareProductsTool = tool('off_compare_products', {
256
287
  lines.push('| Product | Barcode | Found | Nutri-Score | NOVA | Eco-Score | Completeness |');
257
288
  lines.push('|:--------|:--------|:------|:------------|:-----|:----------|:-------------|');
258
289
  for (const p of result.products) {
290
+ // Product names and brands are contributor-edited: a bare pipe would add a column to this
291
+ // row and a line break would end it, so both are neutralized before the cell is written.
259
292
  const name = p.product_name
260
- ? `${p.product_name}${p.brands ? ` (${p.brands})` : ''}`
293
+ ? `${mdTableCell(p.product_name)}${p.brands ? ` (${mdTableCell(p.brands)})` : ''}`
261
294
  : `Barcode ${p.barcode}`;
262
295
  // The exact scalar rides alongside the rounded percentage: 0.7875 and 0.79 both render as
263
296
  // "79%", and a text-only client has no second call that would recover the difference.
264
297
  const completeness = p.completeness !== undefined
265
298
  ? `${Math.round(p.completeness * 100)}% (${p.completeness})`
266
299
  : 'N/A';
267
- lines.push(`| ${name} | ${p.barcode} | ${p.found} | ${p.nutriscore_grade ?? 'N/A'} | ${p.nova_group ?? 'N/A'} | ${p.ecoscore_grade ?? 'N/A'} | ${completeness} |`);
300
+ const grade = (value) => value === undefined ? 'N/A' : mdTableCell(value);
301
+ lines.push(`| ${name} | ${p.barcode} | ${p.found} | ${grade(p.nutriscore_grade)} | ${p.nova_group ?? 'N/A'} | ${grade(p.ecoscore_grade)} | ${completeness} |`);
268
302
  }
269
303
  // Nutrition table
270
304
  lines.push('\n### Nutrition per 100g');
271
305
  lines.push('| Product | Energy (kcal) | Fat (g) | Sat. Fat (g) | Sugars (g) | Salt (g) | Protein (g) | Fiber (g) |');
272
306
  lines.push('|:--------|:-------------|:--------|:-------------|:-----------|:---------|:------------|:----------|');
273
307
  for (const p of found) {
274
- const name = p.product_name ?? `Barcode ${p.barcode}`;
308
+ const name = p.product_name === undefined ? `Barcode ${p.barcode}` : mdTableCell(p.product_name);
275
309
  const fmt = (v) => (v !== undefined ? String(v) : 'N/A');
276
310
  lines.push(`| ${name} | ${fmt(p.energy_kcal_100g)} | ${fmt(p.fat_100g)} | ${fmt(p.saturated_fat_100g)} | ${fmt(p.sugars_100g)} | ${fmt(p.salt_100g)} | ${fmt(p.proteins_100g)} | ${fmt(p.fiber_100g)} |`);
277
311
  }
278
312
  // Completeness notices
279
313
  const lowCompleteness = found.filter((p) => p.completeness !== undefined && p.completeness < 0.5);
280
314
  if (lowCompleteness.length > 0) {
281
- lines.push(`\n*Low completeness (< 50%): ${lowCompleteness.map((p) => p.product_name ?? p.barcode).join(', ')} — many fields may be missing.*`);
315
+ lines.push(`\n*Low completeness (< 50%): ${lowCompleteness.map((p) => mdInline(p.product_name ?? p.barcode)).join(', ')} — many fields may be missing.*`);
282
316
  }
283
317
  lines.push('\n*Data: Open Food Facts (ODbL 1.0) — crowd-sourced. "N/A" = not yet entered.*');
284
318
  return [{ type: 'text', text: lines.join('\n') }];
@@ -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;AAG5F,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,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,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,OAAO,KAAK,CAAC,CAAC,MAAM,MAAM,CAAC,CAAC,KAAK,EAAE,CAAC,CAAC;YACzD,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,0EAA0E,CAAC,CAAC;YACvF,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,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY;gBACzB,CAAC,CAAC,GAAG,CAAC,CAAC,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBACxD,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,KAAK,CAAC,IAAI,CACR,KAAK,IAAI,MAAM,CAAC,CAAC,OAAO,MAAM,CAAC,CAAC,KAAK,MAAM,CAAC,CAAC,gBAAgB,IAAI,KAAK,MAAM,CAAC,CAAC,UAAU,IAAI,KAAK,MAAM,CAAC,CAAC,cAAc,IAAI,KAAK,MAAM,YAAY,IAAI,CACvJ,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,GAAG,CAAC,CAAC,YAAY,IAAI,WAAW,CAAC,CAAC,OAAO,EAAE,CAAC;YACtD,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,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,iCAAiC,CACpI,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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"}