openfoodfacts-mcp-server

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

Sollte ich dies verwenden

Qualität und Sicherheit

A
Qualität der Beschreibung
100%
Vollständigkeit des Schemas
97%
Qualität der Benennung
80%
Risiko der Vergiftung
100%
Übereinstimmung der Berechtigungen
100%
Einhaltung des Protokolls
100%

Basierend auf einer automatisierten Analyse der Tool-Definitionen und der Einhaltung des Protokolls.

Kontextkosten

~10,083Tokens (Tool-Definitionen)
~29.0 KBTypische Antwortgröße
Erhebliche Auswirkung auf die Aufmerksamkeit (7.88% von 128k Kontext)

Dies ist die ungefähre Anzahl der Tokens, die jedes Mal verbraucht werden, wenn die Tools des Servers in den Kontext eines Modells geladen werden. Höhere Werte verringern die Aufmerksamkeit, die für andere Aufgaben verfügbar ist.

Installieren

Installation mit einem Klick

Fügen Sie dies Ihrer Datei `claude_desktop_config.json` hinzu:

{
  "mcpServers": {
    "openfoodfacts-mcp-server": {
      "command": "bun",
      "args": [
        "@cyanheads/openfoodfacts-mcp-server"
      ]
    }
  }
}

Ausführbare Pakete

npm@cyanheads/openfoodfacts-mcp-server0.3.6streamable-http

Remote-Endpunkte

https://openfoodfacts.caseyjhand.com/mcpstreamable-http

Was es kann

Tool-Inventar

Tools (4)

🟢 Nur lesen🟡 Schreiben🔴 Löschen⚪ Unbekannt
🟢off_get_product(barcode, fields)

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 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.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "barcode": {
      "type": "string",
      "pattern": "^0*[1-9]\\d{3,39}$",
      "description": "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)."
    },
    "fields": {
      "description": "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.",
      "type": "array",
      "items": {
        "type": "string",
        "enum": [
          "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"
        ],
        "description": "A specific product field to include in the response."
      }
    }
  },
  "required": [
    "barcode"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false
}

Ausgabe-Schema

