Skip to main content
Glama

openfoodfacts-mcp-server

Get Food Product by Barcode

off_get_product
Read-onlyIdempotent

Fetch a packaged food product by barcode (4–40 digits: EAN-13, EAN-8, UPC, and the shorter and longer codes Open Food Facts also holds) 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 serving and per 100 g, or per 100 ml for liquids, 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. Nutrition is the exception: Open Food Facts returns one preparation state per read, so a read of prepared figures (_prepared keys under nutriments) omits as-sold figures the record can still hold. 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.

Input 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 and serving_quantity_unit each bring the other plus serving_size, since a quantity reads only with its unit. requested_fields echoes the full set that was fetched.
barcodeYesProduct barcode, digits only: 4–40 digits after any leading zeros. The primary key for Open Food Facts — the barcode of an off_search_products row works as is. Example: "3017620422003" (Nutella FR).

Output Schema

NameRequiredDescriptionDefault
errorNoPresent when the call failed. Absent on success.
barcodeNoThe input barcode, echoed back unchanged. Open Food Facts can hold the record under another form of the same code (030000010402 resolves to the record stored as 0030000010402); that stored form is not reported.
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.

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed5 schema 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. 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."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 and serving_quantity_unit each bring the other plus serving_size, since a quantity reads only with its unit. requested_fields echoes the full set that was fetched."
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `not_found`: Open Food Facts answers HTTP 404 or status 0 for the barcode — no contributor has recorded it. `upstream_error`: Open Food Facts returns a 5xx other than 501 or 504, serves an HTML error page with a 2xx or 5xx status, answers 2xx with a malformed envelope, or is unreachable. `upstream_timeout`: Open Food Facts did not answer within the request deadline, or answered 408, 425, or 504. `upstream_rejected`: Open Food Facts refuses the request with a 4xx other than 404, 408, 425, or 429, or with 501 Not Implemented. `rate_limited`: This server's own per-minute product 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: `not_found`: Open Food Facts answers HTTP 404 or status 0 for the barcode — no contributor has recorded it. `upstream_error`: Open Food Facts returns a 5xx other than 501 or 504, serves an HTML error page with a 2xx or 5xx status, answers 2xx with a malformed envelope, closes the connection before finishing its answer, or is unreachable. `upstream_timeout`: Open Food Facts did not answer within the request or retry deadline, or answered 408, 425, or 504. `upstream_rejected`: Open Food Facts refuses the request with a 4xx other than 404, 408, 425, or 429, or with 501 Not Implemented. `rate_limited`: This server's own per-minute product budget is spent, or Open Food Facts answers 429. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / product / properties / nutriments / description
      Previous value: -"Nutrition figures normalized to underscore keys. All values may be absent when nutrition data not yet entered."New value: +"Nutrition figures normalized to underscore keys. The named fields hold as-sold figures, and keys ending in _prepared under additional_100g and additional_serving hold prepared-product figures. Open Food Facts returns one preparation state per read, so a read of prepared figures leaves every named field absent even when the record holds as-sold figures. All values may be absent when nutrition data not yet entered."
    • changedOutput schema / properties / product / properties / nutriments / properties / additional_100g / description
      Previous value: -"Every other nutrient Open Food Facts holds per 100 g, or per 100 ml for liquids, 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 in grams, so calcium 0.071 g is 71 mg."New value: +"Every other nutrient this read returned per 100 g, or per 100 ml for liquids, 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. A key ending in _prepared (energy_kcal_prepared, carbohydrates_prepared, …) is a figure for the prepared product, not the product as sold. Micronutrients are in grams, so calcium 0.071 g is 71 mg."
    • changedOutput schema / properties / product / properties / nutriments / properties / additional_serving / description
      Previous value: -"The same nutrients per serving. Also carries the per-serving figures for macros that have a named _100g field but no named per-serving one (saturated_fat, carbohydrates, fiber, proteins, salt, sodium). Percent, % vol, and unitless figures are concentrations, so they equal the per-100 figure. Check serving_size for the denominator the other figures are measured against."New value: +"The same nutrients per serving. Also carries the per-serving figures for macros that have a named _100g field but no named per-serving one (saturated_fat, carbohydrates, fiber, proteins, salt, sodium). Percent, % vol, and unitless figures are concentrations, so they equal the per-100 figure. Check serving_size for the denominator the other figures are measured against. A key ending in _prepared is a prepared-product figure that Open Food Facts scales from the per-100 figure by serving_quantity, which is often a powder's dry portion rather than the prepared serving, so it can describe a fraction of what is consumed."
  2. Changed17 schema fields changed
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"Machine-readable failure mode. Declared by this tool: `not_found`: Open Food Facts answers HTTP 404 or status 0 for the barcode — no contributor has recorded it. `upstream_error`: Open Food Facts returns a 5xx other than 501 or 504, serves an HTML error page with a 2xx or 5xx status, or is unreachable. `upstream_timeout`: Open Food Facts did not answer within the request deadline, or answered 408, 425, or 504. `upstream_rejected`: Open Food Facts refuses the request with a 4xx other than 404, 408, 425, or 429, or with 501 Not Implemented. `rate_limited`: This server's own per-minute product 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: `not_found`: Open Food Facts answers HTTP 404 or status 0 for the barcode — no contributor has recorded it. `upstream_error`: Open Food Facts returns a 5xx other than 501 or 504, serves an HTML error page with a 2xx or 5xx status, answers 2xx with a malformed envelope, or is unreachable. `upstream_timeout`: Open Food Facts did not answer within the request deadline, or answered 408, 425, or 504. `upstream_rejected`: Open Food Facts refuses the request with a 4xx other than 404, 408, 425, or 429, or with 501 Not Implemented. `rate_limited`: This server's own per-minute product budget is spent, or Open Food Facts answers 429. Other values are possible when a failure originates below the handler."
    • changedOutput schema / properties / product / properties / nutriments / properties / additional_100g / additionalProperties / properties / unit / description
      Previous value: -"Unit the figure is expressed in (\"g\", \"kcal\", \"kJ\"). Absent when Open Food Facts records no unit for this nutrient."New value: +"Unit Open Food Facts normalizes this nutrient to: \"g\" for most nutrients, \"kJ\" for energy, energy_kj, and energy_from_fat, \"kcal\" for energy_kcal, \"% vol\" for alcohol, \"%\" for the fruits-vegetables, collagen, cocoa, whole-grain, moisture, and crude (ash, fat, fibre, protein) ratios, and \"mmol/l\" for water hardness; a _prepared entry takes its base nutrient's unit. Absent for the unitless pH and glycemic index."
    • changedOutput schema / properties / product / properties / nutriments / properties / additional_100g / additionalProperties / properties / value / description
      Previous value: -"The figure Open Food Facts reported per 100g."New value: +"The figure Open Food Facts holds per 100 g, or per 100 ml for liquids."
    • changedOutput schema / properties / product / properties / nutriments / properties / additional_100g / description
      Previous value: -"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."New value: +"Every other nutrient Open Food Facts holds per 100 g, or per 100 ml for liquids, 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 in grams, so calcium 0.071 g is 71 mg."
    • changedOutput schema / properties / product / properties / nutriments / properties / additional_serving / additionalProperties / properties / unit / description
      Previous value: -"Unit the figure is expressed in (\"g\", \"kcal\", \"kJ\"). Absent when Open Food Facts records no unit for this nutrient."New value: +"Unit Open Food Facts normalizes this nutrient to: \"g\" for most nutrients, \"kJ\" for energy, energy_kj, and energy_from_fat, \"kcal\" for energy_kcal, \"% vol\" for alcohol, \"%\" for the fruits-vegetables, collagen, cocoa, whole-grain, moisture, and crude (ash, fat, fibre, protein) ratios, and \"mmol/l\" for water hardness; a _prepared entry takes its base nutrient's unit. Absent for the unitless pH and glycemic index."
    • changedOutput schema / properties / product / properties / nutriments / properties / additional_serving / additionalProperties / properties / value / description
      Previous value: -"The figure Open Food Facts reported per serving."New value: +"The figure Open Food Facts holds per serving."
    • changedOutput schema / properties / product / properties / nutriments / properties / additional_serving / description
      Previous value: -"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."New value: +"The same nutrients per serving. Also carries the per-serving figures for macros that have a named _100g field but no named per-serving one (saturated_fat, carbohydrates, fiber, proteins, salt, sodium). Percent, % vol, and unitless figures are concentrations, so they equal the per-100 figure. Check serving_size for the denominator the other figures are measured against."
    • changedOutput schema / properties / product / properties / nutriments / properties / carbohydrates_100g / description
      Previous value: -"Total carbohydrates per 100g in grams."New value: +"Total carbohydrates in grams per 100 g, or per 100 ml for liquids."
    • changedOutput schema / properties / product / properties / nutriments / properties / energy_kcal_100g / description
      Previous value: -"Energy per 100g in kcal."New value: +"Energy in kcal per 100 g, or per 100 ml for liquids."
    • changedOutput schema / properties / product / properties / nutriments / properties / fat_100g / description
      Previous value: -"Total fat per 100g in grams."New value: +"Total fat in grams per 100 g, or per 100 ml for liquids."
    • changedOutput schema / properties / product / properties / nutriments / properties / fiber_100g / description
      Previous value: -"Dietary fiber per 100g in grams. Often absent."New value: +"Dietary fiber in grams per 100 g, or per 100 ml for liquids. Often absent."
    • changedOutput schema / properties / product / properties / nutriments / properties / proteins_100g / description
      Previous value: -"Protein per 100g in grams."New value: +"Protein in grams per 100 g, or per 100 ml for liquids."
    • changedOutput schema / properties / product / properties / nutriments / properties / salt_100g / description
      Previous value: -"Salt per 100g in grams."New value: +"Salt in grams per 100 g, or per 100 ml for liquids."
    • changedOutput schema / properties / product / properties / nutriments / properties / saturated_fat_100g / description
      Previous value: -"Saturated fat per 100g in grams."New value: +"Saturated fat in grams per 100 g, or per 100 ml for liquids."
    • changedOutput schema / properties / product / properties / nutriments / properties / sodium_100g / description
      Previous value: -"Sodium per 100g in grams."New value: +"Sodium in grams per 100 g, or per 100 ml for liquids."
    • changedOutput schema / properties / product / properties / nutriments / properties / sugars_100g / description
      Previous value: -"Total sugars per 100g in grams."New value: +"Total sugars in grams per 100 g, or per 100 ml for liquids."
    • changedOutput schema / properties / product / properties / serving_size / description
      Previous value: -"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."New value: +"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-100 values."
  3. Changed1 schema field changed
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"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 a 5xx other than 501, serves an HTML error page with a 2xx or 5xx status, 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, or 501 Not Implemented. `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."New value: +"Machine-readable failure mode. Declared by this tool: `not_found`: Open Food Facts answers HTTP 404 or status 0 for the barcode — no contributor has recorded it. `upstream_error`: Open Food Facts returns a 5xx other than 501 or 504, serves an HTML error page with a 2xx or 5xx status, or is unreachable. `upstream_timeout`: Open Food Facts did not answer within the request deadline, or answered 408, 425, or 504. `upstream_rejected`: Open Food Facts refuses the request with a 4xx other than 404, 408, 425, or 429, or with 501 Not Implemented. `rate_limited`: This server's own per-minute product budget is spent, or Open Food Facts answers 429. Other values are possible when a failure originates below the handler."
  4. Changed2 schema fields changed
    • changedInput schema / properties / barcode / description
      Previous value: -"EAN-13 or UPC barcode (8–14 digits). The primary key for Open Food Facts. Example: \"3017620422003\" (Nutella FR)."New value: +"Product barcode, digits only: 4–40 digits after any leading zeros. The primary key for Open Food Facts — the barcode of an off_search_products row works as is. Example: \"3017620422003\" (Nutella FR)."
    • changedInput schema / properties / barcode / pattern
      Previous value: -"^\\d{8,14}$"New value: +"^0*[1-9]\\d{3,39}$"
  5. Changed8 schema fields changed
    • changedOutput schema / properties / barcode / description
      Previous value: -"Barcode as returned by the API."New value: +"The input barcode, echoed back unchanged. Open Food Facts can hold the record under another form of the same code (030000010402 resolves to the record stored as 0030000010402); that stored form is not reported."
    • changedOutput schema / properties / error / properties / data / properties / reason / description
      Previous value: -"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."New value: +"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 a 5xx other than 501, serves an HTML error page with a 2xx or 5xx status, 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, or 501 Not Implemented. `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."
    • changedOutput schema / properties / product / properties / ecoscore_grade / description
      Previous value: -"Green-Score/Eco-Score environmental impact letter (a–e, or \"unknown\"). Highly variable — depends on packaging, origins, and transport data completeness."New value: +"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. Highly variable — depends on packaging, origins, and transport data completeness."
    • changedOutput schema / properties / product / properties / ingredients / description
      Previous value: -"Parsed ingredient list. Absent when not yet parsed by contributors."New value: +"Parsed ingredient list, top level in label order, each entry carrying its sub-ingredients. Absent when not yet parsed by contributors."
    • changedOutput schema / properties / product / properties / ingredients / items / description
      Previous value: -"A single parsed ingredient entry."New value: +"A single top-level parsed ingredient entry."
    • addedOutput schema / properties / product / properties / ingredients / items / properties / ingredients
      Added value: +{
      +  "description": "Sub-ingredients of this entry (e.g. the flours under \"cereal\"), in the same entry shape and nested up to two more levels. Absent when the entry has none.",
      +  "items": {
      +    "additionalProperties": false,
      +    "description": "A sub-ingredient of a top-level entry.",
      +    "properties": {
      +      "id": {
      +        "description": "Canonical ingredient ID (e.g. \"en:sugar\", \"en:salt\").",
      +        "type": "string"
      +      },
      +      "ingredients": {
      +        "description": "Sub-ingredients of this entry. Anything nested deeper upstream is listed here as well, right after the entry it belongs under, so no entry is dropped. Absent when the entry has none.",
      +        "items": {
      +          "additionalProperties": false,
      +          "description": "A sub-ingredient at the third level. An entry nested deeper upstream is listed at this level too, directly after the entry it belongs under.",
      +          "properties": {
      +            "id": {
      +              "description": "Canonical ingredient ID (e.g. \"en:sugar\", \"en:salt\").",
      +              "type": "string"
      +            },
      +            "percent_estimate": {
      +              "description": "Estimated share of the whole product, in percent. On a sub-ingredient it is still a share of the whole product, not of its parent — a parent's estimate already includes its sub-ingredients, so summing across levels double-counts.",
      +              "type": "number"
      +            },
      +            "text": {
      +              "description": "Ingredient name as it appears in the list.",
      +              "type": "string"
      +            },
      +            "vegan": {
      +              "description": "\"yes\", \"no\", or \"maybe\" — absent when unknown.",
      +              "type": "string"
      +            },
      +            "vegetarian": {
      +              "description": "\"yes\", \"no\", or \"maybe\" — absent when unknown.",
      +              "type": "string"
      +            }
      +          },
      +          "required": [
      +            "text"
      +          ],
      +          "type": "object"
      +        },
      +        "type": "array"
      +      },
      +      "percent_estimate": {
      +        "description": "Estimated share of the whole product, in percent. On a sub-ingredient it is still a share of the whole product, not of its parent — a parent's estimate already includes its sub-ingredients, so summing across levels double-counts.",
      +        "type": "number"
      +      },
      +      "text": {
      +        "description": "Ingredient name as it appears in the list.",
      +        "type": "string"
      +      },
      +      "vegan": {
      +        "description": "\"yes\", \"no\", or \"maybe\" — absent when unknown.",
      +        "type": "string"
      +      },
      +      "vegetarian": {
      +        "description": "\"yes\", \"no\", or \"maybe\" — absent when unknown.",
      +        "type": "string"
      +      }
      +    },
      +    "required": [
      +      "text"
      +    ],
      +    "type": "object"
      +  },
      +  "type": "array"
      +}
    • changedOutput schema / properties / product / properties / ingredients / items / properties / percent_estimate / description
      Previous value: -"Estimated percentage of this ingredient."New value: +"Estimated share of the whole product, in percent. On a sub-ingredient it is still a share of the whole product, not of its parent — a parent's estimate already includes its sub-ingredients, so summing across levels double-counts."
    • changedOutput schema / properties / product / properties / nutriscore_grade / description
      Previous value: -"Nutri-Score letter (a–e, lowercase). \"a\" is highest nutritional quality. Absent when not enough nutrition data to compute. Regional formula variants exist."New value: +"Nutri-Score grade, lowercase: \"a\" (highest nutritional quality) 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. Regional formula variants exist."
  6. Changed6 schema 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."
  7. Changed6 schema 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"
      -]
  8. Changed9 schema 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"
      +]
  9. Changed1 schema 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. First observed

