Skip to main content
Glama

openfoodfacts-mcp-server

Server Details

Barcode lookup, nutrition search, and product comparison for 3M+ crowd-sourced food products.

If you are the author of this connector, you can claim ownership with GitHub, an HTTP challenge, or a DNS record. Claimed connector authors can inspect health checks, view analytics, and manage their listing.
Status
Healthy
Last Tested
Transport
Streamable HTTP · MCP 2025-11-25
URL
Repository
cyanheads/openfoodfacts-mcp-server
GitHub Stars
1
Server Listing
@cyanheads/openfoodfacts-mcp-server

TDQS

A4.7/5.0

Scored across 4 tools

Disambiguation5/5

Each of the four tools has a clearly distinct purpose: taxonomy resolution, product search, product detail retrieval, and multi-product comparison. There is no overlap in what an agent would use each for.

Naming Consistency5/5

All tools follow the same off_ prefix plus verb_noun pattern: browse_taxonomy, compare_products, get_product, search_products. The naming is uniform and predictable.

Tool Count5/5

Four tools is well-scoped for a read-only Open Food Facts server, covering search, retrieval, taxonomy resolution, and comparison without unnecessary bloat or missing core functionality.

Completeness5/5

The set covers the full read workflow: resolving tag IDs, searching with structured filters, fetching full product details, and comparing multiple products. No significant gaps for the stated domain.

Available Tools

4 tools
off_browse_taxonomyBrowse Food Facts TaxonomyA
Read-onlyIdempotent
Inspect

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.

ParametersJSON Schema
NameRequiredDescriptionDefault
facetYes"categories" covers food categories (en:cheeses, en:breakfast-cereals). "labels" covers certifications (en:organic, en:fair-trade). "allergens" covers declared allergens (en:milk, en:gluten). "additives" covers E-numbers (en:e322). "countries" covers country-of-sale tags (en:france). "nova_groups" and "nutrition_grades" are closed vocabularies returned complete; the other five are resolved against the Open Food Facts taxonomy.
limitNoMaximum 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.
searchNoTerm to resolve. Matched case-insensitively as a substring of the tag ID, the display name, or a common synonym of either ("shellfish" resolves to en:crustaceans, "gluten free" to en:no-gluten). A single word works best ("hummus", not "hummus dip"). Omit only to see a small reference list — Open Food Facts cannot list the full vocabulary without a term, so an unfiltered call is not a view of the full facet.

Output Schema

ParametersJSON Schema
NameRequiredDescription
capNoThe limit that was applied.
tagsNoMatching tag entries.
errorNoPresent when the call failed. Absent on success.
facetNoThe facet name that was queried (echoes the input).
shownNoNumber of tags returned.
noticeNoCaveat about the answer — that the listing is a limited reference list rather than the full vocabulary, that Open Food Facts was unreachable, or that nothing matched and why.
truncatedNoTrue when more tags exist beyond the limit.
total_in_facetNoTotal entries in this facet. Present only for nova_groups and nutrition_grades, whose vocabularies are closed and complete. Absent for the other facets: Open Food Facts reports no match total and cannot enumerate them, so no figure would be a real one.

TDQS

A4.5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already mark the tool read-only, open-world, and idempotent, but the description adds substantial behavioral context: omitting the search term returns only a small reference list, NOVA groups and Nutri-Score grades are complete, tag ID formats vary by facet, and Open Food Facts cannot list the full vocabulary without a term. It also warns about pluralization and the lack of pagination beyond the first `limit` matches, all useful beyond the structured data.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is a compact, information-dense paragraph with the core purpose front-loaded. Every sentence adds a distinct piece of guidance: coverage, behavior with/without a term, ID formatting, and a warning against constructing IDs. No filler or redundant statements.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present and 100% parameter description coverage, the tool definition is fully self-contained for correct invocation. The description covers edge cases like omitted search, closed vocabularies, prefix conventions, and the absence of pagination. An agent has everything needed to decide when to call and how to interpret the ID results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema already documents each parameter thoroughly. The description repeats some of this, but adds minor value with the 'pass the id through exactly as returned' and pluralization notes. The extra info mostly concerns output or usage rather than new parameter semantics, so the baseline of 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The opening sentence states a specific verb and resource: 'Resolve a human term to the canonical Open Food Facts tag ID that off_search_products filters on.' It enumerates the covered facets and explicitly ties the tool to its sibling, making it unmistakable what this tool does versus searching or comparing products.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description clearly establishes when to use this tool: pass a term to resolve for off_search_products filters, or omit it to get a small reference list. It also warns against paging and advises narrowing search terms. It doesn't explicitly state when not to use it relative to off_compare_products or off_get_product, but the purpose is distinct enough that alternatives are not needed.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

off_compare_productsCompare Food Products Side-by-SideA
Read-onlyIdempotent
Inspect

Side-by-side nutrition and scoring comparison for 2–10 products by barcode. Returns a normalized table of energy (kcal/100g), fat, saturated fat, sugars, salt, protein, fiber, Nutri-Score, NOVA group, and Green-Score. Designed for "which of these cereals is healthiest?" or "compare these pasta brands" workflows. Missing nutrition data for any product is preserved as absent — comparisons are not imputed. A batch is not all-or-nothing: barcodes that resolve are returned even when others fail, with confirmed-missing barcodes listed in not_found and failed fetches listed separately in failed. Scores carry regional formula caveats. Data under ODbL 1.0 — cite Open Food Facts in downstream use.

ParametersJSON Schema
NameRequiredDescriptionDefault
barcodesYes2–10 barcodes to compare, returned as one row each in input order. Example: ["3017620422003", "7622210100146"].

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
failedNoBarcodes whose fetch failed, with the per-barcode reason. Absent when every fetch completed. A barcode listed here is unknown, not absent from Open Food Facts — retry it with off_get_product before concluding anything about the product.
productsNoComparison 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.
not_foundNoBarcodes 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.
succeededNoNumber of barcodes that resolved to a found product.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly, openWorld, and idempotent hints, the description discloses key behaviors: missing data is preserved (not imputed), batches are not all-or-nothing with separate handling of not_found and failed barcodes, regional formula caveats exist, and attribution is required under ODbL 1.0. This adds substantial value over the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-organized and front-loaded with the core purpose, then covers exceptions, licensing, and caveats. It is slightly longer than necessary but each sentence adds distinct information, so it earns a 4 rather than a 5.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description covers purpose, parameter constraints, error behavior, regional caveats, and licensing. An output schema exists, so return-value details are not required in the description. All essential information for correctly invoking the tool is present, and sibling tools provide further context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100% and already describes the barcodes parameter including min/max and input-order behavior. The description repeats the input-order detail and adds output-field information, but this does not clarify the parameter's semantics beyond the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool compares 2–10 products side-by-side by barcode, lists the specific nutrition and scoring fields, and gives concrete example workflows ('which of these cereals is healthiest?'). It distinguishes itself from siblings: off_get_product (single product), off_search_products (search), off_browse_taxonomy (browse).

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit example use cases and explains the batch behavior (partial success, not_found vs failed). It does not explicitly name alternative tools for single-product lookups, but the comparison workflow is clearly the intended use. The distinction from siblings is implied rather than stated, so it falls short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