{
  "type": "object",
  "properties": {
    "barcode": {
      "type": "string",
      "description": "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."
    },
    "product": {
      "type": "object",
      "properties": {
        "product_name": {
          "description": "Product name. May be absent if not yet entered by contributors.",
          "type": "string"
        },
        "brands": {
          "description": "Brand name(s), comma-separated.",
          "type": "string"
        },
        "quantity": {
          "description": "Net quantity as printed on packaging (e.g. \"400g\").",
          "type": "string"
        },
        "ingredients_text": {
          "description": "Raw ingredients text from the label, in the source language.",
          "type": "string"
        },
        "ingredients": {
          "description": "Parsed ingredient list, top level in label order, each entry carrying its sub-ingredients. Absent when not yet parsed by contributors.",
          "type": "array",
          "items": {
            "type": "object",
            "properties": {
              "id": {
                "description": "Canonical ingredient ID (e.g. \"en:sugar\", \"en:salt\").",
                "type": "string"
              },
              "text": {
                "type": "string",
                "description": "Ingredient name as it appears in the list."
              },
              "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"
              },
              "vegan": {
                "description": "\"yes\", \"no\", or \"maybe\" — absent when unknown.",
                "type": "string"
              },
              "vegetarian": {
                "description": "\"yes\", \"no\", or \"maybe\" — absent when unknown.",
                "type": "string"
              },
              "ingredients": {
                "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.",
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "description": "Canonical ingredient ID (e.g. \"en:sugar\", \"en:salt\").",
                      "type": "string"
                    },
                    "text": {
                      "type": "string",
                      "description": "Ingredient name as it appears in the list."
                    },
                    "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"
                    },
                    "vegan": {
                      "description": "\"yes\", \"no\", or \"maybe\" — absent when unknown.",
                      "type": "string"
                    },
                    "vegetarian": {
                      "description": "\"yes\", \"no\", or \"maybe\" — absent when unknown.",
                      "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.",
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "id": {
                            "description": "Canonical ingredient ID (e.g. \"en:sugar\", \"en:salt\").",
                            "type": "string"
                          },
                          "text": {
                            "type": "string",
                            "description": "Ingredient name as it appears in the list."
                          },
                          "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"
                          },
                          "vegan": {
                            "description": "\"yes\", \"no\", or \"maybe\" — absent when unknown.",
                            "type": "string"
                          },
                          "vegetarian": {
                            "description": "\"yes\", \"no\", or \"maybe\" — absent when unknown.",
                            "type": "string"
                          }
                        },
                        "required": [
                          "text"
                        ],
                        "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."
                      }
                    }
                  },
                  "required": [
                    "text"
                  ],
                  "additionalProperties": false,
                  "description": "A sub-ingredient of a top-level entry."
                }
              }
            },
            "required": [
              "text"
            ],
            "additionalProperties": false,
            "description": "A single top-level parsed ingredient entry."
          }
        },
        "allergens_tags": {
          "description": "Canonical allergen tag IDs. Absence means not yet entered — not that the product is allergen-free.",
          "type": "array",
          "items": {
            "type": "string",
            "description": "Canonical allergen tag ID (e.g. \"en:milk\", \"en:gluten\")."
          }
        },
        "traces_tags": {
          "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.",
          "type": "array",
          "items": {
            "type": "string",
            "description": "Canonical allergen tag ID (e.g. \"en:nuts\")."
          }
        },
        "additives_tags": {
          "description": "E-number additive tag IDs. Absence means not yet entered.",
          "type": "array",
          "items": {
            "type": "string",
            "description": "E-number additive tag ID (e.g. \"en:e322\", \"en:e322i\")."
          }
        },
        "ingredients_analysis_tags": {
          "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\").",
          "type": "array",
          "items": {
            "type": "string",
            "description": "Analysis verdict tag (e.g. \"en:non-vegan\", \"en:palm-oil-free\")."
          }
        },
        "nutriscore_grade": {
          "description": "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.",
          "type": "string"
        },
        "nova_group": {
          "description": "NOVA food processing class (1=unprocessed, 2=culinary ingredients, 3=processed, 4=ultra-processed). Absent when not enough data.",
          "type": "number"
        },
        "ecoscore_grade": {
          "description": "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.",
          "type": "string"
        },
        "nutriments": {
          "description": "Nutrition figures normalized to underscore keys. All values may be absent when nutrition data not yet entered.",
          "type": "object",
          "properties": {
            "energy_kcal_100g": {
              "description": "Energy per 100g in kcal.",
              "type": "number"
            },
            "fat_100g": {
              "description": "Total fat per 100g in grams.",
              "type": "number"
            },
            "saturated_fat_100g": {
              "description": "Saturated fat per 100g in grams.",
              "type": "number"
            },
            "carbohydrates_100g": {
              "description": "Total carbohydrates per 100g in grams.",
              "type": "number"
            },
            "sugars_100g": {
              "description": "Total sugars per 100g in grams.",
              "type": "number"
            },
            "fiber_100g": {
              "description": "Dietary fiber per 100g in grams. Often absent.",
              "type": "number"
            },
            "proteins_100g": {
              "description": "Protein per 100g in grams.",
              "type": "number"
            },
            "salt_100g": {
              "description": "Salt per 100g in grams.",
              "type": "number"
            },
            "sodium_100g": {
              "description": "Sodium per 100g in grams.",
              "type": "number"
            },
            "energy_kcal_serving": {
              "description": "Energy per serving in kcal. Absent when serving size not defined.",
              "type": "number"
            },
            "fat_serving": {
              "description": "Total fat per serving in grams. Absent when serving size not defined.",
              "type": "number"
            },
            "sugars_serving": {
              "description": "Sugars per serving in grams. Absent when serving size not defined.",
              "type": "number"
            },
            "additional_100g": {
              "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.",
              "type": "object",
              "propertyNames": {
                "type": "string",
                "description": "Nutrient name, hyphens normalized to underscores."
              },
              "additionalProperties": {
                "type": "object",
                "properties": {
                  "value": {
                    "type": "number",
                    "description": "The figure Open Food Facts reported per 100g."
                  },
                  "unit": {
                    "description": "Unit the figure is expressed in (\"g\", \"kcal\", \"kJ\"). Absent when Open Food Facts records no unit for this nutrient.",
                    "type": "string"
                  }
                },
                "required": [
                  "value"
                ],
                "additionalProperties": false,
                "description": "One nutrient figure with the unit it is expressed in."
              }
            },
            "additional_serving": {
              "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.",
              "type": "object",
              "propertyNames": {
                "type": "string",
                "description": "Nutrient name, hyphens normalized to underscores."
              },
              "additionalProperties": {
                "type": "object",
                "properties": {
                  "value": {
                    "type": "number",
                    "description": "The figure Open Food Facts reported per serving."
                  },
                  "unit": {
                    "description": "Unit the figure is expressed in (\"g\", \"kcal\", \"kJ\"). Absent when Open Food Facts records no unit for this nutrient.",
                    "type": "string"
                  }
                },
                "required": [
                  "value"
                ],
                "additionalProperties": false,
                "description": "One nutrient figure with the unit it is expressed in."
              }
            }
          },
          "additionalProperties": false
        },
        "serving_size": {
          "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"
        },
        "serving_quantity": {
          "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"
        },
        "serving_quantity_unit": {
          "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"
        },
        "categories_tags": {
          "description": "Category tag IDs in canonical form. Use as filter values for off_search_products.",
          "type": "array",
          "items": {
            "type": "string",
            "description": "Canonical category tag ID (e.g. \"en:spreads\")."
          }
        },
        "labels_tags": {
          "description": "Label/certification tag IDs. Absence means not yet entered.",
          "type": "array",
          "items": {
            "type": "string",
            "description": "Canonical label/certification tag ID (e.g. \"en:organic\")."
          }
        },
        "packaging_tags": {
          "description": "Packaging material tag IDs. Often absent.",
          "type": "array",
          "items": {
            "type": "string",
            "description": "Packaging material tag ID (e.g. \"en:cardboard\")."
          }
        },
        "origins_tags": {
          "description": "Ingredient origin tag IDs. Frequently empty.",
          "type": "array",
          "items": {
            "type": "string",
            "description": "Ingredient origin tag ID (e.g. \"en:france\")."
          }
        },
        "countries_tags": {
          "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.",
          "type": "array",
          "items": {
            "type": "string",
            "description": "Canonical country tag ID (e.g. \"en:france\")."
          }
        },
        "image_url": {
          "description": "Front image URL (CDN-hosted JPEG).",
          "type": "string"
        },
        "completeness": {
          "description": "Data completeness score from 0–1. Below 0.5 indicates many fields are missing.",
          "type": "number"
        },
        "data_quality_tags": {
          "description": "Crowd-sourced data quality flags. Absence means not yet checked.",
          "type": "array",
          "items": {
            "type": "string",
            "description": "Crowd-sourced data quality flag (e.g. \"en:nutrition-completed\", \"en:ingredients-completed-at-least-for-one-language\")."
          }
        }
      },
      "additionalProperties": false,
      "description": "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."
    },
    "requested_fields": {
      "description": "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.",
      "type": "array",
      "items": {
        "type": "string",
        "description": "A field name from the requested subset."
      }
    },
    "error": {
      "description": "Present when the call failed. Absent on success.",
      "type": "object",
      "properties": {
        "code": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "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 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.",
              "examples": [
                "not_found",
                "upstream_error",
                "upstream_timeout",
                "upstream_rejected",
                "rate_limited"
              ]
            },
            "recovery": {
              "description": "Actionable next step for the caller.",
              "type": "object",
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "required": [
                "hint"
              ],
              "additionalProperties": {}
            },
            "retryable": {
              "description": "Whether retrying may succeed.",
              "type": "boolean"
            }
          },
          "additionalProperties": {}
        }
      },
      "required": [
        "code",
        "message"
      ],
      "additionalProperties": {}
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false,
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "barcode",
        "product"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ]
}
🟢off_search_products(query, categories_tag, brands_tag, labels_tag, allergens_tag, ...)

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: every word of the query must match the product name, generic name, categories, labels, or brand, and every filter provided must hold (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 are canonical tag IDs (e.g. "en:organic", "en:no-gluten") — use off_browse_taxonomy to resolve human terms to tag IDs. A case variant, synonym, or singular of a tag is resolved to its canonical ID where Open Food Facts recognizes it; anything else is matched exactly. exclude_allergens and exclude_traces drop products that declare an allergen or a "may contain" trace, but a product with no allergen or trace data entered passes them, so confirm a candidate with off_get_product before relying on it. 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.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "query": {
      "description": "Words to find. Every word must match the product name, generic name, categories, labels, or brand — ingredients and quantity are not searched — so put only words the product itself would carry. Stop words of English, French, Spanish, German, and Italian (\"with\", \"the\", \"de\", \"mit\", …) are not required, and neither is a content word that is a stop word in one of them (such as Spanish \"soy\"), though it still ranks the results. Names are matched in the 31 languages the text index analyzes, so a product named only in French is found by its French name. At most 24 words, counting each part of a hyphenated word. 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.",
      "type": "string"
    },
    "categories_tag": {
      "description": "Canonical category tag ID. Example: \"en:breakfast-cereals\", \"en:cheeses\". Use off_browse_taxonomy with facet=\"categories\" to discover valid values.",
      "type": "string"
    },
    "brands_tag": {
      "description": "Brand slug (lowercased, hyphenated). Example: \"nutella\", \"kelloggs\". A brand name is slugged the way Open Food Facts slugs it (\"Ben & Jerry's\" → \"ben-jerry-s\") and then matched exactly — a partial or misspelled slug matches nothing rather than falling back to a near match, so put open-ended brand wording in query instead.",
      "type": "string"
    },
    "labels_tag": {
      "description": "Canonical label/certification tag ID, or an array of up to 10 that must all apply. Example: \"en:organic\", or [\"en:organic\", \"en:fair-trade\"] for products carrying both. Use off_browse_taxonomy with facet=\"labels\".",
      "anyOf": [
        {
          "type": "string",
          "description": "One canonical label tag ID."
        },
        {
          "maxItems": 10,
          "type": "array",
          "items": {
            "type": "string",
            "description": "One canonical label tag ID."
          },
          "description": "Up to 10 canonical label tag IDs, all of which must apply."
        }
      ]
    },
    "allergens_tag": {
      "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. To leave an allergen out, use exclude_allergens.",
      "type": "string"
    },
    "traces_tag": {
      "description": "Canonical allergen tag ID the label warns the product may contain as a trace (\"may contain nuts\"). Example: \"en:nuts\". Trace tags are allergen tags, so off_browse_taxonomy with facet=\"allergens\" resolves them. Selects products carrying the warning; to leave them out, use exclude_traces.",
      "type": "string"
    },
    "exclude_allergens": {
      "description": "Allergen tag IDs a product must not declare, all applied. Example: [\"en:nuts\", \"en:peanuts\"]. Each value must be an allergen tag Open Food Facts recognizes — resolve it with off_browse_taxonomy facet=\"allergens\" — and one it does not recognize is rejected rather than sent, because it would exclude nothing. A product with no allergen data entered passes an exclusion, so check a candidate with off_get_product before relying on it.",
      "maxItems": 14,
      "type": "array",
      "items": {
        "type": "string",
        "description": "One canonical allergen tag ID to exclude, e.g. \"en:nuts\"."
      }
    },
    "exclude_traces": {
      "description": "Allergen tag IDs a product's label must not warn it may contain as traces, all applied. Example: [\"en:nuts\"]. Values are validated like exclude_allergens. A product with no trace data entered passes, so check a candidate with off_get_product before relying on it.",
      "maxItems": 14,
      "type": "array",
      "items": {
        "type": "string",
        "description": "One canonical allergen tag ID to exclude as a trace, e.g. \"en:nuts\"."
      }
    },
    "ingredients_analysis_tag": {
      "description": "Vegan, vegetarian, or palm-oil verdict Open Food Facts computes from the parsed ingredients. Example: \"en:vegan\", \"en:palm-oil-free\". \"en:maybe-vegan\" and \"en:may-contain-palm-oil\" mean the ingredients could not settle it, and the \"-unknown\" values mean no verdict could be computed.",
      "type": "string",
      "enum": [
        "en:palm-oil",
        "en:palm-oil-free",
        "en:may-contain-palm-oil",
        "en:palm-oil-content-unknown",
        "en:vegan",
        "en:maybe-vegan",
        "en:non-vegan",
        "en:vegan-status-unknown",
        "en:vegetarian",
        "en:maybe-vegetarian",
        "en:non-vegetarian",
        "en:vegetarian-status-unknown"
      ]
    },
    "additives_tag": {
      "description": "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.",
      "type": "string"
    },
    "nutrition_grade": {
      "description": "Filter by Nutri-Score grade. \"a\" is highest nutritional quality, \"e\" is lowest. Products without a score are excluded.",
      "type": "string",
      "enum": [
        "a",
        "b",
        "c",
        "d",
        "e"
      ]
    },
    "nova_group": {
      "description": "Filter by NOVA food processing class. \"1\"=unprocessed/minimally processed, \"4\"=ultra-processed. Products without a NOVA score are excluded.",
      "type": "string",
      "enum": [
        "1",
        "2",
        "3",
        "4"
      ]
    },
    "countries_tag": {
      "description": "Canonical country tag ID. Example: \"en:france\", \"en:united-states\". Filters to products sold in that country.",
      "type": "string"
    },
    "nutrient_filters": {
      "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.",
      "maxItems": 18,
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "nutrient": {
            "type": "string",
            "enum": [
              "energy-kcal",
              "fat",
              "saturated-fat",
              "carbohydrates",
              "sugars",
              "fiber",
              "proteins",
              "salt",
              "sodium"
            ],
            "description": "Nutrient to constrain, measured per 100 g. Energy is kilocalories; every other value is grams per 100 g."
          },
          "operator": {
            "type": "string",
            "enum": [
              "lt",
              "lte",
              "gt",
              "gte"
            ],
            "description": "Comparison against value: \"lt\" below, \"lte\" at or below, \"gt\" above, \"gte\" at or above."
          },
          "value": {
            "type": "number",
            "minimum": 0,
            "description": "Threshold to compare against, in the nutrient's per-100 g unit."
          }
        },
        "required": [
          "nutrient",
          "operator",
          "value"
        ],
        "description": "One numeric constraint on a per-100 g nutrient value."
      }
    },
    "sort_by": {
      "description": "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.",
      "type": "string",
      "enum": [
        "last_modified_t",
        "unique_scans_n",
        "created_t",
        "popularity_key"
      ]
    },
    "page": {
      "default": 1,
      "description": "Page number (1-based). Use with page_size to paginate results. A search by tag filters alone is served through page 10 only, so at page_size 50 it reaches the first 500 matches. A search carrying query or nutrient_filters serves only the first 10000 results, so page * page_size must stay at or below 10000. A request past either bound is rejected rather than sent; narrow the filters or change sort_by to bring other products forward.",
      "type": "integer",
      "minimum": 1,
      "maximum": 9007199254740991
    },
    "page_size": {
      "default": 20,
      "description": "Results per page (1–50, default 20). Keep low for initial exploration; increase for comparison workflows.",
      "type": "integer",
      "minimum": 1,
      "maximum": 50
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false
}

