Swiss Food Safety Mcp

io.github.malkreide由 GitHub 账号 malkreide 发布v1.2.0更新于 Oct 24, 2026

BLV open data for food safety and veterinary inspections

已验证STDIO仅桌面位置与生活数据与分析

概览

AI 生成的概览

本地 MCP 服务器,让助手以只读方式访问瑞士 BLV 开放数据,涵盖食品召回、动物疫病监测、食品检查、抗生素使用和农药登记。

可以做什么
获取 BLV 当前的食品召回与健康警告,并浏览或查看 opendata.swiss 上 28 个 BLV 数据集的详情与资源链接。查询 1991 年以来的须通报动物疫病和年度动物健康统计,以及野生鸟类禽流感监测数据。查询各州食品检查结果、兽用抗生素使用和屠宰场肉类检查统计。检索瑞士批准的农药登记,并读取 menuCH-Kids 儿童营养问卷计数。所有工具均为对瑞士联邦数据源的只读 HTTP GET 查询。
适用场景
适合在对话中需要官方瑞士食品安全或兽医信息时使用:查看当前召回、按州查询动物疫病报告、检查结果、抗生素使用或已批准农药,无需离开助手。
运行要求
通过 stdio 在本地运行;需要 Python 3.11+ 和 uv/uvx(也可用 uv tool install 或源码检出)。无需 API 密钥或身份验证。需要访问瑞士联邦主机(opendata.swiss、lindas.admin.ch、news.admin.ch)的网络。另有可选 HTTP 模式供浏览器客户端使用,主机与来源通过 BLV_MCP_* 变量配置。
安装前请注意
只读:不写入、修改或删除数据,也不处理个人数据。请求发往第三方瑞士联邦 API,受其各自服务条款和速率限制约束,大量使用可能触发 CKAN 与 SPARQL 限制。数据由社区打包,与 BLV 无隶属关系,时效取决于上游更新。若启用 HTTP 传输,绑定 0.0.0.0 会将服务器暴露到外部,应限制允许的来源。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Swiss Food Safety Mcp,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

🇨🇭 Part of the Swiss Public Data MCP Portfolio

swiss-food-safety-mcp

[Version] [License: MIT] [Python 3.11+] [MCP] [Data Source] [No Auth Required] [CI]

🌐 English | Deutsch

MCP server connecting AI models to Swiss Federal Food Safety and Veterinary Office (BLV) open data — food recalls, animal disease surveillance, food control results, antibiotic usage, children's nutrition surveys and the pesticide register. No authentication required.


Overview

swiss-food-safety-mcp gives AI assistants like Claude direct access to official Swiss food safety and veterinary data from the Federal Food Safety and Veterinary Office (BLV / Bundesamt für Lebensmittelsicherheit und Veterinärwesen). It provides 11 tools covering food recalls, animal disease surveillance, food control results, antibiotic usage in veterinary medicine, nutrition surveys for children, and the pesticide register.

All data comes from official Swiss federal sources (opendata.swiss, lindas.admin.ch, news.admin.ch). No API keys or authentication are required.

This server follows the No-Auth-First philosophy and is part of a Swiss public sector MCP portfolio.

Anchor demo query: "Are there any current BLV food warnings relevant to Zurich school canteens — and which notifiable animal diseases are currently reported in the canton?"

Demo

[Demo: Claude using blv_get_public_warnings and blv_search_animal_diseases] → More use cases by audience →


Features

  • 🚨 Public warnings & recalls — Live RSS feed of BLV product recalls and health warnings
  • 🐄 Animal disease surveillance — Notifiable animal diseases since 1991 (InfoSM) via the LINDAS SPARQL cube
  • 🐦 Avian influenza monitoring — Wild bird surveillance data with geodata
  • 🥩 Food control results — Cantonal food inspection results and violation rates
  • 💊 Antibiotic usage veterinary — ISABV data on antibiotic use in animal medicine
  • 🧒 Children's nutrition survey — menuCH-Kids questionnaire tallies (answer counts, not nutrient intake)
  • 🌿 Pesticide register — Swiss approved pesticide products and active ingredients
  • 📊 Dataset discovery — Browse all 28 BLV datasets on opendata.swiss via CKAN API
  • 🔗 Dual transport — stdio (Claude Desktop) + Streamable HTTP (cloud/Render.com)
  • 🗣️ Bilingual — English-first documentation, German secondary

Prerequisites

  • Python 3.11+
  • uv or uvx (recommended) — install uv

Installation

Using uvx (recommended — no install needed)