off_get_productGet Food Product by BarcodeA
Read-onlyIdempotent
Inspect

Fetch a packaged food product by barcode (EAN-13 or UPC) from Open Food Facts. Returns the product name, brand, quantity, ingredients (raw text and parsed list), declared allergens, trace allergens the label warns about, additives, the product-level vegan/vegetarian/palm-oil analysis, computed scores (Nutri-Score a–e, NOVA 1–4, Green-Score), nutrition per 100g and per serving, categories, labels, packaging, origins, countries of sale, image URL, and data completeness. Open Food Facts is a crowd-sourced database — a missing field means "not yet entered by contributors," not that the attribute is absent from the actual product. Computed scores carry regional formula caveats and are indicators, not absolute rankings. Data is under ODbL 1.0 — cite Open Food Facts in downstream use.

ParametersJSON Schema
NameRequiredDescriptionDefault
fieldsNoSubset of fields to return. Omitting returns all standard fields. Use to reduce payload when only scores or ingredients are needed. A field that cannot be read on its own arrives with what it depends on: nutriments brings serving_size, serving_quantity, and serving_quantity_unit so per-serving figures carry their denominator, and serving_quantity_unit brings the quantity it describes. requested_fields echoes the full set that was fetched.
barcodeYesEAN-13 or UPC barcode (8–14 digits). The primary key for Open Food Facts. Example: "3017620422003" (Nutella FR).

Output Schema

ParametersJSON Schema
NameRequiredDescription
errorNoPresent when the call failed. Absent on success.
barcodeNoBarcode as returned by the API.
productNoProduct data. Always present on a successful call — a barcode with no contributor record raises the not_found error instead of returning an empty result.
requested_fieldsNoThe field subset that was fetched, when the caller passed `fields` — the requested fields plus the ones they depend on, so every field that can appear in `product` is named here. Absent means all standard fields were requested. Sections outside this subset are omitted because they were not requested — not because Open Food Facts lacks the data.

TDQS

A4.4/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, and idempotentHint; the description adds valuable behavioral context beyond those: crowd-sourced data means missing fields are 'not yet entered by contributors,' computed scores have regional formula caveats and are indicators, and ODbL licensing requires attribution. This directly shapes agent expectations about data reliability and downstream use.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is long but front-loads the core action and resource in the first sentence. The enumerated return fields and caveats are informative, though the field list is somewhat redundant given the output schema exists. Overall, the length is justified by the important data-quality and licensing context.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a read-only barcode lookup, the description covers the essential operational context: what data comes back, how to interpret missing values, caveats on computed scores, and licensing obligations. Since an output schema exists, the return-field enumeration is optional but the behavior and limitations are fully disclosed.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the structured schema already documents barcode and fields in detail. The tool description adds a useful high-level return-field list but does not itself explain the fields parameter's subsetting behavior or dependency rules; those live in the schema. Baseline 3 is appropriate.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Fetch a packaged food product by barcode (EAN-13 or UPC) from Open Food Facts.' It clearly distinguishes this exact-lookup tool from the sibling search, compare, and taxonomy browsing tools by emphasizing the barcode key.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear context: it is a barcode-driven lookup against Open Food Factsaine, and it implies use when a specific product barcode is known. It does not explicitly name sibling alternatives or state when not to use it, but the barcode-focused purpose makes the appropriate use case evident.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

off_search_productsSearch Food ProductsA
Read-onlyIdempotent
Inspect

Search Open Food Facts by full-text query, structured tag filters, or both at once. Returns a summary list with barcodes, product names, brands, Nutri-Score, NOVA group, and categories — enough for triage and selection, not full label data. Use off_get_product on the returned barcodes for complete details. A text query and tag filters combine: results match the query text and satisfy every filter provided (e.g. query "dark chocolate" with labels_tag "en:organic" and countries_tag "en:france" returns organic chocolate sold in France); numeric nutrient_filters express per-100 g thresholds such as sugars below 8 g and combine the same way; additives_tag is the one exception, filtering only on searches carrying neither query nor nutrient_filters. Tag filter values must be canonical tag IDs (e.g. "en:organic", "en:no-gluten") — use off_browse_taxonomy to resolve human terms to tag IDs. At least one search parameter is required. The two paths read different indexes: a search carrying query is answered by the text index, a snapshot that lags the live database, while a tag-only search reads the live database and is current — so a recently contributed product can be missing from a text search and present in the same search without query. Data is crowd-sourced; result count reflects contributed products, not all products in the market. Data under ODbL 1.0 — cite Open Food Facts in downstream use.

