Zh Education Mcp — independently scanned and version-tracked by SaferSkills.
SaferSkills independently audited Zh Education Mcp (Agent Skill) 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.
🇨🇭 Part of the [Swiss Public Data MCP Portfolio](https://github.com/malkreide)
MCP server for education statistics of the Canton and City of Zurich (BISTA)
zh-education-mcp connects AI assistants to the Bildungsstatistik Kanton Zürich (BISTA) — the official education statistics of the Canton of Zurich. It provides structured access to pupil numbers, school district trends, secondary school profiles, nationality breakdowns, and gymnasium graduation rates.
| Source | Data | API |
|---|---|---|
| BISTA Kanton Zürich | Learner statistics (Volksschule, Mittelschulen, Maturität) | REST/CSV |
All data is fetched from the BISTA public API (bista.zh.ch/basicapi/ogd/) — no API key required. Data is updated annually on 15 September (reference date).
Anchor demo query: "How has the number of pupils in school district Letzi developed over the last 5 years?"
<p align="center"> <img src="assets/demo.png" alt="zh-education-mcp demo: Claude queries BISTA data" width="720"> </p>
# Clone the repository
git clone https://github.com/malkreide/zh-education-mcp.git
cd zh-education-mcp
# Install
pip install -e .
# or with uv:
uv pip install -e .Or with uvx (no permanent installation):
uvx zh-education-mcp# stdio (for Claude Desktop)
python -m zh_education_mcp.server
# Streamable HTTP (port 8000)
python -m zh_education_mcp.server --http --port 8000Try it immediately in Claude Desktop:
"Wie hat sich die Lernendenzahl im Schulkreis Letzi entwickelt?" "Zeige die Maturitätsquote der Stadt Zürich" "Welche Nationalitäten sind in Adliswil am häufigsten?"
→ More use cases by audience →
Edit ~/Library/Application Support/Claude/claude_desktop_config.json (macOS) or %APPDATA%\Claude\claude_desktop_config.json (Windows):
{
"mcpServers": {
"zh-education": {
"command": "python",
"args": ["-m", "zh_education_mcp.server"]
}
}
}Or with uvx:
{
"mcpServers": {
"zh-education": {
"command": "uvx",
"args": ["zh-education-mcp"]
}
}
}Config file locations:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.jsonFor use via claude.ai in the browser (e.g. on managed workstations without local software):
Render.com (recommended):
Dockerfile)MCP_TRANSPORT=streamable-http, MCP_HOST=0.0.0.0, MCP_PORT=8000, and MCP_CORS_ORIGINS=https://claude.aihttps://your-app.onrender.com/mcp💡 "stdio for the developer laptop, Streamable HTTP for the browser."
Health probe: GET /health. Full deployment guide (container, load balancing, CORS, resource limits): docs/deployment.md.
| Tool | Description |
|---|---|
zh_edu_list_schulgemeinden | List all school communities / Schulkreise in Canton Zurich |
zh_edu_schulkreis_trend | Pupil trend by Schulkreis (2000–present) |
zh_edu_overview | Canton-wide learner overview by school level |
zh_edu_sek1_profil | Secondary I profile (Sek A/B/C breakdown) |
zh_edu_staatsangehoerigkeiten | Nationality structure of pupils per school community |
zh_edu_maturitaetsquote | Gymnasium graduation rates by municipality / district |
zh_edu_wohnort_trend | Residence-based learner trend (Bezirk / Gemeinde) |
zh_edu_mittelschulen | Secondary school statistics (Gymnasium, FMS, HMS) |
| Query | Tool |
|---|---|
| "List all Schulkreise in Zurich" | zh_edu_list_schulgemeinden |
| "Pupil trend in Letzi over 5 years" | zh_edu_schulkreis_trend |
| "How many Sek A vs Sek B in Winterthur?" | zh_edu_sek1_profil |
| "Top nationalities in Zürich-Letzi" | zh_edu_staatsangehoerigkeiten |
| "Maturitätsquote of Stadt Zürich" | zh_edu_maturitaetsquote |
┌─────────────────┐ ┌──────────────────────────────┐ ┌──────────────────────────┐
│ Claude / AI │────▶│ zh-education-mcp │────▶│ BISTA Kanton Zürich │
│ (MCP Host) │◀────│ (MCP Server) │◀────│ REST/CSV (Public API) │
└─────────────────┘ │ │ └──────────────────────────┘
│ 8 Tools │
│ Stdio | Streamable HTTP │
│ 24h Cache │
│ No authentication required │
└──────────────────────────────┘| Source | Protocol | Coverage | Auth | Update |
|---|---|---|---|---|
| BISTA Kanton ZH | REST/CSV | Learner statistics 2000–present | None | Annual (15 Sep) |
zh-education-mcp/
├── src/zh_education_mcp/
│ ├── __init__.py # Package
│ ├── config.py # ENV settings (MCP_*)
│ ├── constants.py # API base, endpoints, timeouts
│ ├── logging_setup.py # structured stderr logging
│ ├── provenance.py # response envelope, license attribution
│ ├── http_client.py # egress guard, connection pool, lifespan
│ ├── data.py # cache, CSV fetch, filters, error handling
│ ├── models.py # Pydantic input models
│ ├── tools.py # FastMCP instance, 8 tools, 2 resources
│ └── server.py # thin composition layer + entrypoint
├── tests/
│ └── test_server.py # Unit tests (mocked HTTP with respx)
├── docs/ # deployment, security, egress, roadmap, …
├── Dockerfile # multi-stage, non-root, healthcheck
├── docker-compose.yml # resource limits, read-only rootfs
├── .github/workflows/ci.yml # GitHub Actions (Python 3.11/3.12/3.13)
├── .github/dependabot.yml # monthly dependency updates
├── pyproject.toml
├── CHANGELOG.md
├── CONTRIBUTING.md # + CONTRIBUTING.de.md
├── SECURITY.md # + SECURITY.de.md
├── LICENSE
├── README.md # This file (English)
└── README.de.md # German versionzh_edu_list_schulgemeinden to find valid names).| Topic | Details |
|---|---|
| No personal data | BISTA statistics are aggregated — no individual pupil data is exposed or accessible. All figures are anonymized at the school community level. |
| Read-only | All tools are read-only (readOnlyHint: true). The server cannot modify, delete, or write any data. |
| No authentication | The BISTA API is fully public. No API keys, tokens, or credentials are stored or transmitted. |
| Rate limits | The BISTA API has no documented rate limit, but the server uses a 24h in-memory cache to minimize requests. Please use responsibly. |
| Data license | All data is published under CC BY 4.0 by the Canton of Zurich. Attribution: Bildungsstatistik Kanton Zürich (BISTA). |
| Terms of Service | Usage is subject to the BISTA terms of use. The MCP server is an independent open-source project and is not affiliated with the Canton of Zurich. |
| AI output disclaimer | Statistics are passed through as-is from the BISTA API. AI-generated interpretations or summaries should be verified against the official BISTA portal. |
# Unit tests (no API calls)
PYTHONPATH=src pytest tests/ -m "not live"
# Integration tests (live API calls)
pytest tests/ -m "live"This server targets the MCP specification as implemented by the pinned mcp[cli] SDK (see pyproject.toml). Protocol/spec-version bumps are recorded in CHANGELOG.md. Dependencies (incl. the MCP SDK) receive monthly update PRs via Dependabot (.github/dependabot.yml).
Project phase: Phase 1 — read-only (all tools readOnlyHint: true). See docs/roadmap.md.
See CHANGELOG.md
See CONTRIBUTING.md · 🇩🇪 Beitragen
See SECURITY.md · 🇩🇪 Sicherheit
MIT License — see LICENSE
Hayal Oezkan · malkreide
<!-- mcp-name: io.github.malkreide/zh-education-mcp -->
<!-- BEGIN GENERATED: install -->
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):
{
"mcpServers": {
"zh-education-mcp": {
"command": "uvx",
"args": [
"zh-education-mcp"
]
}
}
}<!-- END GENERATED: install -->
~30 seconds. Free. No account. Every finding cites a rule and a line of evidence.