bash
uvx swiss-food-safety-mcp

Using uv

bash
uv tool install swiss-food-safety-mcpswiss-food-safety-mcp

From source

bash
git clone https://github.com/malkreide/swiss-food-safety-mcpcd swiss-food-safety-mcpuv syncuv run swiss-food-safety-mcp

Quickstart

Add to claude_desktop_config.json:

macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json

json
{  "mcpServers": {    "swiss-food-safety": {      "command": "uvx",      "args": ["swiss-food-safety-mcp"]    }  }}

Try it immediately in Claude Desktop:

"Which BLV food warnings are currently active?"
"Are there any notifiable animal diseases reported in Zurich canton this year?"

Other MCP Clients (Cursor, Windsurf, VS Code + Continue)

json
{  "mcpServers": {    "swiss-food-safety": {      "command": "uvx",      "args": ["swiss-food-safety-mcp"]    }  }}

Cloud Deployment (Streamable HTTP)

For use via claude.ai in the browser (e.g. on managed workstations without local software):

bash
# Loopback only (default) — safe for local testing:swiss-food-safety-mcp --http# Server runs on 127.0.0.1:8002
# External exposure (e.g. behind the Render TLS proxy):swiss-food-safety-mcp --http --host 0.0.0.0

⚠️ The HTTP transport binds to 127.0.0.1 by default. Pass --host 0.0.0.0 only when external exposure is intended. Set BLV_MCP_ALLOWED_ORIGINS (comma-separated, no wildcard) to permit browser clients; it defaults to https://claude.ai.

Render.com (recommended):

  1. Push/fork the repository to GitHub
  2. On render.com: New Web Service → connect GitHub repo
  3. Set the start command to: swiss-food-safety-mcp --http --host 0.0.0.0
  4. In claude.ai under Settings → MCP Servers, add: https://your-app.onrender.com/mcp

Docker:

bash
docker build -t swiss-food-safety-mcp .docker run -p 8002:8002 swiss-food-safety-mcp# or, with explicit CPU/memory limits:docker compose up

The image is a non-root, multi-stage build; the container already binds 0.0.0.0 and includes a healthcheck. docker-compose.yml additionally caps CPU and memory.

💡 "stdio for the developer laptop, Streamable HTTP for the browser."

🔧 Configuration — every runtime setting is overridable via BLV_MCP_* environment variables (BLV_MCP_HTTP_HOST, BLV_MCP_HTTP_PORT, BLV_MCP_ALLOWED_ORIGINS, BLV_MCP_TIMEOUT, BLV_MCP_OTEL_ENDPOINT, …). Outbound requests are restricted to Swiss federal hosts (*.admin.ch, opendata.swiss). Optional OpenTelemetry tracing: install with pip install swiss-food-safety-mcp[otel] and set BLV_MCP_OTEL_ENDPOINT.


Available Tools

ToolDescriptionData Source
blv_get_public_warningsCurrent food recalls & health warningsnews.admin.ch RSS
blv_list_datasetsBrowse all 28 BLV open datasetsopendata.swiss CKAN
blv_get_dataset_infoDataset details & resource URLsopendata.swiss CKAN
blv_search_animal_diseasesNotifiable animal diseases since 1991LINDAS SPARQL (/query)
blv_get_animal_health_statsAnnual animal health statisticsopendata.swiss CSV/JSON
blv_get_food_control_resultsCantonal food inspection resultsopendata.swiss CSV
blv_get_antibiotic_usage_vetVeterinary antibiotic usage (ISABV)opendata.swiss CSV
blv_get_avian_influenzaWild bird avian influenza surveillanceopendata.swiss CSV
blv_get_nutrition_data_childrenmenuCH-Kids: questionnaire tallies (not nutrient intake)opendata.swiss CSV
blv_search_pesticide_productsSwiss approved pesticide registeropendata.swiss XML
blv_get_meat_inspection_statsSlaughterhouse inspection statisticsopendata.swiss CSV/JSON

Example Queries

QueryTool
"Which BLV food warnings are currently active?"blv_get_public_warnings
"Are there animal diseases in Zurich canton in 2024?"blv_search_animal_diseases
"What is the avian influenza situation in Switzerland 2024?"blv_get_avian_influenza
"What do Swiss children actually eat?"blv_get_nutrition_data_children
"Which copper-based pesticides are approved in Switzerland?"blv_search_pesticide_products

Architecture