ParametersJSON Schema
NameRequiredDescriptionDefault
pageNoPage number (1-based). Use with page_size to paginate results. Searches that include a text query serve only the first 10,000 results, so page * page_size must stay at or below 10,000 — a deeper request is rejected rather than sent. Tag-only searches have no published window, but Open Food Facts refuses deep pages unpredictably; narrowing the filters is more reliable than paging far in.
queryNoFull-text search term across product names, brands, and ingredients. Combines with any tag filters — results match this text and satisfy the filters. Example: "dark chocolate 70%". Supplying it routes the search to the text index, a snapshot that lags the live Open Food Facts database; drop it to run the same tag filters against the current data.
sort_byNoSort order, applied on every search. Each value orders newest or highest first: "unique_scans_n" surfaces the most-scanned products, "last_modified_t" and "created_t" the most recently updated and newest records, "popularity_key" the most popular. Omitting it leaves text searches relevance-ranked and tag-only searches in the default order.
page_sizeNoResults per page (1–50, default 20). Keep low for initial exploration; increase for comparison workflows.
brands_tagNoBrand slug (lowercased, hyphenated). Example: "nutella", "kelloggs". Matched exactly against the normalized slug — a partial or misspelled slug matches nothing rather than falling back to a near match, so put open-ended brand wording in query instead.
labels_tagNoCanonical label/certification tag ID. Example: "en:organic", "en:fair-trade", "en:no-gluten". Use off_browse_taxonomy with facet="labels".
nova_groupNoFilter by NOVA food processing class. "1"=unprocessed/minimally processed, "4"=ultra-processed. Products without a NOVA score are excluded.
additives_tagNoCanonical additive (E-number) tag ID. Example: "en:e322", "en:e330". Use off_browse_taxonomy with facet="additives". Available only on searches carrying neither query nor nutrient_filters — both route to a backend with no additives field, so combining them is rejected instead of silently returning nothing.
allergens_tagNoCanonical allergen tag ID. Example: "en:milk", "en:gluten". Use off_browse_taxonomy with facet="allergens". Selects products that declare this allergen; it cannot select allergen-free products, because a product with no allergen tags may simply have none entered yet.
countries_tagNoCanonical country tag ID. Example: "en:france", "en:united-states". Filters to products sold in that country.
categories_tagNoCanonical category tag ID. Example: "en:breakfast-cereals", "en:cheeses". Use off_browse_taxonomy with facet="categories" to discover valid values.
nutrition_gradeNoFilter by Nutri-Score grade. "a" is highest nutritional quality, "e" is lowest. Products without a score are excluded.
nutrient_filtersNoNumeric constraints on nutrient values per 100 g, combined as AND with each other and with every other filter. Pair two entries on the same nutrient to express a range (e.g. sugars gte 2 and sugars lte 8). Served only by the text backend, so supplying one routes the search there even without query — it then reads the lagging text index and is subject to the 10,000-result page window, and additives_tag cannot be combined with it. Per-serving and prepared-product values are not searchable.

Output Schema

ParametersJSON Schema
NameRequiredDescription
capNoThe page_size that was applied.
pageNoCurrent page number (1-based).
errorNoPresent when the call failed. Absent on success.
shownNoNumber of products returned on this page.
totalNoMatching products in the database for this search. Exact unless total_is_lower_bound is true, in which case at least this many match and the real figure is unknown.
noticeNoGuidance about this result set — echoes the filters and suggests how to broaden when nothing matched, or names the current page and how far the backend will actually paginate when more results exist.
productsNoMatching products. Use barcodes with off_get_product for full label data.
last_pageNoDeepest page of this result set that holds products, at the page_size used — capped by the 10,000-result window on a search the text index answers. Absent when total_is_lower_bound is true — the total it would divide is the ceiling the backend stopped counting at, so no exact last page exists — and when nothing matched at all. On a tag-only search Open Food Facts can still refuse a deep page, so narrowing the filters beats paging out to this bound.
truncatedNoTrue when more results exist beyond this page.
page_countNoProducts returned on this page (mirrors page_size except on the last page). Not the total number of pages.
text_index_snapshotNoPresent only on searches the text backend answered. States that those results come from an index snapshot that lags the live Open Food Facts database, so a recently contributed product can be missing from them while the tag-only path still returns it. Absent on tag-only searches, which read the live database.
total_is_lower_boundNoTrue when the backend stopped counting at its ceiling and total is a floor, not the match total. Only text searches can hit it; add filters to bring the result set under the ceiling and get an exact count.

TDQS