Ausgabe-Schema

{
  "type": "object",
  "properties": {
    "total": {
      "type": "number",
      "description": "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."
    },
    "total_is_lower_bound": {
      "type": "boolean",
      "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."
    },
    "page": {
      "type": "number",
      "description": "Current page number (1-based)."
    },
    "page_count": {
      "type": "number",
      "description": "Products returned on this page — page_size except on the last page, or when a match stored under a code Open Food Facts cannot serve was left off. Not the total number of pages."
    },
    "last_page": {
      "description": "Deepest page of this result set that holds products and can be requested, at the page_size used — capped at page 10 on a search by tag filters alone and by the 10000-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.",
      "type": "number"
    },
    "omitted": {
      "description": "Matches on this page left off because Open Food Facts stores them under a code it cannot serve (not 4–40 digits once leading zeros are stripped), so off_get_product could not look them up either. Absent when none was. total still counts them.",
      "type": "number"
    },
    "products": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "barcode": {
            "type": "string",
            "description": "Product barcode, 4–40 digits after any leading zeros — a code off_get_product accepts as is, so pass it there for full details. A match stored under a code Open Food Facts cannot serve is left off the page."
          },
          "product_name": {
            "description": "Product name. May be absent for incompletely entered products.",
            "type": "string"
          },
          "brands": {
            "description": "Brand name(s), comma-separated. Absent when not yet entered.",
            "type": "string"
          },
          "nutriscore_grade": {
            "description": "Nutri-Score grade: \"a\" through \"e\", \"unknown\" when the nutrition data entered is not enough to compute it, or \"not-applicable\" for product categories the score does not cover. Absent when Open Food Facts sent none.",
            "type": "string"
          },
          "nova_group": {
            "description": "NOVA processing class (1–4). Absent when not assigned.",
            "type": "number"
          },
          "ecoscore_grade": {
            "description": "Green-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. Absent when Open Food Facts sent none.",
            "type": "string"
          },
          "categories_tags": {
            "description": "Category tag IDs in canonical form. Use as filter values for off_search_products.",
            "type": "array",
            "items": {
              "type": "string",
              "description": "Canonical category tag ID (e.g. \"en:cheeses\")."
            }
          }
        },
        "required": [
          "barcode"
        ],
        "additionalProperties": false,
        "description": "A single matching product summary row."
      },
      "description": "Matching products. Use barcodes with off_get_product for full label data."
    },
    "notice": {
      "description": "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.",
      "type": "string"
    },
    "text_index_snapshot": {
      "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"
    },
    "exclusion_coverage": {
      "description": "Present only on searches carrying exclude_allergens or exclude_traces. States that products with no allergen or trace data entered pass an exclusion, so a result is not confirmed free of the excluded allergens, and names the off_get_product fields to check.",
      "type": "string"
    },
    "truncated": {
      "description": "True when more results exist beyond this page.",
      "type": "boolean"
    },
    "shown": {
      "description": "Number of products returned on this page.",
      "type": "number"
    },
    "cap": {
      "description": "The page_size that was applied.",
      "type": "number"
    },
    "error": {
      "description": "Present when the call failed. Absent on success.",
      "type": "object",
      "properties": {
        "code": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "description": "Machine-readable failure mode. Declared by this tool: `no_filters`: No search query or filter was provided. `unrecognized_exclusion`: An exclude_allergens or exclude_traces value is not an allergen tag the Open Food Facts vocabulary confirms, or the vocabulary could not be reached to check it — an unrecognized exclusion would exclude nothing. `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. `query_too_long`: query carries more than 24 words, more than the text backend can require at once. `page_out_of_range`: A search by tag filters alone asks for a page past 10, or a search the text backend serves asks for page * page_size beyond its 10000-result window. `upstream_error`: Open Food Facts returns a 5xx other than 501, serves an HTML error page with a 2xx or 5xx status, reports a search-engine failure inside an HTTP 200, or is unreachable. `upstream_timeout`: Open Food Facts did not answer within the request deadline. `upstream_rejected`: Open Food Facts answers 4xx or 501 Not Implemented — 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",
                "unrecognized_exclusion",
                "additives_filter_needs_tag_search",
                "query_too_long",
                "page_out_of_range",
                "upstream_error",
                "upstream_timeout",
                "upstream_rejected",
                "rate_limited"
              ]
            },
            "recovery": {
              "description": "Actionable next step for the caller.",
              "type": "object",
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "required": [
                "hint"
              ],
              "additionalProperties": {}
            },
            "retryable": {
              "description": "Whether retrying may succeed.",
              "type": "boolean"
            }
          },
          "additionalProperties": {}
        }
      },
      "required": [
        "code",
        "message"
      ],
      "additionalProperties": {}
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false,
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "total",
        "total_is_lower_bound",
        "page",
        "page_count",
        "products"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ]
}
🟢off_compare_products(barcodes)

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.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "barcodes": {
      "minItems": 2,
      "maxItems": 10,
      "type": "array",
      "items": {
        "type": "string",
        "pattern": "^0*[1-9]\\d{3,39}$",
        "description": "Product barcode, digits only: 4–40 digits after any leading zeros."
      },
      "description": "2–10 barcodes to compare, returned as one row each in input order. Example: [\"3017620422003\", \"7622210100146\"]."
    }
  },
  "required": [
    "barcodes"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false
}