┌─────────────────┐     ┌─────────────────────────────┐     ┌──────────────────────────────┐│   Claude / AI   │────▶│   Swiss Food Safety MCP     │────▶│  Swiss Federal Open Data     ││   (MCP Host)    │◀────│   (MCP Server)              │◀────│                              │└─────────────────┘     │                             │     │  opendata.swiss (CKAN/CSV)   │                        │  11 Tools · No Auth         │     │  lindas.admin.ch (SPARQL)    │                        │  Stdio | Streamable HTTP    │     │  news.admin.ch (RSS/XML)     │                        └─────────────────────────────┘     └──────────────────────────────┘

Synergies with Related MCP Servers

CombinationUse Case
swiss-food-safety-mcp + zurich-opendata-mcpGeo-mapped animal disease risk near school locations
swiss-food-safety-mcp + fedlex-mcpLink recalls to food law (Lebensmittelgesetz)
swiss-food-safety-mcp + swiss-statistics-mcpNutrition data × socioeconomics by school district
swiss-food-safety-mcp + global-education-mcpSwiss children's nutrition vs. OECD benchmarks

Project Structure

swiss-food-safety-mcp/├── src/│   └── swiss_food_safety_mcp/│       ├── __init__.py        # Package metadata│       └── server.py          # All tools, resources, prompts├── tests/│   ├── __init__.py│   └── test_server.py         # Unit tests (no live API calls)├── .github/│   └── workflows/│       └── ci.yml             # Python 3.11–3.13 matrix├── pyproject.toml             # hatchling build, uv-compatible├── CHANGELOG.md├── CONTRIBUTING.md            # Contribution guide (English)├── CONTRIBUTING.de.md        # Contribution guide (German)├── SECURITY.md               # Security policy (English)├── SECURITY.de.md            # Security policy (German)├── LICENSE                    # MIT├── README.md                  # This file (English)└── README.de.md               # German version

Data Sources

SourceDescriptionFormat
opendata.swiss/BLV28 open datasetsCSV, JSON, Parquet, SPARQL, XML
lindas.admin.ch/sparqlSwiss linked data SPARQL endpointRDF/SPARQL
news.admin.ch RSSBLV public warnings & recallsRSS/XML
blv.admin.chBLV website (DE/FR/IT/EN)HTML

All data is open government data (OGD) under Creative Commons with attribution requirement.


Known Limitations

  • RSS feed: Limited to the most recent BLV publications; no historical archive
  • Pesticide register: XML parsing may be slow for queries returning large result sets
  • CKAN datasets: Opendata.swiss rate limits apply under heavy usage
  • Animal disease data: Canton-level filtering depends on data completeness in the source
  • Datasets are pinned, not searched: each data tool names its dataset slug and the resource that carries the data (see DATENQUELLEN in server.py). A keyword search takes the first hit and therefore falls back silently onto something plausible — that is how blv_get_animal_health_stats came to return antibiotics data, and how blv_get_food_control_results came to return a code list out of a dataset whose 26 resources include 18 of them. scripts/record_fixtures.py re-measures the pinned pairs on every run; a renamed dataset now fails loudly.
  • Children's nutrition is questionnaire tallies, not nutrient intake: the only menuCH-Kids dataset published on opendata.swiss carries answer counts (Geschlecht, Sprachregion, Altersgruppe, Frage, Antwort, Anzahl). The docstring previously promised nutrient intake against dietary recommendations and offered "Energie", "Zucker", "Eisen" as filter examples — those matched nothing and returned an empty list. Adult food-consumption data exists as a separate dataset that this server does not cover.
  • The SPARQL-to-CSV fallback is gone. It could never work: the one CSV resource of the fallback dataset is a ZIP file declared as format: CSV. With the endpoint corrected the fallback is also unnecessary — and a fallback that hides a broken query is worse than none.

Safety & Limits

  • Read-only: All tools perform HTTP GET requests only — no data is written, modified, or deleted.
  • No personal data: The APIs return aggregated public health and food safety statistics. No personally identifiable information is processed or stored by this server.
  • Rate limits: opendata.swiss CKAN and lindas.admin.ch SPARQL are public APIs; use limit and filtering parameters conservatively. The server enforces a 30-second timeout per request.
  • Data freshness: RSS warnings reflect the latest BLV publications at query time. Statistical datasets (animal diseases, food control, antibiotics) are updated periodically by the BLV. No caching is performed by this server.
  • Terms of service: Data is subject to the ToS of each source — opendata.swiss, lindas.admin.ch, news.admin.ch. BLV data is published under Creative Commons with attribution.
  • No guarantees: This server is a community project, not affiliated with the BLV or the Swiss federal administration. Availability depends on upstream APIs.