A5/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly/openWorld/idempotent annotations, the description discloses substantial behavioral traits: the text index lags the live database, tag-only searches read live data, crowd-sourced counts may miss products, ODbL licensing applies, and certain filter combinations are rejected rather than silently returning nothing. These are exactly the behaviors an agent needs to interpret results correctly.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but every sentence earns its place: summary output, sibling routing, combination semantics, canonical-value guidance, backend differences, and data caveats. It is front-loaded with the core function and output, then layers constraints in logical order without padding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given 13 parameters, multiple filter types, backend-specific behavior, and an output schema, the description is complete. It covers return granularity, pagination limits, value resolution, exceptions, data freshness, and licensing, so an agent has everything required to call and interpret the tool correctly.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Although the schema already documents every parameter (100% coverage), the description adds meaning the schema cannot convey: how query and tag filters combine as AND, how nutrient_filters form ranges, the additives_tag exception, canonical tag ID requirements, and the 10,000-result page window for text searches. This transforms isolated parameter definitions into a usable search model.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description opens with a specific verb and resource: 'Search Open Food Facts by full-text query, structured tag filters, or both at once,' and defines the output as a summary list for triage, explicitly pointing to off_get_product for complete label data. This differentiates it from the sibling tools and leaves no ambiguity about what the tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It explicitly says when to use this tool versus off_get_product ('Use off_get_product on the returned barcodes for complete details'), and directs tag-value resolution to off_browse_taxonomy. It also states the precondition that at least one search parameter is required and explains filter-scope exceptions, so an agent can decide correctly before calling.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 1 tool update
    • Changedoff_get_product6 fields changed
      • changedInput schema / properties / fields / description
        Previous value: -"Subset of fields to return. Omitting returns all standard fields. Use to reduce payload when only scores or ingredients are needed."New value: +"Subset of fields to return. Omitting returns all standard fields. Use to reduce payload when only scores or ingredients are needed. A field that cannot be read on its own arrives with what it depends on: nutriments brings serving_size, serving_quantity, and serving_quantity_unit so per-serving figures carry their denominator, and serving_quantity_unit brings the quantity it describes. requested_fields echoes the full set that was fetched."
      • changedInput schema / properties / fields / items / enum
        Previous value: -[
        -  "product_name",
        -  "brands",
        -  "quantity",
        -  "ingredients_text",
        -  "ingredients",
        -  "allergens_tags",
        -  "additives_tags",
        -  "nutriscore_grade",
        -  "nova_group",
        -  "ecoscore_grade",
        -  "nutriments",
        -  "serving_size",
        -  "serving_quantity",
        -  "serving_quantity_unit",
        -  "categories_tags",
        -  "labels_tags",
        -  "packaging_tags",
        -  "origins_tags",
        -  "image_url",
        -  "completeness",
        -  "data_quality_tags"
        -]New value: +[
        +  "product_name",
        +  "brands",
        +  "quantity",
        +  "ingredients_text",
        +  "ingredients",
        +  "allergens_tags",
        +  "traces_tags",
        +  "additives_tags",
        +  "ingredients_analysis_tags",
        +  "nutriscore_grade",
        +  "nova_group",
        +  "ecoscore_grade",
        +  "nutriments",
        +  "serving_size",
        +  "serving_quantity",
        +  "serving_quantity_unit",
        +  "categories_tags",
        +  "labels_tags",
        +  "packaging_tags",
        +  "origins_tags",
        +  "countries_tags",
        +  "image_url",
        +  "completeness",
        +  "data_quality_tags"
        +]
      • addedOutput schema / properties / product / properties / countries_tags
        Added value: +{
        +  "description": "Countries where the product is sold — the same values off_search_products accepts as countries_tag. Distinct from origins_tags, which is where the ingredients come from.",
        +  "items": {
        +    "description": "Canonical country tag ID (e.g. \"en:france\").",
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / product / properties / ingredients_analysis_tags
        Added value: +{
        +  "description": "Product-level vegan, vegetarian, and palm-oil verdicts computed by Open Food Facts from the parsed ingredients. \"maybe-\" and \"-status-unknown\" values mean the ingredients could not settle it (e.g. \"en:maybe-vegan\").",
        +  "items": {
        +    "description": "Analysis verdict tag (e.g. \"en:non-vegan\", \"en:palm-oil-free\").",
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • addedOutput schema / properties / product / properties / traces_tags
        Added value: +{
        +  "description": "Allergens the label says the product may contain as traces, from cross-contamination warnings. Distinct from allergens_tags, which carries allergens declared in the ingredients. [\"en:none\"] means the label states no traces; an empty array or an absent field means not yet entered, not trace-free. Values resolve through off_browse_taxonomy's allergens facet.",
        +  "items": {
        +    "description": "Canonical allergen tag ID (e.g. \"en:nuts\").",
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / properties / requested_fields / description
        Previous value: -"The field subset that was requested, when the caller passed `fields`. Absent means all standard fields were requested. Sections outside this subset are omitted because they were not requested — not because Open Food Facts lacks the data."New value: +"The field subset that was fetched, when the caller passed `fields` — the requested fields plus the ones they depend on, so every field that can appear in `product` is named here. Absent means all standard fields were requested. Sections outside this subset are omitted because they were not requested — not because Open Food Facts lacks the data."
  2. 2 tool updates
    • Changedoff_browse_taxonomy1 field changed
      • changedInput schema / properties / search / description
        Previous value: -"Term to resolve. Matched case-insensitively as a substring of the tag ID or display name. A single word works best (\"hummus\", not \"hummus dip\"). Omit only to see a small reference list — Open Food Facts cannot list the full vocabulary without a term, so an unfiltered call is not a view of the full facet."New value: +"Term to resolve. Matched case-insensitively as a substring of the tag ID, the display name, or a common synonym of either (\"shellfish\" resolves to en:crustaceans, \"gluten free\" to en:no-gluten). A single word works best (\"hummus\", not \"hummus dip\"). Omit only to see a small reference list — Open Food Facts cannot list the full vocabulary without a term, so an unfiltered call is not a view of the full facet."
    • Changedoff_search_products7 fields changed
      • changedInput schema / properties / additives_tag / description
        Previous value: -"Canonical additive (E-number) tag ID. Example: \"en:e322\", \"en:e330\". Use off_browse_taxonomy with facet=\"additives\". Available only on searches with no query — full-text searches cannot filter by additive, so combining the two is rejected instead of silently returning nothing."New value: +"Canonical additive (E-number) tag ID. Example: \"en:e322\", \"en:e330\". Use off_browse_taxonomy with facet=\"additives\". Available only on searches carrying neither query nor nutrient_filters — both route to a backend with no additives field, so combining them is rejected instead of silently returning nothing."
      • addedInput schema / properties / nutrient_filters
        Added value: +{
        +  "description": "Numeric constraints on nutrient values per 100 g, combined as AND with each other and with every other filter. Pair two entries on the same nutrient to express a range (e.g. sugars gte 2 and sugars lte 8). Served only by the text backend, so supplying one routes the search there even without query — it then reads the lagging text index and is subject to the 10,000-result page window, and additives_tag cannot be combined with it. Per-serving and prepared-product values are not searchable.",
        +  "items": {
        +    "description": "One numeric constraint on a per-100 g nutrient value.",
        +    "properties": {
        +      "nutrient": {
        +        "description": "Nutrient to constrain, measured per 100 g. Energy is kilocalories; every other value is grams per 100 g.",
        +        "enum": [
        +          "energy-kcal",
        +          "fat",
        +          "saturated-fat",
        +          "carbohydrates",
        +          "sugars",
        +          "fiber",
        +          "proteins",
        +          "salt",
        +          "sodium"
        +        ],
        +        "type": "string"
        +      },
        +      "operator": {
        +        "description": "Comparison against value: \"lt\" below, \"lte\" at or below, \"gt\" above, \"gte\" at or above.",
        +        "enum": [
        +          "lt",
        +          "lte",
        +          "gt",
        +          "gte"
        +        ],
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "Threshold to compare against, in the nutrient's per-100 g unit.",
        +        "minimum": 0,
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "nutrient",
        +      "operator",
        +      "value"
        +    ],
        +    "type": "object"
        +  },
        +  "maxItems": 18,
        +  "type": "array"
        +}
      • changedInput schema / properties / query / description
        Previous value: -"Full-text search term across product names, brands, and ingredients. Combines with any tag filters — results match this text and satisfy the filters. Example: \"dark chocolate 70%\"."New value: +"Full-text search term across product names, brands, and ingredients. Combines with any tag filters — results match this text and satisfy the filters. Example: \"dark chocolate 70%\". Supplying it routes the search to the text index, a snapshot that lags the live Open Food Facts database; drop it to run the same tag filters against the current data."
      • changedInput schema / properties / sort_by / description
        Previous value: -"Sort order for searches without a text query. \"unique_scans_n\" surfaces the most-scanned products; omitting returns results in default order. Searches that include a text query are relevance-ranked and ignore this option."New value: +"Sort order, applied on every search. Each value orders newest or highest first: \"unique_scans_n\" surfaces the most-scanned products, \"last_modified_t\" and \"created_t\" the most recently updated and newest records, \"popularity_key\" the most popular. Omitting it leaves text searches relevance-ranked and tag-only searches in the default order."
      • changedOutput schema / properties / error / properties / data / properties / reason / description
        Previous value: -"Machine-readable failure mode. Declared by this tool: `no_filters`: No search query or filter was provided `additives_filter_needs_tag_search`: additives_tag was combined with a text query, which cannot filter by additive `page_out_of_range`: A text search asks for page * page_size beyond the 10000-result window Open Food Facts serves `upstream_error`: Open Food Facts returns 5xx, serves an HTML error page, or is unreachable `upstream_timeout`: Open Food Facts did not answer within the request deadline `upstream_rejected`: Open Food Facts answers 4xx — the request as formed will be refused again `rate_limited`: This server's own per-minute search budget is spent, or Open Food Facts answers 429 Other values are possible when a failure originates below the handler."New value: +"Machine-readable failure mode. Declared by this tool: `no_filters`: No search query or filter was provided `additives_filter_needs_tag_search`: additives_tag was combined with a query or nutrient_filters, which route to a backend that cannot filter by additive `page_out_of_range`: A search the text backend serves asks for page * page_size beyond the 10000-result window Open Food Facts offers `upstream_error`: Open Food Facts returns 5xx, serves an HTML error page, or is unreachable `upstream_timeout`: Open Food Facts did not answer within the request deadline `upstream_rejected`: Open Food Facts answers 4xx — the request as formed will be refused again `rate_limited`: This server's own per-minute search budget is spent, or Open Food Facts answers 429 Other values are possible when a failure originates below the handler."
      • addedOutput schema / properties / last_page
        Added value: +{
        +  "description": "Deepest page of this result set that holds products, at the page_size used — capped by the 10,000-result window on a search the text index answers. Absent when total_is_lower_bound is true — the total it would divide is the ceiling the backend stopped counting at, so no exact last page exists — and when nothing matched at all. On a tag-only search Open Food Facts can still refuse a deep page, so narrowing the filters beats paging out to this bound.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / text_index_snapshot
        Added value: +{
        +  "description": "Present only on searches the text backend answered. States that those results come from an index snapshot that lags the live Open Food Facts database, so a recently contributed product can be missing from them while the tag-only path still returns it. Absent on tag-only searches, which read the live database.",
        +  "type": "string"
        +}
  3. 4 tool updates
    • Changedoff_browse_taxonomy11 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedInput schema / properties / facet / description
        Previous value: -"\"categories\" covers food categories (en:cheeses, en:breakfast-cereals). \"labels\" covers certifications (en:organic, en:fair-trade). \"allergens\" covers declared allergens (en:milk, en:gluten). \"additives\" covers E-numbers (en:e322). \"countries\" covers country-of-sale tags (en:france). \"nova_groups\" and \"nutrition_grades\" are closed vocabularies answered offline and returned complete; the other five are resolved against the live Open Food Facts taxonomy."New value: +"\"categories\" covers food categories (en:cheeses, en:breakfast-cereals). \"labels\" covers certifications (en:organic, en:fair-trade). \"allergens\" covers declared allergens (en:milk, en:gluten). \"additives\" covers E-numbers (en:e322). \"countries\" covers country-of-sale tags (en:france). \"nova_groups\" and \"nutrition_grades\" are closed vocabularies returned complete; the other five are resolved against the Open Food Facts taxonomy."
      • changedInput schema / properties / limit / description
        Previous value: -"Maximum entries to return (1–100, default 20). There is no offset or page input: the upstream taxonomy endpoint serves only the first `limit` matches for a term and offers no cursor, so narrow the search term rather than paging."New value: +"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."
      • changedInput schema / properties / search / description
        Previous value: -"Term to resolve. Matched case-insensitively as a substring of the tag ID or display name, against both the live Open Food Facts vocabulary and this server's offline sample. A single word works best (\"hummus\", not \"hummus dip\"). Omit only to see the offline sample — the live vocabulary cannot be listed without a term, so an unfiltered call is not a view of the full facet."New value: +"Term to resolve. Matched case-insensitively as a substring of the tag ID or display name. A single word works best (\"hummus\", not \"hummus dip\"). Omit only to see a small reference list — Open Food Facts cannot list the full vocabulary without a term, so an unfiltered call is not a view of the full facet."
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "facet",
        +      "tags"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode.",
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • changedOutput schema / properties / notice / description
        Previous value: -"Caveat about how this answer was produced — that the listing is the offline sample rather than the live vocabulary, that the live vocabulary was unreachable, or that nothing matched and why."New value: +"Caveat about the answer — that the listing is a limited reference list rather than the full vocabulary, that Open Food Facts was unreachable, or that nothing matched and why."
      • changedOutput schema / properties / total_in_facet / description
        Previous value: -"Total entries in this facet. Present only for nova_groups and nutrition_grades, whose vocabularies are closed and complete here. Absent for the live facets: the Open Food Facts taxonomy endpoint reports no match total and cannot be enumerated, so no figure would be a real one."New value: +"Total entries in this facet. Present only for nova_groups and nutrition_grades, whose vocabularies are closed and complete. Absent for the other facets: Open Food Facts reports no match total and cannot enumerate them, so no figure would be a real one."
      • removedOutput schema / required
        Removed value: -[
        -  "facet",
        -  "tags"
        -]
    • Changedoff_compare_products6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "products",
        +      "succeeded",
        +      "not_found"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `upstream_error`: Open Food Facts returns 5xx, serves an HTML error page, or is unreachable — surfaced per barcode in failed[] `upstream_timeout`: Open Food Facts did not answer within the request deadline — surfaced per barcode in failed[] `upstream_rejected`: Open Food Facts answers 4xx for a barcode — surfaced per barcode in failed[] `rate_limited`: This server's own per-minute request budget is spent, or Open Food Facts answers 429 — surfaced per barcode in failed[] Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "upstream_error",
        +            "upstream_timeout",
        +            "upstream_rejected",
        +            "rate_limited"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "products",
        -  "succeeded",
        -  "not_found"
        -]
    • Changedoff_get_product6 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "barcode",
        +      "product"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `not_found`: Barcode status:0 — not present in any contributor record `upstream_error`: Open Food Facts returns 5xx, serves an HTML error page, or is unreachable `upstream_timeout`: Open Food Facts did not answer within the request deadline `upstream_rejected`: Open Food Facts answers 4xx for something other than a missing barcode `rate_limited`: This server's own per-minute request budget is spent, or Open Food Facts answers 429 Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "not_found",
        +            "upstream_error",
        +            "upstream_timeout",
        +            "upstream_rejected",
        +            "rate_limited"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "barcode",
        -  "product"
        -]
    • Changedoff_search_products7 fields changed
      • changedInput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedInput schema / additionalProperties
        Added value: +false
      • changedInput schema / properties / additives_tag / description
        Previous value: -"Canonical additive (E-number) tag ID. Example: \"en:e322\", \"en:e330\". Use off_browse_taxonomy with facet=\"additives\". Available only on searches with no query — the text backend does not index additives, so combining the two is rejected instead of silently returning nothing."New value: +"Canonical additive (E-number) tag ID. Example: \"en:e322\", \"en:e330\". Use off_browse_taxonomy with facet=\"additives\". Available only on searches with no query — full-text searches cannot filter by additive, so combining the two is rejected instead of silently returning nothing."
      • changedOutput schema / $schema
        Previous value: -"http://json-schema.org/draft-07/schema#"New value: +"https://json-schema.org/draft/2020-12/schema"
      • addedOutput schema / anyOf
        Added value: +[
        +  {
        +    "not": {
        +      "required": [
        +        "error"
        +      ]
        +    },
        +    "required": [
        +      "total",
        +      "total_is_lower_bound",
        +      "page",
        +      "page_count",
        +      "products"
        +    ]
        +  },
        +  {
        +    "required": [
        +      "error"
        +    ]
        +  }
        +]
      • addedOutput schema / properties / error
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "Present when the call failed. Absent on success.",
        +  "properties": {
        +    "code": {
        +      "description": "JSON-RPC error code for this failure.",
        +      "maximum": 9007199254740991,
        +      "minimum": -9007199254740991,
        +      "type": "integer"
        +    },
        +    "data": {
        +      "additionalProperties": {},
        +      "properties": {
        +        "reason": {
        +          "description": "Machine-readable failure mode. Declared by this tool: `no_filters`: No search query or filter was provided `additives_filter_needs_tag_search`: additives_tag was combined with a text query, which cannot filter by additive `page_out_of_range`: A text search asks for page * page_size beyond the 10000-result window Open Food Facts serves `upstream_error`: Open Food Facts returns 5xx, serves an HTML error page, or is unreachable `upstream_timeout`: Open Food Facts did not answer within the request deadline `upstream_rejected`: Open Food Facts answers 4xx — the request as formed will be refused again `rate_limited`: This server's own per-minute search budget is spent, or Open Food Facts answers 429 Other values are possible when a failure originates below the handler.",
        +          "examples": [
        +            "no_filters",
        +            "additives_filter_needs_tag_search",
        +            "page_out_of_range",
        +            "upstream_error",
        +            "upstream_timeout",
        +            "upstream_rejected",
        +            "rate_limited"
        +          ],
        +          "type": "string"
        +        },
        +        "recovery": {
        +          "additionalProperties": {},
        +          "description": "Actionable next step for the caller.",
        +          "properties": {
        +            "hint": {
        +              "type": "string"
        +            }
        +          },
        +          "required": [
        +            "hint"
        +          ],
        +          "type": "object"
        +        },
        +        "retryable": {
        +          "description": "Whether retrying may succeed.",
        +          "type": "boolean"
        +        }
        +      },
        +      "type": "object"
        +    },
        +    "message": {
        +      "description": "Human-readable description of what went wrong.",
        +      "type": "string"
        +    }
        +  },
        +  "required": [
        +    "code",
        +    "message"
        +  ],
        +  "type": "object"
        +}
      • removedOutput schema / required
        Removed value: -[
        -  "total",
        -  "total_is_lower_bound",
        -  "page",
        -  "page_count",
        -  "products"
        -]
  4. 1 tool update
    • Changedoff_browse_taxonomy6 fields changed
      • changedInput schema / properties / facet / description
        Previous value: -"\"categories\" covers food categories (en:cheeses, en:breakfast-cereals). \"labels\" covers certifications (en:organic, en:fair-trade). \"allergens\" covers declared allergens (en:milk, en:gluten). \"additives\" covers E-numbers (en:e322). \"countries\" covers country-of-sale tags (en:france). \"nova_groups\" and \"nutrition_grades\" return the complete fixed vocabularies."New value: +"\"categories\" covers food categories (en:cheeses, en:breakfast-cereals). \"labels\" covers certifications (en:organic, en:fair-trade). \"allergens\" covers declared allergens (en:milk, en:gluten). \"additives\" covers E-numbers (en:e322). \"countries\" covers country-of-sale tags (en:france). \"nova_groups\" and \"nutrition_grades\" are closed vocabularies answered offline and returned complete; the other five are resolved against the live Open Food Facts taxonomy."
      • changedInput schema / properties / limit / description
        Previous value: -"Maximum entries to return (1–100, default 20). The categories facet is broad; a search term narrows it to the relevant tags."New value: +"Maximum entries to return (1–100, default 20). There is no offset or page input: the upstream taxonomy endpoint serves only the first `limit` matches for a term and offers no cursor, so narrow the search term rather than paging."
      • changedInput schema / properties / search / description
        Previous value: -"Case-insensitive substring filter against tag ID or display name. Example: \"gluten\" returns en:gluten, en:no-gluten. Omit to list all entries for the facet (may be large for categories)."New value: +"Term to resolve. Matched case-insensitively as a substring of the tag ID or display name, against both the live Open Food Facts vocabulary and this server's offline sample. A single word works best (\"hummus\", not \"hummus dip\"). Omit only to see the offline sample — the live vocabulary cannot be listed without a term, so an unfiltered call is not a view of the full facet."
      • addedOutput schema / properties / notice
        Added value: +{
        +  "description": "Caveat about how this answer was produced — that the listing is the offline sample rather than the live vocabulary, that the live vocabulary was unreachable, or that nothing matched and why.",
        +  "type": "string"
        +}
      • changedOutput schema / properties / tags / items / properties / id / description
        Previous value: -"Canonical tag ID (e.g. \"en:organic\"). Use this value in off_search_products filter parameters."New value: +"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."
      • changedOutput schema / properties / total_in_facet / description
        Previous value: -"Total entries in this facet before search filtering. Large for categories."New value: +"Total entries in this facet. Present only for nova_groups and nutrition_grades, whose vocabularies are closed and complete here. Absent for the live facets: the Open Food Facts taxonomy endpoint reports no match total and cannot be enumerated, so no figure would be a real one."
  5. 1 tool update
    • Changedoff_get_product9 fields changed
      • changedInput schema / properties / fields / items / enum
        Previous value: -[
        -  "product_name",
        -  "brands",
        -  "quantity",
        -  "ingredients_text",
        -  "ingredients",
        -  "allergens_tags",
        -  "additives_tags",
        -  "nutriscore_grade",
        -  "nova_group",
        -  "ecoscore_grade",
        -  "nutriments",
        -  "categories_tags",
        -  "labels_tags",
        -  "packaging_tags",
        -  "origins_tags",
        -  "image_url",
        -  "completeness",
        -  "data_quality_tags"
        -]New value: +[
        +  "product_name",
        +  "brands",
        +  "quantity",
        +  "ingredients_text",
        +  "ingredients",
        +  "allergens_tags",
        +  "additives_tags",
        +  "nutriscore_grade",
        +  "nova_group",
        +  "ecoscore_grade",
        +  "nutriments",
        +  "serving_size",
        +  "serving_quantity",
        +  "serving_quantity_unit",
        +  "categories_tags",
        +  "labels_tags",
        +  "packaging_tags",
        +  "origins_tags",
        +  "image_url",
        +  "completeness",
        +  "data_quality_tags"
        +]
      • removedOutput schema / properties / found
        Removed value: -{
        -  "description": "False when the barcode exists in no contributor record (status:0). A false result means no contributor has entered this product yet — not that the product does not exist.",
        -  "type": "boolean"
        -}
      • changedOutput schema / properties / product / description
        Previous value: -"Product data. Absent when found is false."New value: +"Product data. Always present on a successful call — a barcode with no contributor record raises the not_found error instead of returning an empty result."
      • addedOutput schema / properties / product / properties / nutriments / properties / additional_100g
        Added value: +{
        +  "additionalProperties": {
        +    "additionalProperties": false,
        +    "description": "One nutrient figure with the unit it is expressed in.",
        +    "properties": {
        +      "unit": {
        +        "description": "Unit the figure is expressed in (\"g\", \"kcal\", \"kJ\"). Absent when Open Food Facts records no unit for this nutrient.",
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "The figure Open Food Facts reported per 100g.",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "value"
        +    ],
        +    "type": "object"
        +  },
        +  "description": "Every other per-100g nutrient Open Food Facts holds, keyed by normalized name (calcium, iron, vitamin_c, trans_fat, added_sugars, cholesterol, energy in kJ, …). Excludes the named fields above, so a nutrient appears in exactly one place. Micronutrients are usually reported in grams, so calcium 0.071 g is 71 mg — read the unit rather than assuming.",
        +  "propertyNames": {
        +    "description": "Nutrient name, hyphens normalized to underscores.",
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / product / properties / nutriments / properties / additional_serving
        Added value: +{
        +  "additionalProperties": {
        +    "additionalProperties": false,
        +    "description": "One nutrient figure with the unit it is expressed in.",
        +    "properties": {
        +      "unit": {
        +        "description": "Unit the figure is expressed in (\"g\", \"kcal\", \"kJ\"). Absent when Open Food Facts records no unit for this nutrient.",
        +        "type": "string"
        +      },
        +      "value": {
        +        "description": "The figure Open Food Facts reported per serving.",
        +        "type": "number"
        +      }
        +    },
        +    "required": [
        +      "value"
        +    ],
        +    "type": "object"
        +  },
        +  "description": "The same nutrients per serving. Also carries the per-serving figures for macros that have a named per-100g field but no named per-serving one (saturated_fat, carbohydrates, fiber, proteins, salt, sodium). Check serving_size for the denominator these figures are measured against.",
        +  "propertyNames": {
        +    "description": "Nutrient name, hyphens normalized to underscores.",
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
      • addedOutput schema / properties / product / properties / serving_quantity
        Added value: +{
        +  "description": "Serving size parsed to a number, in serving_quantity_unit. Absent when Open Food Facts could not parse the printed serving size.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / product / properties / serving_quantity_unit
        Added value: +{
        +  "description": "Unit of serving_quantity — usually \"g\" but \"ml\" for liquids, so it is not safe to assume grams. Absent when serving_quantity is absent or Open Food Facts records no unit.",
        +  "type": "string"
        +}
      • addedOutput schema / properties / product / properties / serving_size
        Added value: +{
        +  "description": "Serving size as printed on the label (e.g. \"28 g\", \"1 can (12 fl oz)\"). The denominator for every per-serving figure. Absent when contributors have not entered one, in which case per-serving values cannot be converted to or from the per-100g values.",
        +  "type": "string"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "barcode",
        -  "found"
        -]New value: +[
        +  "barcode",
        +  "product"
        +]
  6. 1 tool update
    • Changedoff_search_products6 fields changed
      • addedInput schema / properties / additives_tag
        Added value: +{
        +  "description": "Canonical additive (E-number) tag ID. Example: \"en:e322\", \"en:e330\". Use off_browse_taxonomy with facet=\"additives\". Available only on searches with no query — the text backend does not index additives, so combining the two is rejected instead of silently returning nothing.",
        +  "type": "string"
        +}
      • addedInput schema / properties / allergens_tag
        Added value: +{
        +  "description": "Canonical allergen tag ID. Example: \"en:milk\", \"en:gluten\". Use off_browse_taxonomy with facet=\"allergens\". Selects products that declare this allergen; it cannot select allergen-free products, because a product with no allergen tags may simply have none entered yet.",
        +  "type": "string"
        +}
      • changedInput schema / properties / brands_tag / description
        Previous value: -"Brand slug (lowercased, hyphenated). Example: \"nutella\", \"kelloggs\". Fuzzy — partial matches may work."New value: +"Brand slug (lowercased, hyphenated). Example: \"nutella\", \"kelloggs\". Matched exactly against the normalized slug — a partial or misspelled slug matches nothing rather than falling back to a near match, so put open-ended brand wording in query instead."
      • changedOutput schema / properties / total / description
        Previous value: -"Total matching products in the database for this query."New value: +"Matching products in the database for this search. Exact unless total_is_lower_bound is true, in which case at least this many match and the real figure is unknown."
      • addedOutput schema / properties / total_is_lower_bound
        Added value: +{
        +  "description": "True when the backend stopped counting at its ceiling and total is a floor, not the match total. Only text searches can hit it; add filters to bring the result set under the ceiling and get an exact count.",
        +  "type": "boolean"
        +}
      • changedOutput schema / required
        Previous value: -[
        -  "total",
        -  "page",
        -  "page_count",
        -  "products"
        -]New value: +[
        +  "total",
        +  "total_is_lower_bound",
        +  "page",
        +  "page_count",
        +  "products"
        +]
  7. 2 tool updates
    • Changedoff_compare_products3 fields changed
      • addedOutput schema / properties / failed
        Added value: +{
        +  "description": "Barcodes whose fetch failed, with the per-barcode reason. Absent when every fetch completed. A barcode listed here is unknown, not absent from Open Food Facts — retry it with off_get_product before concluding anything about the product.",
        +  "items": {
        +    "additionalProperties": false,
        +    "description": "A single barcode whose fetch failed.",
        +    "properties": {
        +      "barcode": {
        +        "description": "EAN-13 or UPC barcode whose fetch failed.",
        +        "type": "string"
        +      },
        +      "error": {
        +        "description": "What went wrong for this barcode and what to do about it.",
        +        "type": "string"
        +      },
        +      "reason": {
        +        "description": "Declared failure reason — one of upstream_error, upstream_timeout, upstream_rejected, rate_limited.",
        +        "type": "string"
        +      }
        +    },
        +    "required": [
        +      "barcode",
        +      "reason",
        +      "error"
        +    ],
        +    "type": "object"
        +  },
        +  "type": "array"
        +}
      • changedOutput schema / properties / not_found / description
        Previous value: -"Barcodes with no contributor record. Not an error — the product may exist but not yet entered in Open Food Facts."New value: +"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."
      • changedOutput schema / properties / products / description
        Previous value: -"Comparison rows, one per barcode in input order."New value: +"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."
    • Changedoff_search_products2 fields changed
      • changedInput schema / properties / page / description
        Previous value: -"Page number (1-based). Use with page_size to paginate results."New value: +"Page number (1-based). Use with page_size to paginate results. Searches that include a text query serve only the first 10,000 results, so page * page_size must stay at or below 10,000 — a deeper request is rejected rather than sent. Tag-only searches have no published window, but Open Food Facts refuses deep pages unpredictably; narrowing the filters is more reliable than paging far in."
      • changedOutput schema / properties / notice / description
        Previous value: -"Guidance when results are empty — echoes filters and suggests how to broaden."New value: +"Guidance about this result set — echoes the filters and suggests how to broaden when nothing matched, or names the current page and how far the backend will actually paginate when more results exist."
  8. 3 tool updates
    • Changedoff_browse_taxonomy1 field changed
      • changedInput schema / properties / limit / description
        Previous value: -"Maximum entries to return (1–100, default 20). Categories has many entries — always provide a search term when browsing categories."New value: +"Maximum entries to return (1–100, default 20). The categories facet is broad; a search term narrows it to the relevant tags."
    • Changedoff_compare_products1 field changed
      • changedInput schema / properties / barcodes / description
        Previous value: -"2–10 barcodes to compare. All products are fetched in parallel. Example: [\"3017620422003\", \"7622210100146\"]."New value: +"2–10 barcodes to compare, returned as one row each in input order. Example: [\"3017620422003\", \"7622210100146\"]."
    • Changedoff_search_products2 fields changed
      • changedInput schema / properties / query / description
        Previous value: -"Full-text search term across product names, brands, and ingredients. When provided, routes to the text search engine — tag filters (categories_tag, brands_tag, etc.) are ignored in this path. Example: \"dark chocolate 70%\"."New value: +"Full-text search term across product names, brands, and ingredients. Combines with any tag filters — results match this text and satisfy the filters. Example: \"dark chocolate 70%\"."
      • changedInput schema / properties / sort_by / description
        Previous value: -"Sort order for tag-filter results. \"unique_scans_n\" surfaces the most-scanned products. Ignored on text-query searches (search.openfoodfacts.org does not support server-side sort). Omitting returns results in default database order."New value: +"Sort order for searches without a text query. \"unique_scans_n\" surfaces the most-scanned products; omitting returns results in default order. Searches that include a text query are relevance-ranked and ignore this option."
  9. 1 tool update
    • Changedoff_get_product1 field changed
      • addedOutput schema / properties / requested_fields
        Added value: +{
        +  "description": "The field subset that was requested, when the caller passed `fields`. Absent means all standard fields were requested. Sections outside this subset are omitted because they were not requested — not because Open Food Facts lacks the data.",
        +  "items": {
        +    "description": "A field name from the requested subset.",
        +    "type": "string"
        +  },
        +  "type": "array"
        +}
  10. 2 tool updates
    • Changedoff_browse_taxonomy3 fields changed
      • addedOutput schema / properties / cap
        Added value: +{
        +  "description": "The limit that was applied.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / shown
        Added value: +{
        +  "description": "Number of tags returned.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "description": "True when more tags exist beyond the limit.",
        +  "type": "boolean"
        +}
    • Changedoff_search_products3 fields changed
      • addedOutput schema / properties / cap
        Added value: +{
        +  "description": "The page_size that was applied.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / shown
        Added value: +{
        +  "description": "Number of products returned on this page.",
        +  "type": "number"
        +}
      • addedOutput schema / properties / truncated
        Added value: +{
        +  "description": "True when more results exist beyond this page.",
        +  "type": "boolean"
        +}
  11. 1 tool update
    • Changedoff_search_products2 fields changed
      • addedInput schema / properties / sort_by
        Added value: +{
        +  "description": "Sort order for tag-filter results. \"unique_scans_n\" surfaces the most-scanned products. Ignored on text-query searches (search.openfoodfacts.org does not support server-side sort). Omitting returns results in default database order.",
        +  "enum": [
        +    "last_modified_t",
        +    "unique_scans_n",
        +    "created_t",
        +    "popularity_key"
        +  ],
        +  "type": "string"
        +}
      • addedOutput schema / properties / products / items / properties / ecoscore_grade
        Added value: +{
        +  "description": "Green-Score letter (a–e). Environmental impact indicator. Absent when not computed.",
        +  "type": "string"
        +}
  12. 4 tool updates
    • First observedoff_browse_taxonomy
    • First observedoff_compare_products
    • First observedoff_get_product
    • First observedoff_search_products

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    Provides access to a comprehensive food database with 300,000+ items, enabling nutritional data lookups, food searches, and barcode scanning with all processing happening locally for privacy and speed.
    207
    MIT
  • A
    license
    A
    quality
    A
    maintenance
    Product evaluation MCP server for US packaged food. Health scores, ingredient safety, regulatory flags, recall history, corporate ownership.
    2
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables querying Open Food Facts product database by barcode, full-text search, category, brand, or country.
    1 npm
    MIT
  • A
    license
    A
    quality
    D
    maintenance
    Enables AI assistants to access the Open Food Facts database to query detailed food product information, nutritional data, and environmental scores. Supports product lookup by barcode, smart search with filtering, nutritional analysis, product comparison, and dietary recommendations to help users make informed food choices.
    5
    1
    MIT
Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.