.codex-plugin — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited .codex-plugin (MCP Server) and scored it 100/100 (green). The audit ran 55 deterministic rules across Security, Supply Chain, Maintenance, Transparency, and Community; it found 0 high-severity and 0 lower-severity findings. The full rule-by-rule trace and per-finding evidence are below. Free, methodology-open.
Findings & checks · 0 flagged
Every scanned point with the score it earned and what moved between them.
First recorded scan — no prior version to compare against.
The primary manifest — the file an agent reads to learn what this artifact does.
<div align="center"> <h1>@cyanheads/openfoodfacts-mcp-server</h1> <p><b>Look up food products by barcode, search by ingredient or nutrition filter, compare products side-by-side, and browse the canonical tag vocabulary via MCP. STDIO or Streamable HTTP.</b> <div>4 Tools</div> </p> </div>
<div align="center">
</div>
<div align="center">
</div>
<div align="center">
Public Hosted Server: https://openfoodfacts.caseyjhand.com/mcp
</div>
Four tools for working with Open Food Facts — a free, crowd-sourced database of 3M+ packaged food products:
| Tool | Description |
|---|---|
off_get_product | Fetch a packaged food product by barcode. Returns name, brand, quantity, ingredients, allergens, additives, Nutri-Score, NOVA group, Green-Score, nutrition per 100g/serving, categories, labels, and data completeness. |
off_search_products | Search by text query and/or structured tag filters (category, brand, label, Nutri-Score grade, NOVA group, country). Returns summary rows with barcodes for follow-up lookups. |
off_compare_products | Side-by-side nutrition and scoring comparison for 2–10 products by barcode. Returns a normalized table of energy, macros, salt, Nutri-Score, NOVA, and Green-Score. |
off_browse_taxonomy | Browse and search the canonical tag vocabulary (categories, labels, allergens, additives, countries, NOVA groups, Nutri-Score grades) for use as filter values in off_search_products. |
off_get_productFetch a packaged food product by barcode (EAN-13 or UPC).
fields parameter restricts the response to a subset (e.g., scores only, or nutrition only)found: false means no contributor has recorded this barcode yet — not a product defectoff_search_productsSearch Open Food Facts by text and/or structured tag filters.
categories_tag, brands_tag, labels_tag, nutrition_grade (a–e), nova_group (1–4), countries_tagoff_browse_taxonomy to resolve human terms (e.g., "organic" → en:organic)page (1-based) and page_size (1–50, default 20); response includes total count for computing total pagesoff_get_product for full label dataoff_compare_productsSide-by-side nutrition and scoring comparison for 2–10 barcodes.
null — comparisons are not imputed or estimatednot_found list identifies barcodes with no contributor record (partial results are not an error)off_browse_taxonomyBrowse the canonical Open Food Facts tag vocabulary before building off_search_products filters.
categories, labels, allergens, additives, countries, nova_groups, nutrition_gradessearch parameter: case-insensitive substring match against tag ID or display name (e.g., "gluten" → en:gluten, en:no-gluten, en:no-added-gluten)search term when browsing categorieslimit controls results returned (1–100, default 20)Built on @cyanheads/mcp-ts-core:
none, jwt, oauthin-memory, filesystem, Supabase, Cloudflare KV/R2/D1Open Food Facts-specific:
User-Agent header (required by OFF terms) is baked into the service layerenergy-kcal_100g) to underscore form — only the _100g and _serving variants are returnedoff_browse_taxonomy — curated 200+ category subset, full allergen/label/additive vocabulariesAgent-friendly output:
found field on every product response — explicit false when a barcode has no contributor record, not a thrown errornot_found list in off_compare_products allows partial batch comparisons without request failureA public instance is available at https://openfoodfacts.caseyjhand.com/mcp — no installation required. Point any MCP client at it via Streamable HTTP:
{
"mcpServers": {
"openfoodfacts-mcp-server": {
"type": "streamable-http",
"url": "https://openfoodfacts.caseyjhand.com/mcp"
}
}
}No API key is required. Add the following to your MCP client configuration file.
{
"mcpServers": {
"openfoodfacts-mcp-server": {
"type": "stdio",
"command": "bunx",
"args": ["@cyanheads/openfoodfacts-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with npx (no Bun required):
{
"mcpServers": {
"openfoodfacts-mcp-server": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@cyanheads/openfoodfacts-mcp-server@latest"],
"env": {
"MCP_TRANSPORT_TYPE": "stdio",
"MCP_LOG_LEVEL": "info"
}
}
}
}Or with Docker:
{
"mcpServers": {
"openfoodfacts-mcp-server": {
"type": "stdio",
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "MCP_TRANSPORT_TYPE=stdio",
"ghcr.io/cyanheads/openfoodfacts-mcp-server:latest"
]
}
}
}For Streamable HTTP, set the transport and start the server:
MCP_TRANSPORT_TYPE=http MCP_HTTP_PORT=3010 bun run start:http
# Server listens at http://localhost:3010/mcpUser-Agent to comply with Open Food Facts' terms of service — this is baked in and requires no configuration.git clone https://github.com/cyanheads/openfoodfacts-mcp-server.gitcd openfoodfacts-mcp-serverbun installcp .env.example .env
# edit .env if you need to override rate limits or the base URLAll configuration is validated at startup via Zod schemas in src/config/server-config.ts.
| Variable | Description | Default |
|---|---|---|
OFF_BASE_URL | Open Food Facts API base URL. Override for local testing against a mock server. | https://world.openfoodfacts.org |
OFF_RATE_LIMIT_PRODUCT | Product read rate limit (requests/min). | 100 |
OFF_RATE_LIMIT_SEARCH | Search rate limit (requests/min). | 10 |
MCP_TRANSPORT_TYPE | Transport: stdio or http. | stdio |
MCP_HTTP_PORT | HTTP server port. | 3010 |
MCP_AUTH_MODE | Auth mode: none, jwt, or oauth. | none |
MCP_LOG_LEVEL | Log level (debug, info, warning, error). | info |
LOGS_DIR | Log file directory (Node.js only). | <project-root>/logs |
OTEL_ENABLED | Enable OpenTelemetry instrumentation. | false |
See .env.example for the full list of optional overrides.
Attribution: Open Food Facts data is released under the Open Database License (ODbL) 1.0. Downstream use must cite Open Food Facts.
# One-time build
bun run rebuild
# Run the built server
bun run start:stdio
# or
bun run start:http bun run devcheck # Lint, format, typecheck, security
bun run test # Vitest test suite
bun run lint:mcp # Validate MCP definitions against specdocker build -t openfoodfacts-mcp-server .
docker run --rm -p 3010:3010 openfoodfacts-mcp-serverThe Dockerfile defaults to HTTP transport, stateless session mode, and logs to /var/log/openfoodfacts-mcp-server. OpenTelemetry peer dependencies are installed by default — build with --build-arg OTEL_ENABLED=false to omit them.
| Directory | Purpose |
|---|---|
src/index.ts | createApp() entry point — registers tools and inits services. |
src/config | Server-specific environment variable parsing and validation with Zod. |
src/mcp-server/tools | Tool definitions (*.tool.ts). |
src/services/openfoodfacts | Open Food Facts API client — HTTP, rate limiting, retry, field normalization. |
src/services/taxonomy | Embedded tag vocabulary service for off_browse_taxonomy. |
tests/ | Unit and integration tests mirroring src/. |
See CLAUDE.md for development guidelines and architectural rules. The short version:
try/catch in tool logicctx.log for request-scoped logging, ctx.state for tenant-scoped storagesrc/mcp-server/tools/definitions/index.tsIssues and pull requests are welcome. Run checks and tests before submitting:
bun run devcheck
bun run testApache-2.0 — see LICENSE for details.
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.