Deployment & Scaling

This server is Phase 1 — read-only (see ROADMAP.md): all 11 tools are read-only queries with no write surface.

Run it as a single instance. The Streamable HTTP transport keeps per-session state, so horizontal scaling would require Mcp-Session-Id sticky routing at the load balancer plus a shared session store — neither is implemented, by design, for a server of this scope. A single Render instance (or one container) is the supported deployment; docker-compose.yml sets explicit CPU/memory limits for self-hosting.


Testing

bash
# Unit + contract tests (no network) — this is what CI runsPYTHONPATH=src pytest tests/ -m "not live"
# All tests including live API checksPYTHONPATH=src pytest tests/
# Re-measure which dataset and resource each tool hitsPYTHONPATH=src python scripts/record_fixtures.py

54 tests — 53 offline, 1 live.

Why the fixtures are recorded rather than written

A hand-written mock encodes its author's assumption and therefore cannot refute it: production code and fixture come from the same head, the same hour, the same reading of the docs. Where both are wrong, both are wrong together — and the suite stays green.

This repo had it in pure form. Every mocked CKAN resource was named "name": "CSV". On opendata.swiss the same field reads Food establishments 2025 or Food establishments codelist administrative measures — and that difference alone decided whether a tool returned inspection results or a code legend. The mocks could not express the distinction, so no test could fail on it.

What is recorded is therefore the selection: for each tool, the pinned dataset slug, the resource that was hit, and that file's header line. The header is the object of the exercise — it separates data from a legend, and it shows whether the BOM and the delimiter were handled. PROVENANCE.md names the source, the date, the selection rule and the SHA-256 for each file.

Two of the recorded measurements are controls: an invented path under lindas.admin.ch (POST 404, so the 404 on /sparql is real) and an invented class in the fsvo namespace (0 instances, so the previously queried foag class genuinely does not exist). Without them each measurement would only show what we received. The recorder aborts if a control stops discriminating, if a pinned resource disappears, if a header line is empty or starts with a BOM, or if one of the findings is superseded.


MCP Protocol Version

This server speaks spec 2026-07-28 natively. It runs fastmcp 4.x, which pins mcp 2.x, and that SDK serves two protocol eras over the same server object:

EraRevisionHow a client reaches it
modern2026-07-28server/discover, metadata in _meta.io.modelcontextprotocol/*
handshake (legacy)2025-11-25the classic initialize exchange

A current client gets 2026-07-28; one that has not moved yet falls back to the handshake and still gets every tool. Neither revision is chosen by this server — the SDK negotiates, and the pin records which pair that negotiation is allowed to produce.

The modern era is not just a higher number. It has no initialize handshake and no InitializeResult: Client.initialize() raises there, and the server metadata comes from server/discover instead. A check that still measured initialize_result.protocolVersion would therefore be testing only the legacy half while reporting a pass for both.

tests/test_protocol_version.py measures each era over its own path rather than comparing constants to one another: it pins both revisions against LATEST_MODERN_VERSION / LATEST_HANDSHAKE_VERSION, connects a real client in each mode, asserts the structural absence of InitializeResult in the modern one, and checks that both eras list the same tools. test_das_sdk_fuehrt_weiterhin_zwei_aeren guards the other direction — a downgrade back to mcp 1.x would otherwise reduce half of those assertions to an import error nobody reads.

The transport allow-list moved with the SDK: Mcp-Method, Mcp-Name and MCP-Protocol-Version are the routing headers spec 2026-07-28 mirrors into HTTP, and mcp.shared.inbound now reads them, so CORS lists them. Mcp-Param-* is deliberately still absent — the spec mints those only for parameters a tool marks with x-mcp-header, and no tool here does.


Changelog

See CHANGELOG.md


Contributing

See CONTRIBUTING.md


Security

See SECURITY.md for the security policy and how to report a vulnerability.


License

MIT License — see LICENSE


Author

Hayal Oezkan · github.com/malkreide


Credits & Related Projects

Installation

Run via uv's uvx — no clone or manual install needed. Add to your MCP client config (mcpServers for Claude Desktop, Cursor and Windsurf; use a top-level servers key for VS Code in .vscode/mcp.json):

json
{  "mcpServers": {    "swiss-food-safety-mcp": {      "command": "uvx",      "args": [        "swiss-food-safety-mcp"      ]    }  }}

来源:README.md,提交 ad7c4b4

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

2
  1. v1.2.0最新Sep 27, 2026
  2. v1.1.5Sep 16, 2026

评分

已满足适用检查项的 50%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分