TDQS

A4.2/5.0
Behavior5/5

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

Goes well beyond the readOnly/idempotent/openWorld annotations: it discloses that missing fields mean "not yet entered by contributors" rather than absent, that nutrition returns one preparation state per read so prepared reads can omit as-sold figures, that computed scores carry regional formula caveats, and that ODbL 1.0 requires attribution. These are exactly the interpretive caveats an agent needs to avoid over-claiming results.

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?

Wait — reassessed: the definition is front-loaded correctly but the single second sentence is bloated by an exhaustive enumeration of every returned attribute (name, brand, quantity, ingredients, allergens, additives, scores, nutrition, categories, labels, packaging, origins, image, completeness). Since an output schema exists, that inventory is redundant and crowds out the genuinely useful caveats. Score reflects over-length rather than waste-free structure.

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

Completeness4/5

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

With an output schema present, the return-value detail is unnecessary, but the description compensates with strong caveats on data provenance, preparation-state nutrition, and score reliability. The notable gap is failure behavior: nothing says what happens when a barcode is validly formatted but unknown to the database, which matters for a primary-key lookup.

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 both parameters are already documented, including the field-dependency behavior (nutriments pulling serving fields, requested_fields echo). The description's only addition is naming barcode symbologies (EAN-13, EAN-8, UPC), which is marginal over the schema's pattern and example; baseline 3 applies.

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?

States a specific verb and resource ("Fetch a packaged food product by barcode") plus the data source (Open Food Facts) and the full barcode range accepted. The barcode-based lookup is self-evidently distinct from the browse/search/compare siblings, so an agent can route correctly without opening the schema.

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

Usage Guidelines3/5

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

Usage is only implied by the required barcode: there is no explicit "use off_search_products when you don't have a barcode" or any statement about when this tool is the wrong choice. The one routing hint given is chaining-oriented ("the barcode of an off_search_products row works as is"), which helps but is not a use-vs-alternative rule.

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

Try in Browser

Glama MCP Gateway

Add one secure layer between your agents and this server.