Ausgabe-Schema

{
  "type": "object",
  "properties": {
    "products": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "barcode": {
            "type": "string",
            "description": "Barcode, echoed exactly as provided in input."
          },
          "product_name": {
            "description": "Product name. Absent when not yet entered by contributors.",
            "type": "string"
          },
          "brands": {
            "description": "Brand name(s), comma-separated. Absent when not yet entered.",
            "type": "string"
          },
          "found": {
            "type": "boolean",
            "description": "False if the barcode has no contributor record."
          },
          "nutriscore_grade": {
            "description": "Nutri-Score grade: \"a\" through \"e\", \"unknown\" when the nutrition data entered is not enough to compute it, or \"not-applicable\" for product categories the score does not cover. Absent when Open Food Facts sent none.",
            "type": "string"
          },
          "nova_group": {
            "description": "NOVA processing class (1–4). Absent when not assigned.",
            "type": "number"
          },
          "ecoscore_grade": {
            "description": "Green-Score (formerly Eco-Score) environmental impact grade: \"a-plus\" (lowest impact), then \"a\" through \"f\"; \"unknown\" when the data it needs is missing, or \"not-applicable\" for product categories the score does not cover. Often absent.",
            "type": "string"
          },
          "energy_kcal_100g": {
            "description": "Energy per 100g in kcal. Absent when not entered.",
            "type": "number"
          },
          "fat_100g": {
            "description": "Total fat per 100g in grams. Absent when not entered.",
            "type": "number"
          },
          "saturated_fat_100g": {
            "description": "Saturated fat per 100g in grams. Absent when not entered.",
            "type": "number"
          },
          "sugars_100g": {
            "description": "Total sugars per 100g in grams. Absent when not entered.",
            "type": "number"
          },
          "salt_100g": {
            "description": "Salt per 100g in grams. Absent when not entered.",
            "type": "number"
          },
          "proteins_100g": {
            "description": "Protein per 100g in grams. Absent when not entered.",
            "type": "number"
          },
          "fiber_100g": {
            "description": "Dietary fiber per 100g in grams. Often absent.",
            "type": "number"
          },
          "completeness": {
            "description": "Data completeness 0–1. Low values mean many fields are missing.",
            "type": "number"
          }
        },
        "required": [
          "barcode",
          "found"
        ],
        "additionalProperties": false,
        "description": "A single product comparison row."
      },
      "description": "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."
    },
    "succeeded": {
      "type": "number",
      "description": "Number of barcodes that resolved to a found product."
    },
    "not_found": {
      "type": "array",
      "items": {
        "type": "string",
        "description": "Barcode with no contributor record, as provided in input."
      },
      "description": "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."
    },
    "failed": {
      "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.",
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "barcode": {
            "type": "string",
            "description": "Barcode whose fetch failed, as provided in input."
          },
          "reason": {
            "type": "string",
            "description": "Declared failure reason — one of upstream_error, upstream_timeout, upstream_rejected, rate_limited."
          },
          "error": {
            "type": "string",
            "description": "What went wrong for this barcode and what to do about it."
          }
        },
        "required": [
          "barcode",
          "reason",
          "error"
        ],
        "additionalProperties": false,
        "description": "A single barcode whose fetch failed."
      }
    },
    "error": {
      "description": "Present when the call failed. Absent on success.",
      "type": "object",
      "properties": {
        "code": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "description": "Machine-readable failure mode. Declared by this tool: `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 — 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 or 501 Not Implemented 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"
              ]
            },
            "recovery": {
              "description": "Actionable next step for the caller.",
              "type": "object",
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "required": [
                "hint"
              ],
              "additionalProperties": {}
            },
            "retryable": {
              "description": "Whether retrying may succeed.",
              "type": "boolean"
            }
          },
          "additionalProperties": {}
        }
      },
      "required": [
        "code",
        "message"
      ],
      "additionalProperties": {}
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false,
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "products",
        "succeeded",
        "not_found"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ]
}
🟢off_browse_taxonomy(facet, search, limit)

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.

