MCP server for education statistics of Canton and City of Zurich (BISTA)
- ✓Open-source license (MIT)
- ✓Actively maintained (<30d)
- ✓Clear description
- ✓Topics declared
claude mcp add zh-education-mcp -- uvx zh-education-mcp{
"mcpServers": {
"zh-education-mcp": {
"command": "uvx",
"args": ["zh-education-mcp"],
"env": {
"MCP_HOST": "<mcp_host>"
}
}
}
}MCP_HOSTMCP Servers overview
> 🇨🇭 **Part of the [Swiss Public Data MCP Portfolio](https://github.com/malkreide)**
# 📊 zh-education-mcp

[](https://opensource.org/licenses/MIT)
[](https://www.python.org/downloads/)
[](https://modelcontextprotocol.io/)
[](https://github.com/malkreide/zh-education-mcp)

> MCP server for education statistics of the Canton and City of Zurich (BISTA)
[🇩🇪 Deutsche Version](README.de.md)
---
## Overview
`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?"*
---
## Demo
<p align="center">
<img src="assets/demo.png" alt="zh-education-mcp demo: Claude queries BISTA data" width="720">
</p>
---
## Features
- 📊 **8 tools** for education data across all school levels
- 🔍 **School district trends** — pupil numbers for all Schulkreise (Letzi, Glattal, Schwamendingen, Oerlikon, Uto, Waidberg, Zürichberg) from 2000 to present
- 🏫 **Secondary school profiles** — breakdown by requirement type (Sek A/B/C, Mittelschule, special classes)
- 🌐 **Nationality structure** — top nationalities of pupils per school community
- 🎓 **Gymnasium graduation rates** — Maturitätsquote by municipality, district, and canton
- 📈 **Canton-wide overview** — all learners by school level, type, gender, and nationality
- 🏠 **Residence-based trends** — pupil counts by place of residence (Bezirk / Gemeinde)
- 🏛️ **Mittelschulen** — Gymnasium, FMS, HMS statistics
- 🔓 **No API key required** — all data under CC BY 4.0
- ☁️ **Dual transport** — stdio (Claude Desktop) + Streamable HTTP (cloud)
---
## Prerequisites
- Python 3.11+
- [uv](https://github.com/astral-sh/uv) (recommended) or pip
---
## Installation
```bash
# 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):
```bash
uvx zh-education-mcp
```
---
## Quickstart
```bash
# stdio (for Claude Desktop)
python -m zh_education_mcp.server
# Streamable HTTP (port 8000)
python -m zh_education_mcp.server --http --port 8000
```
Try 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](EXAMPLES.md) →
---
## Configuration
### Claude Desktop
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
```json
{
"mcpServers": {
"zh-education": {
"command": "python",
"args": ["-m", "zh_education_mcp.server"]
}
}
}
```
Or with `uvx`:
```json
{
"mcpServers": {
"zh-education": {
"command": "uvx",
"args": ["zh-education-mcp"]
}
}
}
```
**Config file locations:**
- macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`
- Windows: `%APPDATA%\Claude\claude_desktop_config.json`
### Cloud Deployment (Streamable HTTP for browser access)
For use via **claude.ai in the browser** (e.g. on managed workstations without local software):
**Render.com (recommended):**
1. Push/fork the repository to GitHub
2. On [render.com](https://render.com): New Web Service → runtime **Docker** (uses the provided `Dockerfile`)
3. Set env vars: `MCP_TRANSPORT=streamable-http`, `MCP_HOST=0.0.0.0`, `MCP_PORT=8000`, and `MCP_CORS_ORIGINS=https://claude.ai`
4. In claude.ai under Settings → MCP Servers, add: `https://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`](docs/deployment.md).
---
## Available Tools
| 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) |
### Example Use Cases
| 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` |
---
## Architecture
```
┌─────────────────┐ ┌──────────────────────────────┐ ┌──────────────────────────┐
│ 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 │
└──────────────────────────────┘
```
### Data Source Characteristics
| Source | Protocol | Coverage | Auth | Update |
|--------|----------|----------|------|--------|
| BISTA Kanton ZH | REST/CSV | Learner statistics 2000–present | None | Annual (15 Sep) |
---
## Project Structure
```
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 version
```
---
## Known Limitations
- **Annual updates only:** BISTA data is updated once per year (reference date: 15 September). The 24h in-memory cache matches this cycle.
- **CSV-based API:** The BISTA API returns CSV data; large datasets may take a moment to parse.
- **School community names:** Names must match exactly (use `zh_edu_list_schulgemeinden` to find valid names).
---
## Safety & Limits
| 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](https://creativecommons.org/licenses/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](https://pub.bista.zh.ch). 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](https://pub.bista.zh.ch). |
---
## Testing
```bash
# Unit tests (no API calls)
PYTHONPATH=src pytest tests/ -m "not live"
# Integration tWhat people ask about zh-education-mcp
What is malkreide/zh-education-mcp?
+
malkreide/zh-education-mcp is mcp servers for the Claude AI ecosystem. MCP server for education statistics of Canton and City of Zurich (BISTA) It has 0 GitHub stars and was last updated today.
How do I install zh-education-mcp?
+
You can install zh-education-mcp by cloning the repository (https://github.com/malkreide/zh-education-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.
Is malkreide/zh-education-mcp safe to use?
+
Our security agent has analyzed malkreide/zh-education-mcp and assigned a Trust Score of 87/100 (tier: Trusted). See the full breakdown of passed checks and flags on this page.
Who maintains malkreide/zh-education-mcp?
+
malkreide/zh-education-mcp is maintained by malkreide. The last recorded GitHub activity is from today, with 0 open issues.
Are there alternatives to zh-education-mcp?
+
Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.
Deploy zh-education-mcp to your cloud
Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.
Maintain this repo? Add a badge to your README
Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.
[](https://claudewave.com/repo/malkreide-zh-education-mcp)<a href="https://claudewave.com/repo/malkreide-zh-education-mcp"><img src="https://claudewave.com/api/badge/malkreide-zh-education-mcp" alt="Featured on ClaudeWave: malkreide/zh-education-mcp" width="320" height="64" /></a>More MCP Servers
Fair-code workflow automation platform with native AI capabilities. Combine visual building with custom code, self-host or cloud, 400+ integrations.
User-friendly AI Interface (Supports Ollama, OpenAI API, ...)
An open-source AI agent that brings the power of Gemini directly into your terminal.
The fastest path to AI-powered full stack observability, even for lean teams.
Real-time global intelligence dashboard. AI-powered news aggregation, geopolitical monitoring, and infrastructure tracking in a unified situational awareness interface
🕷️ An adaptive Web Scraping framework that handles everything from a single request to a full-scale crawl!