Eingabe-Schema

{
  "type": "object",
  "properties": {
    "facet": {
      "type": "string",
      "enum": [
        "categories",
        "labels",
        "allergens",
        "additives",
        "countries",
        "nova_groups",
        "nutrition_grades"
      ],
      "description": "\"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."
    },
    "search": {
      "description": "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.",
      "type": "string"
    },
    "limit": {
      "default": 20,
      "description": "Maximum entries to return (1–100, default 20). There is no offset or page input: Open Food Facts offers no cursor for this lookup, so narrow the search term rather than paging. The tag spelling the term itself (e.g. \"lentil\" → en:lentils) is listed first among the live matches, so it is not the one a small limit cuts.",
      "type": "integer",
      "minimum": 1,
      "maximum": 100
    }
  },
  "required": [
    "facet"
  ],
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false
}

Ausgabe-Schema

{
  "type": "object",
  "properties": {
    "facet": {
      "type": "string",
      "description": "The facet name that was queried (echoes the input)."
    },
    "tags": {
      "type": "array",
      "items": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string",
            "description": "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."
          },
          "name": {
            "type": "string",
            "description": "Human-readable display name (e.g. \"Organic\")."
          }
        },
        "required": [
          "id",
          "name"
        ],
        "additionalProperties": false,
        "description": "A single taxonomy tag entry with its canonical ID and display name."
      },
      "description": "Matching tag entries."
    },
    "total_in_facet": {
      "description": "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.",
      "type": "number"
    },
    "notice": {
      "description": "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.",
      "type": "string"
    },
    "truncated": {
      "description": "True when more tags exist beyond the limit.",
      "type": "boolean"
    },
    "shown": {
      "description": "Number of tags returned.",
      "type": "number"
    },
    "cap": {
      "description": "The limit that was applied.",
      "type": "number"
    },
    "error": {
      "description": "Present when the call failed. Absent on success.",
      "type": "object",
      "properties": {
        "code": {
          "type": "integer",
          "minimum": -9007199254740991,
          "maximum": 9007199254740991,
          "description": "JSON-RPC error code for this failure."
        },
        "message": {
          "type": "string",
          "description": "Human-readable description of what went wrong."
        },
        "data": {
          "type": "object",
          "properties": {
            "reason": {
              "type": "string",
              "description": "Machine-readable failure mode."
            },
            "recovery": {
              "description": "Actionable next step for the caller.",
              "type": "object",
              "properties": {
                "hint": {
                  "type": "string"
                }
              },
              "required": [
                "hint"
              ],
              "additionalProperties": {}
            },
            "retryable": {
              "description": "Whether retrying may succeed.",
              "type": "boolean"
            }
          },
          "additionalProperties": {}
        }
      },
      "required": [
        "code",
        "message"
      ],
      "additionalProperties": {}
    }
  },
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "additionalProperties": false,
  "anyOf": [
    {
      "not": {
        "required": [
          "error"
        ]
      },
      "required": [
        "facet",
        "tags"
      ]
    },
    {
      "required": [
        "error"
      ]
    }
  ]
}

Community

Diesen Server bewerten

Nachweis

Aktuelle Beobachtungen

verifiziertVersion nicht aufgezeichnet4 Tools
verifiziertVersion nicht aufgezeichnet4 Tools