Skip to main content
Glama
malkreide

swiss-school-calendar-mcp

by malkreide

🇹🇭 Teil des Swiss Public Data MCP Portfolio

Dies ist ein privates Projekt. Es ist unabhÀngig von jeglicher Arbeitgeber- oder institutioneller Zugehörigkeit und stellt keine offizielle Position einer Behörde dar.

📅 swiss-holidays-mcp

License: MIT Python 3.10+ MCP CI No Auth Required Data Source

Ein Schweizer Feiertagskalender fĂŒr KI-Agenten — gesetzliche Feiertage, Schulferien und lange Wochenenden fĂŒr alle 26 Kantone, mit kantonsĂŒbergreifendem Vergleich. Schulferien werden nach Schulart unterschieden, was wichtiger ist, als es zunĂ€chst scheint. Kein API-SchlĂŒssel erforderlich.

đŸ‡©đŸ‡Ș Deutsche Version


Überblick

swiss-holidays-mcp ist ein Schweizer Feiertagskalender fĂŒr KI-Assistenten wie Claude — gesetzliche Feiertage, Schulferien und lange Wochenenden fĂŒr alle 26 Kantone, ohne API-SchlĂŒssel. Gesetzliche Feiertage sind kantonal (Berchtoldstag, Fronleichnam & Co. unterscheiden sich je nach Kanton, nicht nur nach dem bundesrechtlichen Minimum). Schulferien werden kantonal festgelegt, manchmal auf Bezirksebene, und — in sechs Kantonen — getrennt nach Schulart. Einen einzigen Bundesferienkalender gibt es nicht; wer kantonsĂŒbergreifend plant, ist sonst darauf angewiesen, 26 PDF-Seiten zu öffnen.

Der Server deckt zwei thematische Cluster ab: gesetzliche Feiertage / lange Wochenenden und Schulferien (mit Schulart-Unterscheidung). Jedes Cluster ist einer Gruppe zweckgebundener Tools zugeordnet, die rohe Behörden-Daten in saubere, mit Herkunftsnachweis versehene JSON-Antworten ĂŒbersetzen. Alle Daten stammen aus der OpenHolidays API (CC BY 4.0) und Nager.Date (MIT).

EselsbrĂŒcke: Ein Duplikat in Schweizer Schuldaten ist meist eine Schulart in Verkleidung. Die zugrunde liegende API veröffentlicht denselben Ferienzeitraum mehrmals, wenn ein Kanton nach Schulart unterscheidet. Das sieht nach duplizierten Daten aus und verleitet zu naiver Deduplizierung — die genau die Unterscheidung zerstören wĂŒrde, die eine Schulbehörde braucht.

Anker-Demo-Abfrage: „In welchen Wochen 2026 haben die Volksschulen von ZĂŒrich, Zug und Aargau gleichzeitig Ferien — und wie viele ĂŒberlappende Tage hat jedes Paar?" → Dies ĂŒbt find_common_free_window, compare_school_holidays und list_school_types in einem einzigen GesprĂ€ch und beantwortet eine Frage, die in jedem Planungszyklus der interkantonalen Koordination wiederkehrt. → Weitere AnwendungsfĂ€lle nach Zielgruppe →

Demo

Demo: Claude verwendet find_common_free_window und compare_school_holidays


Related MCP server: mcp-nager-holidays

Funktionen

  • đŸ« Schulferien — ZeitrĂ€ume pro Kanton und Datumsbereich, unterschieden nach Schulart (VS / MS / BS / EO)

  • 🎌 Gesetzliche Feiertage — kantonale Feiertagssets, nicht nur das bundesrechtliche Minimum (Berchtoldstag & Co.)

  • 🔍 DatumsprĂŒfung — ist ein bestimmtes Datum ein Schul- oder gesetzlicher Feiertag in einem Kanton?

  • 🔗 KantonsĂŒbergreifender Vergleich — paarweise Überlappungsmatrix der Feiertage zwischen Kantonen

  • đŸȘŸ Gemeinsame freie Fenster — Datumsbereiche, in denen alle aufgefĂŒhrten Kantone gleichzeitig Ferien haben

  • 🌉 Lange Wochenenden & BrĂŒckentage — berechnet aus bundesrechtlichen Feiertagen (Nager.Date)

  • đŸ˜ïž Lokale & kommunale Feiertage — Besonderheiten auf Bezirks- und Gemeindeebene wie ZĂŒrichs SechselĂ€uten und Knabenschiessen, mit einem scope-Marker, damit sie nie mit kantonsweiten verwechselt werden

  • 📆 iCal / ICS-Export — die Feiertage eines Kantons fĂŒr ein Jahr als importierbarer .ics-Kalender

  • 🔖 Feiertags-Feed-Ressource — holidays://<canton>/<year> MCP-Ressource mit einer Markdown-Zusammenfassung

  • 📌 „Ist heute Feiertag?" — Ein-Aufruf-Komfort fĂŒr die Alltagsfrage

  • đŸ©ș Quellen-Gesundheit — Erreichbarkeit und Latenz beider Upstreams, jederzeit bewertbar

  • 🔑 Keine Authentifizierung erforderlich — beide Datenquellen sind öffentlich zugĂ€nglich

  • ☁ Dualer Transport — stdio fĂŒr Claude Desktop, Streamable HTTP/SSE fĂŒr Cloud-Bereitstellung

  • đŸ§Ÿ Herkunftsnachweis auf jeder Antwort — live_api | cached | degraded, niemals eine stille leere Liste


Datenquellen

Quelle

Daten

Lizenz

OpenHolidays API

Kantone, Schularten, Schulferien, gesetzliche Feiertage

CC BY 4.0

Nager.Date

Lange Wochenenden und erforderliche BrĂŒckentage

MIT

Beide Quellen sind öffentlich zugĂ€nglich, keine Authentifizierung erforderlich. Namensnennung erforderlich: OpenHolidays (CC BY 4.0) und Nager.Date mĂŒssen bei Verwendung ihrer Daten als Quelle genannt werden.


Tools

Tool

Zweck

Datenquelle

list_cantons

Die 26 Kantone mit ISO-Codes und Amtssprachen

OpenHolidays

list_school_types

Schulart-Gruppen pro Kanton (CH-ZH-VS usw.)

OpenHolidays

get_school_holidays

Schulferien fĂŒr einen Kanton und Datumsbereich

OpenHolidays

get_public_holidays

Gesetzliche Feiertage fĂŒr einen Kanton und ein Jahr

OpenHolidays

get_local_holidays

Gesetzliche Feiertage fĂŒr eine Gemeinde oder einen Bezirk, inkl. lokaler Besonderheiten

OpenHolidays

check_date

Ist ein bestimmtes Datum ein Schul- oder gesetzlicher Feiertag?

OpenHolidays

compare_school_holidays

Paarweise Überlappungsmatrix ĂŒber Kantone hinweg

OpenHolidays

find_common_free_window

Fenster, in denen alle aufgefĂŒhrten Kantone Ferien haben

OpenHolidays

next_school_holidays

Die nÀchsten anstehenden FerienzeitrÀume

OpenHolidays

get_long_weekends

Lange Wochenenden und erforderliche BrĂŒckentage

Nager.Date

export_holidays_ics

Die Feiertage eines Kantons fĂŒr ein Jahr als iCalendar- (.ics)-Dokument

OpenHolidays

is_holiday_today

Ist heute ein Schul- oder gesetzlicher Feiertag in einem Kanton?

OpenHolidays

source_status

Erreichbarkeit und Latenz beider Upstreams

Integriert

Ressourcen

Ressourcen-URI

Inhalt

holidays://{canton}/{year}

Markdown-Zusammenfassung aller gesetzlichen + Schulferien, z. B. holidays://CH-ZH/2026

Alle Tools tragen das vollstĂ€ndige Annotations-Set — readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true (sie erreichen eine externe API). Kein Tool schreibt irgendwohin. Eingaben werden schemavalidisiert (Kantonscodes gegen die 26 bekannten Kantone, Daten als YYYY-MM-DD, year begrenzt, language/school_type auf Whitelist).

Beispiel-AnwendungsfÀlle

Abfrage

Tool

„Welche Kantone gibt es, und wie lauten ihre Codes?"

list_cantons

„Zeige ZĂŒrichs Volksschulferien fĂŒr FrĂŒhling 2026"

get_school_holidays

„Ist der 3. April 2026 ein gesetzlicher Feiertag im Tessin?"

check_date

„Überlappen sich die Schulferien von ZĂŒrich und Zug dieses Jahr?"

compare_school_holidays

„Wann können ZH, ZG, AG gemeinsam eine schulfreie Woche planen?"

find_common_free_window

„Was sind die nĂ€chsten Ferien fĂŒr die Schulen von Basel-Stadt?"

next_school_holidays

„Welche langen Wochenenden hat 2026, und welche BrĂŒckentage brauchen sie?"

get_long_weekends

„Welche lokalen Feiertage hat die Stadt ZĂŒrich, die der Rest des Kantons nicht hat?"

get_local_holidays

„Exportiere ZĂŒrichs 2026er-Feiertage als .ics-Kalender, den ich importieren kann"

export_holidays_ics

„Ist heute im Aargau Feiertag?"

is_holiday_today


đŸ›Ąïž Sicherheit & Grenzen

Aspekt

Details

Zugriff

SchreibgeschĂŒtzt (readOnlyHint: true) — der Server kann keine Daten Ă€ndern oder löschen

Personendaten

Keine Personendaten — alle Quellen sind aggregierte, öffentliche Feiertagskalender

Caching

12-Stunden-In-Memory-TTL (Feiertagstabellen Àndern sich nur wenige Male pro Jahr)

Wiederholung

Exponentielles Backoff 2s / 4s / 8s; 4xx außer 429 werden nicht wiederholt

Timeout

20 Sekunden pro API-Aufruf (8 Sekunden fĂŒr Health-Probes)

Authentifizierung

Keine API-SchlĂŒssel erforderlich — beide Upstreams sind öffentlich zugĂ€nglich

Degradierung

Upstream-Fehler ergibt einen degraded-Envelope mit erklÀrendem note, niemals eine stille leere Liste

Nutzungsbedingungen

Unterliegt den ToS der jeweiligen Datenquellen: OpenHolidays, Nager.Date


Architektur

Dieser Server verwendet Architektur A (nur Live-API, mit In-Memory-Cache).

                    ┌──────────────────────────┐
   Claude / any ───▶│  swiss-holidays-mcp      │
   MCP host         │  (MCPServer · 13 tools)  │
                    └────────┬─────────────────┘
                             │  retry 2s/4s/8s · 12h cache
                    ┌────────┮─────────┐
                    ▌                  ▌
          OpenHolidays API        Nager.Date
          (CC BY 4.0)             (MIT)
          cantons · Schularten    long weekends
          school + public         bridge days

BegrĂŒndung (live verifiziert am 2026-07-19):

  • Alle zehn dokumentierten OpenHolidays-Endpunkte antworteten mit HTTP 200 und plausiblen Payloads; /Subdivisions?countryIsoCode=CH liefert genau 26 Kantone, was der offiziellen Anzahl entspricht.

  • Kein öffentlicher Bulk-Dump konnte zum Build-Zeitpunkt verifiziert werden (openpotato/openholidays.data-Rohzugriff lieferte 404), daher war Architektur B nicht verfĂŒgbar.

  • Feiertagstabellen Ă€ndern sich nur wenige Male pro Jahr, daher entfernt eine 12-Stunden-In-Memory-TTL fast die gesamte Upstream-Last, ohne Veraltungsrisiko.

Konsequenzen:

  • Jede Antwort trĂ€gt provenance (live_api | cached | degraded).

  • Upstream-Fehler ergibt einen degraded-Envelope mit erklĂ€rendem note, niemals eine stille leere Liste.

  • source_status liefert immer einen bewertbaren Gesundheitsbericht.


Live-Probe-Ergebnisse (2026-07-19)

Endpoint

HTTP

Status

Records

Note

/Countries

200

✅ funktioniert

36

/Subdivisions?countryIsoCode=CH

200

✅ funktioniert

26

entspricht der offiziellen Kantonszahl

/Groups?countryIsoCode=CH

200

✅ funktioniert

11

Schulart-Gruppen, nur 6 Kantone

/PublicHolidays (CH, 2026)

200

✅ funktioniert

39

kantonale Ebene enthalten

/SchoolHolidays (CH, 2026)

200

✅ funktioniert

193

183 eindeutig nach Schulart-Aufteilung

/SchoolHolidaysByDate

200

✅ funktioniert

–

/SchoolHolidays?countryIsoCode=XX

200

⚠ still leer

0

ungĂŒltiges Land ≠ Fehler

/Subdivisions?languageIsoCode=ZZ

200

⚠ stiller EN-Fallback

26

ungĂŒltige Sprache ≠ Fehler

/SchoolHolidays ohne Datumsbereich

400

✅ korrekter Fehler

–

RFC 9110 problem+json

Nager /PublicHolidays/2026/CH

200

✅ funktioniert

33

29 Zeilen enthalten counties

Nager /LongWeekend/2026/CH

200

✅ funktioniert

3

Nager /PublicHolidays/2026/XX

404

✅ korrekter Fehler

–

strenger als OpenHolidays

Bekannte Befunde

  1. Scheinbare Duplikate sind Schularten. ZĂŒrich liefert FrĂŒhlingsferien 2026 zweimal: einmal fĂŒr CH-ZH-VS (Volksschulen, gekennzeichnet als Recommended) und einmal fĂŒr CH-ZH-BS + CH-ZH-MS (Berufsfach- und Mittelschulen). Verwenden Sie den Parameter school_type (VS / MS / BS / EO) anstelle einer Deduplizierung.

  2. Nur sechs Kantone unterscheiden nach Schulart (AI, AR, BE, GR, SO, ZH). Anderswo fehlt groups und eine Tabelle deckt alles ab. Der Filter behandelt daher ein fehlendes groups-Feld als „gilt fĂŒr alle".

  3. Subdivision-Codes mischen Ebenen. DatensÀtze können CH-AI-AP oder CH-BE-TH-BL enthalten. Gleichen Sie immer auf das CH-XX-PrÀfix ab, niemals auf String-Gleichheit.

  4. Eine leere Liste ist keine Antwort. Ein unbekannter LĂ€nder- oder Kantonscode liefert HTTP 200 mit []. Dieser Server setzt eine erklĂ€rende note, damit „keine Feiertage" und „ungĂŒltiger Filter" unterscheidbar bleiben.


Voraussetzungen

  • Python 3.10 oder höher

  • uv / uvx (empfohlen) oder pip

  • Internetzugang (beide APIs sind öffentlich verfĂŒgbar)


Installation

AusfĂŒhren ĂŒber uv's uvx — kein Klonen oder manuelles Installieren nötig:

uvx swiss-holidays-mcp

Entwicklung

git clone https://github.com/malkreide/swiss-holidays-mcp
cd swiss-holidays-mcp
pip install -e ".[dev]"

Konfiguration

Claude Desktop

HinzufĂŒgen zu claude_desktop_config.json:

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

{
  "mcpServers": {
    "swiss-holidays": {
      "command": "uvx",
      "args": ["swiss-holidays-mcp"]
    }
  }
}

Claude Desktop neu starten — der Server startet automatisch bei der ersten Verwendung.

Cloud-Bereitstellung (SSE / Streamable HTTP fĂŒr Browserzugriff)

FĂŒr die Nutzung ĂŒber claude.ai im Browser (z. B. auf verwalteten ArbeitsplĂ€tzen ohne lokale Software):

MCP_TRANSPORT=sse PORT=8000 python -m swiss_holidays_mcp

Das SDK stellt SSE unter /sse bereit, nicht unter /mcp.

Variable

Standard

Beschreibung

MCP_TRANSPORT

stdio

Transport: stdio, sse, streamable-http (auch http)

PORT / MCP_PORT

8000

Port fĂŒr HTTP-Transports

MCP_HOST

127.0.0.1

Bind-Adresse fĂŒr HTTP-Transports. StandardmĂ€ĂŸig Loopback; 0.0.0.0 ist opt-in und protokolliert eine Warnung — hinter einem authentifizierenden Reverse-Proxy betreiben.

MCP_CORS_ORIGINS

(leer)

Kommagetrennte zusĂ€tzliche CORS-Origins fĂŒr Browser-Clients (Audit SDK-004). Loopback-Origins sind immer erlaubt; fĂŒgen Sie den öffentlichen Origin hinzu, von dem Ihre UI ausgeliefert wird, z. B. https://ui.example.ch. Niemals *.

Die HTTP-Transports fĂŒgen eine explizite CORS-Ebene hinzu, die den Mcp-Session-Id-Header exponiert, sodass ein Browser-MCP-Client die Session-ID lesen und Folgeanfragen stellen kann. Die Allow-Liste ist niemals ein Wildcard.

Beim Betrieb von mehr als einer HTTP-Instanz hinter einem Load Balancer sind sticky Sessions mit SchlĂŒssel Mcp-Session-Id erforderlich — siehe docs/scaling.md fĂŒr nginx/Traefik/Kubernetes-Beispiele. Eine einzelne Instanz (der ĂŒbliche Fall) benötigt keine AffinitĂ€tskonfiguration.

💡 „stdio fĂŒr das Entwickler-Laptop, SSE fĂŒr den Browser."


Projektstruktur

swiss-holidays-mcp/
├── src/
│   └── swiss_holidays_mcp/
│       ├── __init__.py       # Package init
│       ├── __main__.py       # Entry point: stdio / SSE / Streamable HTTP
│       ├── server.py         # MCPServer: lifespan, 13 tools, 1 resource, op_* logic
│       ├── client.py         # Shared HTTP client: retry, 12h cache, egress guard
│       ├── guard.py          # Egress / SSRF guard (HTTPS + allow-list + IP blocklist)
│       ├── pinning.py        # DNS-pinning transport (TOCTOU-free connect, SEC-005)
│       ├── ical.py           # RFC 5545 iCalendar (.ics) writer
│       ├── settings.py       # Pydantic-Settings config (loopback default)
│       ├── logging_setup.py  # Structured logging to stderr
│       ├── constants.py      # Canton codes, Schulart suffixes, API bases, allow-list
│       └── models.py         # Pydantic v2 response envelopes
├── tests/
│   ├── conftest.py           # respx fixtures
│   ├── test_tools.py         # Tool unit tests (mocked, no network)
│   ├── test_resilience.py    # Degradation / retry / cache behaviour
│   └── test_live.py          # Live smoke tests (marker: live)
├── docs/                     # roadmap.md, security.md, network-egress.md
├── deploy/                   # Network-layer egress manifests (Cilium / NetworkPolicy)
├── audits/                   # mcp-audit run artifacts
├── Dockerfile                # Non-root multi-stage container
├── .github/
│   ├── dependabot.yml        # Weekly dependency / action update PRs
│   └── workflows/            # ci.yml, live-tests.yml, publish.yml
├── pyproject.toml
├── CHANGELOG.md
├── CONTRIBUTING.md           # Contributing guide (English)
├── CONTRIBUTING.de.md        # Contributing guide (German)
├── SECURITY.md               # Security policy (English)
├── SECURITY.de.md            # Security policy (German)
├── EXAMPLES.md               # Use cases by audience
├── server.json               # MCP registry manifest
├── LICENSE
├── README.md                 # This file (English)
└── README.de.md              # German version

Zur einzeiligen Datei server.py (Audit ARCH-011). Die 13 Tools leben bewusst in einem Modul statt in einem tools/-Paket. Jedes Tool ist ein dĂŒnner, einheitlicher Wrapper (@mcp.tool → @_safe_tool → op_*) ĂŒber eine transportagnostische op_*- Operation, und jede Operation teilt sich denselben kleinen Satz an Helfern (_to_period, _matches_school_type, _require_known_canton, 
) und den einen HolidayClient. Eine Aufteilung auf mehrere Dateien wĂŒrde diesen gemeinsamen Kern verstreuen und Imports duplizieren, ohne Isolationsvorteil — die Datei ist einheitlich gegliedert (Aliase → Helfer → op_*-Logik → Tool-Wrapper → Resource) und jede op_* wird direkt ohne Transport unit-getestet. Eine tools/-Aufteilung ist der geplante Schritt nur, wenn Phase 2 die Tool-Anzahl materiell erhöht.


Lebenszyklus-Phase

Dieser Server befindet sich in Phase 1 (nur lesend) — alle Tools sind nur lesend, keine Authentifizierung, keine Seiteneffekte. Das 13-Tool-Budget (vom empfohlenen Maximum von 15–20) lĂ€sst noch Spielraum. Lokale und kommunale Besonderheiten — einschließlich ZĂŒrichs SechselĂ€uten und Knabenschiessen — werden direkt ĂŒber OpenHolidays via get_local_holidays abgedeckt (ein Live-Test zeigte, dass sie upstream auf Gemeindeebene veröffentlicht sind), sodass keine separate stĂ€dtische Datenquelle dafĂŒr erforderlich ist.


MCP-Primitive & Protokollversion

  • Primitive — Tools + Resources. Die 13 Tools sind idempotente, nebenwirkungsfreie GETs. Eine Resource exponiert einen stabilen URI-Feed (holidays://<canton>/<year>), sodass Clients den Kalender eines Kantons als cachebaren Kontext ohne Tool-Aufruf lesen können. Es gibt keine wiederkehrenden templatisierten Workflows, daher werden Prompts nicht verwendet (wird ĂŒberdacht, falls sich das Ă€ndert).

  • MCP-Protokollversion — zwei Epochen. mcp 2.x bedient beide ĂŒber denselben Server, und die erste Anfrage eines Clients auf einer Verbindung entscheidet, welche gilt: Der initialize-Handshake begrenzt auf 2025-11-25, der Pro-Anfrage-Envelope erreicht 2026-07-28.

    source_status zeigt eine davon in seinem Feld mcp_protocol_version — ein einzelner String kann nicht beide benennen — und es zeigt die Handshake-Obergrenze, weil das das ist, was ein Client, der diesen Server ĂŒber initialize erreicht, tatsĂ€chlich ausgehandelt hat. Gemessen, nicht aus einem Konstantennamen abgeleitet: Ein Client, der den Handshake nach 2026-07-28 fragt, erhĂ€lt 2025-11-25 zurĂŒck.

    MCP_PROTOCOL_VERSION wird aus LATEST_HANDSHAKE_VERSION des SDK abgeleitet statt festgeschrieben, sodass es nicht mehr so driften kann wie einst — es stand zwei Revisionen lang auf 2025-06-18, wĂ€hrend jeder Aufruf es als Tatsache meldete. tests/test_protocol_version.py hĂ€lt beide Epochen gegen das SDK und prĂŒft das gelieferte Feld ebenfalls gegen das SDK, nicht gegen die Konstante, aus der es stammt. Die Wire-Version wird vom gepinnten mcp-SDK ausgehandelt (mcp>=2.0.0,<3).

  • Update-Policy. SDK- und AbhĂ€ngigkeits-Updates erfolgen ĂŒber Dependabot (wöchentlich); Protokollversions- oder Tool-DefinitionsĂ€nderungen werden in CHANGELOG.md mit einem Versionssprung dokumentiert.

Datenklassifikation

Alle Daten sind Öffentlich / Public Open Data — aggregierte Feiertagskalender, keine personenbezogenen Daten (DSG/DSGVO). Dies ist die höchste Klassifikation, die der Server verarbeitet; das vollstĂ€ndige Modell steht in docs/security.md.

Bekannte EinschrÀnkungen

  • Inoffizielle Quelle. OpenHolidays aggregiert kantonale Veröffentlichungen. FĂŒr rechtsverbindliche Daten bleibt die kantonale Behörde maßgeblich. Jede Antwort weist darauf hin.

  • Kommunale Abdeckung hĂ€ngt vom Upstream ab. OpenHolidays fĂŒhrt durchaus öffentliche Feiertage auf Bezirks- und Gemeindeebene (z. B. SechselĂ€uten, Knabenschiessen unter CH-ZH-ZH-ZH), exponiert ĂŒber get_local_holidays. Die VollstĂ€ndigkeit auf Gemeindeebene ist nur so gut wie die Upstream-Daten, die je nach Kanton variieren. Kommunale Schulferien sind nicht separat modelliert.

  • Nager-Lange Wochenenden ignorieren kantonale Feiertage. Sie werden nur aus landesweiten Feiertagen berechnet.

  • Keine Garantie historischer Tiefe. Die Abdeckung von Jahren vor etwa 2020 ist ungleichmĂ€ĂŸig.


Testen

# Unit tests (no network required — respx-mocked)
PYTHONPATH=src pytest tests/ -m "not live"

# Live smoke tests (hits the real upstream APIs)
PYTHONPATH=src pytest tests/ -m "live"

# Linting
ruff check src/ tests/ scripts/
ruff format --check src/ tests/ scripts/

Mitwirken

BeitrĂ€ge sind willkommen! Bitte lesen Sie CONTRIBUTING.md (Englisch) · CONTRIBUTING.de.md (Deutsch) fĂŒr Richtlinien zur Fehlermeldung, Einrichtung der Entwicklungsumgebung, Codestil und Testanforderungen.

Dieses Projekt folgt den Konventionen des Swiss Public Data MCP Portfolio.


Sicherheit

Um eine Schwachstelle zu melden, folgen Sie bitte dem Prozess der verantwortungsvollen Offenlegung in SECURITY.md (Englisch) · SECURITY.de.md (Deutsch). Der Server ist nur lesend und benötigt keinen API-SchlĂŒssel; siehe den Abschnitt Safety & Limits oben fĂŒr das Sicherheitsmodell.


Änderungsprotokoll

Siehe CHANGELOG.md


Bereitstellung fĂŒr die Schweizer öffentliche Verwaltung

Wenn Sie diesen Server fĂŒr eine Schweizer Schulbehörde oder einen kommunalen Anwendungsfall selbst hosten:

  • Datenresidenz: Die Abfragemuster selbst (welche Kantone ein Verwaltungsangestellter vergleicht) können laufende Planungen offenlegen und sollten am besten auf Schweizer oder vertrauenswĂŒrdiger Infrastruktur verbleiben.

  • Upstream-Aufrufe gehen an OpenHolidays (EU-gehostetes OGD-Projekt) und Nager.Date. Keine personenbezogenen Daten verlassen Ihre Umgebung; es werden nur Feiertagskalender abgefragt.

  • Protokollierung: Logs werden nach stderr geschrieben; konfigurieren Sie Ihre IT-Aufbewahrungsrichtlinie entsprechend.

  • HTTP-Transport sollte hinter einem Reverse-Proxy mit Authentifizierung und Pro-IP-Ratenbegrenzung laufen — der Server hat keine eingebaute Authentifizierung.


Lizenz

MIT-Lizenz — siehe LICENSE

Quelldaten unterliegen den Bedingungen von OpenHolidays (CC BY 4.0) und Nager.Date (MIT); bei Verwendung dieser Daten ist die Quellenangabe erforderlich.


Autor

Hayal Oezkan · github.com/malkreide


Danksagungen & verwandte Projekte

Server

Beschreibung

zh-education-mcp

Bildungsdaten des Kantons ZĂŒrich

zurich-opendata-mcp

Open Data der Stadt ZĂŒrich

swiss-statistics-mcp

BFS STAT-TAB — Schweizer Bundesstatistik

swisstopo-mcp

Schweizer Geodaten des Bundes (swisstopo)

MIT-lizenziert. Öffentliches Geld, öffentlicher Code.

Available Tools

13 tools
check_dateA
Read-onlyIdempotent

Check whether a given date falls into school holidays or a public holiday.

The everyday scheduling question: can we hold the parents' evening on that Thursday? Checks one date against both school and public holidays.

The everyday question behind this tool: "Can we schedule the parents' evening on that Thursday?"

ParametersJSON Schema
NameRequiredDescriptionDefault
cantonYesISO code, e.g. CH-ZH
languageNoDE
school_typeNo
check_date_isoYesDate as YYYY-MM-DD

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
cantonYes
sourceYesAttribution string of the upstream source.
matchesYes
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
checked_dateYes
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.
is_public_holidayYes
is_school_holidayYes

TDQS

A3.7/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare read-only, idempotent, and non-destructive. Description adds context that it checks both school and public holidays, which is beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Short but includes redundant use-case block repeating the same idea. Could be more concise without losing meaning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Adequately covers core purpose. Output schema exists, so return values not needed. Distinguishes from siblings partly, but lacks edge-case context.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Despite 50% schema coverage, description adds no information about parameters. Relies entirely on schema, which has descriptions for only two of four parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool checks a date for school and public holidays. It distinguishes from siblings like is_holiday_today and get_school_holidays.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Implies usage for single date checking against both holiday types, but no explicit when-to-use or when-not-to-use compared to alternatives like get_school_holidays.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

compare_school_holidaysA
Read-onlyIdempotent

Compare school holiday overlap between cantons for a calendar year.

Quantify inter-cantonal school-holiday overlap (pairwise day counts) for coordinating events or campaigns across cantonal borders.

Returns a pairwise matrix of overlapping holiday days. Defaults to VS (Volksschule) because that is the level most inter-cantonal coordination concerns.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearYes
cantonsYes
languageNoDE
school_typeNoVS

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
rowsYes
yearYes
sourceYesAttribution string of the upstream source.
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.
school_type_filterYes

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already provide readOnlyHint, idempotentHint, and openWorldHint. The description adds the output format and default behavior but does not significantly extend behavioral insight beyond the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, with a structured use case block. Every sentence adds value, no redundant information.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Input schema is covered with defaults and use case. Output schema exists (not shown). The description is adequate for the tool's complexity, though it could elaborate on overlap calculation.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate. It explains the default for school_type and the purpose, but does not detail the language or cantons format, leaving gaps.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool compares school holiday overlap between cantons, returning a pairwise matrix. It is distinct from siblings like get_school_holidays or find_common_free_window.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The use case explicitly states when to use the tool (coordinating events across cantonal borders) and explains the default school type (VS) as most relevant. It lacks explicit alternatives, but context is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

export_holidays_icsA
Read-onlyIdempotent

Export a canton's holidays for a year as an iCalendar (.ics) document.

Produce a ready-to-import .ics calendar of a canton's holidays for a year, filtered by public/school and Schulart.

Returns a ready-to-save text/calendar document with one all-day event per holiday. include selects all (default), public or school; combine with school_type (VS/MS/BS/EO) to narrow school holidays.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearYes
cantonYesISO code, e.g. CH-ZH
includeNoall
languageNoDE
school_typeNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
icsYesThe full iCalendar (text/calendar) document.
noteNoHuman-readable caveat, set when provenance is 'degraded'.
yearYes
cantonYes
sourceYesAttribution string of the upstream source.
filenameYesSuggested file name, e.g. holidays-CH-ZH-2026.ics.
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
event_countYesNumber of VEVENTs in the calendar.
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, openWorldHint=true, idempotentHint=true, and destructiveHint=false. The description adds that the output is a text/calendar document with all-day events, and explains how parameters filter holidays. This complements the annotations without contradiction.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise and well-structured: one sentence for the main purpose, a use_case block, and a sentence detailing return and parameters. Every sentence adds value, and there is no redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the output schema exists and annotations are rich, the description covers the essential behavioral and parameter details. It explains the output type and filtering options. Minor omission: it doesn't mention the output is a downloadable file, but this is inferred from 'ready-to-import .ics document.'

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema covers only 20% of parameters with descriptions. The description adds meaning for 'include' (all, public, school) and 'school_type' (VS/MS/BS/EO) beyond patterns. However, 'language' and the constraints on 'year' and 'canton' are not elaborated. Overall, it provides useful context but leaves some gaps.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool exports a canton's holidays for a year as an iCalendar document. The use_case block reinforces the purpose, and the sibling tools (e.g., check_date, get_school_holidays) are distinct in that they do not produce ICS files, making this tool's purpose unique and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says to produce a ready-to-import .ics calendar, implying use when an ICS file is needed. However, it does not explicitly state when not to use it or mention alternatives (e.g., get_school_holidays for JSON). The guidance is clear but lacks exclusionary context.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

find_common_free_windowA
Read-onlyIdempotent

Find date ranges in which all listed cantons are simultaneously on holiday.

Find a common free window across several cantons — joint events, maintenance or campaigns when every listed canton is on holiday.

Useful for planning campaigns, joint events or maintenance windows across cantonal borders.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearYes
cantonsYes
languageNoDE
min_daysNo
school_typeNoVS

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
sourceYesAttribution string of the upstream source.
windowsYes
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnly, openWorld, idempotent, and non-destructive hints. Description adds context about finding common free windows but does not discuss rate limits, authorization, or other behavioral traits beyond what annotations provide.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Very concise: two short sentences plus a use case block. Front-loaded with the core purpose. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool has 5 parameters and an output schema, the description covers the main use case but lacks details about return format, parameter defaults, and edge cases. Adequate but not comprehensive.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters1/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%; the description does not explain individual parameters (year, cantons, language, min_days, school_type). It only briefly mentions 'listed cantons' and 'year', leaving other parameters without semantic context.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool finds date ranges when all listed cantons are simultaneously on holiday, with a concrete use case. It distinguishes from sibling tools like check_date or is_holiday_today.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Describes when to use it (planning campaigns, joint events, maintenance). Does not explicitly state when not to use, but context from siblings implies alternatives. Slightly lacking explicit exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_local_holidaysA
Read-onlyIdempotent

Public holidays for a single municipality or district, incl. local specifics.

Answer the locality question the canton-level tools flatten away: which holidays are observed only in this town (e.g. Zurich's Sechselaeuten)? scope is 'local' (specific here), 'regional' (canton/district) or 'national' (inherited). Accepts a name or a full subdivision code.

Answers the local question the canton-level tools flatten away: which holidays are observed only here? The city of Zurich, for example, keeps SechselÀuten and Knabenschiessen (both half-day), which the rest of the canton does not.

municipality accepts a name (e.g. "ZĂŒrich", "Morschach") or a full subdivision code (e.g. "CH-ZH-ZH-ZH"). The result lists every holiday that applies in that locality; each carries a scope of local (specific to this place), regional (inherited from the canton/district) or national.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearYes
cantonYesISO code, e.g. CH-ZH
languageNoDE
municipalityYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
countYes
sourceYesAttribution string of the upstream source.
holidaysYes
match_typeNoHow the lookup key resolved (audit ARCH-003): 'exact' (code or full name / validated canton), 'fuzzy' (a single prefix match was assumed) or 'none' (nothing matched — see `note` for suggestions).
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint false. The description adds behavioral context: it describes the scope attribute on returned holidays, that municipality accepts name or full subdivision code, and that results list every holiday applying in the locality. No contradictions.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with use_case and important_notes sections, but it is somewhat lengthy. Every sentence adds value, but it could be slightly more concise without losing clarity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's complexity (many sibling tools) and the presence of comprehensive annotations and an output schema, the description is complete. It explains the key differentiator (local scope) and adequately covers behavior beyond structured fields.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is low (25%), but the description adds meaning for the municipality parameter (accepts name or code) and clarifies the result structure with scope. However, it does not explain the canton, year, or language parameters beyond what the schema already provides.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool returns public holidays for a specific municipality or district, including local specifics, and explicitly distinguishes from canton-level tools that flatten away local holidays.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a use case for when to use this tool (to answer locality questions flatted by canton tools) and explains the scope concept (local/regional/national). It does not explicitly list when not to use it or mention sibling alternatives, but the differentiation is clear.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_long_weekendsA
Read-onlyIdempotent

Return Swiss long weekends and the bridge days needed to create them.

Plan bridge days: which long weekends exist this year and which working days must be taken off to extend them. Computed from federal public holidays (Nager.Date); cantonal-only holidays are not considered.

Sourced from Nager.Date, which computes these from federal public holidays; cantonal-only holidays are not considered.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearYes

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
yearYes
sourceYesAttribution string of the upstream source.
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.
long_weekendsYes

TDQS

A4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare the tool as read-only, idempotent, and non-destructive. The description adds behavioral context: it is computed from federal public holidays from Nager.Date, and cantonal holidays are ignored. This goes beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is fairly structured with a main sentence and XML tags, but it contains redundancy (the note about federal holidays appears twice). It could be more concise.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity (one parameter), annotations, and existence of an output schema, the description adequately covers purpose, usage, and behavioral limitations. It is mostly complete, though it does not describe the output structure.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The input schema has 0% description coverage, but the description implies the 'year' parameter through the use case ('which long weekends exist this year'). However, the description does not explicitly document the parameter or its constraints, so it provides minimal additional meaning.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'Return Swiss long weekends and the bridge days needed to create them', using a specific verb and resource. The use case further clarifies the tool's purpose, distinguishing it from siblings like get_public_holidays.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides a use case for planning bridge days and notes the limitation of only considering federal holidays. It implies when to use this tool, but does not explicitly mention alternatives or when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_public_holidaysA
Read-onlyIdempotent

Return public holidays for one canton and calendar year.

Get a canton's official public holidays for a whole year — cantonal holidays (Berchtoldstag, Fronleichnam) differ, so always pass the canton.

Cantonal holidays such as Berchtoldstag differ substantially across Switzerland, so always pass the canton rather than assuming the federal set.

ParametersJSON Schema
NameRequiredDescriptionDefault
yearYes
cantonYesISO code, e.g. CH-ZH
languageNoDE

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
countYes
sourceYesAttribution string of the upstream source.
holidaysYes
match_typeNoHow the lookup key resolved (audit ARCH-003): 'exact' (code or full name / validated canton), 'fuzzy' (a single prefix match was assumed) or 'none' (nothing matched — see `note` for suggestions).
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.

TDQS

A3.6/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true, idempotentHint=true, and destructiveHint=false, covering safety and idempotency. The description adds that it returns data for a whole year, but no further behavioral details (e.g., performance, errors) are provided, so the added value is moderate.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness3/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short and front-loaded with the purpose, but it contains redundancy (e.g., 'always pass the canton' is stated twice). It could be more concise and structured better.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple read-only tool with an output schema, the description covers the main use case but misses the optional language parameter entirely. Given the sibling tools, it does not differentiate explicitly, leaving some context gaps.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is low at 33% (only canton has a description). The tool description repeats the need to pass the canton and year but does not explain the format or the optional language parameter, failing to compensate for the missing schema descriptions.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool returns public holidays for a canton and year, using the verb 'Return' and specifying the resource and scope. It distinguishes itself from siblings like get_school_holidays and is_holiday_today by emphasizing the need to pass a canton for cantonal holidays.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly advises to 'always pass the canton because cantonal holidays differ substantially,' providing clear context on when to use this tool. However, it does not mention when not to use it or list alternative tools for related queries, slightly reducing the score.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_school_holidaysA
Read-onlyIdempotent

Return school holiday periods for one canton in a date range.

Look up a canton's school holidays for planning within an explicit from/to window (term breaks, parent events, campaigns). Apparent duplicates are the same period per Schulart; set school_type to collapse them. Cantons that do not differentiate return one table.

Args: canton: ISO subdivision code, e.g. CH-ZH. valid_from: Inclusive start date, YYYY-MM-DD. valid_to: Inclusive end date, YYYY-MM-DD. school_type: Optional Schulart suffix -- VS, MS, BS or EO. Use VS for compulsory schooling (Volksschule). language: DE, FR, IT or EN.

Records that look duplicated are usually the same period published for a different Schulart. Set school_type to collapse them.

ParametersJSON Schema
NameRequiredDescriptionDefault
cantonYesISO code, e.g. CH-ZH
languageNoDE
valid_toYesDate as YYYY-MM-DD
valid_fromYesDate as YYYY-MM-DD
school_typeNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
countYes
sourceYesAttribution string of the upstream source.
holidaysYes
match_typeNoHow the lookup key resolved (audit ARCH-003): 'exact' (code or full name / validated canton), 'fuzzy' (a single prefix match was assumed) or 'none' (nothing matched — see `note` for suggestions).
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond annotations (readOnlyHint, idempotentHint), the description discloses duplicate handling and how to collapse them via 'school_type', and explains behavior for cantons that don't differentiate. This adds significant context.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is well-structured with tags but slightly verbose. It could be tightened without losing clarity, but remains efficient.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the presence of an output schema, the description adequately covers use case, parameters, and behavioral quirks. It is complete for a tool of moderate complexity.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The 'Args' section provides clear explanations for all 5 parameters, including format examples and guidance on 'school_type' values. This surpasses the schema descriptions, which had 60% coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'return', resource 'school holiday periods', and constraints (one canton, date range). It distinguishes from siblings like 'get_public_holidays' by focusing on school holidays and canton-specific scope.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The 'use_case' tag explicitly describes when to use the tool (planning within an explicit from/to window). It does not provide direct exclusions but the sibling list implies alternatives for other holiday types.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

is_holiday_todayA
Read-onlyIdempotent

Is today a school or public holiday in the given canton?

One-call convenience for the everyday 'are we off today?' question in a given canton.

Convenience wrapper over check_date for the everyday question "are we off today?".

ParametersJSON Schema
NameRequiredDescriptionDefault
cantonYesISO code, e.g. CH-ZH
languageNoDE
school_typeNo

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
cantonYes
sourceYesAttribution string of the upstream source.
matchesYes
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
checked_dateYes
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.
is_public_holidayYes
is_school_holidayYes

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint, covering the safe nature. The description adds that it's a convenience wrapper for `check_date`, but does not provide significant additional behavioral context beyond what annotations convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is extremely concise: two sentences and a tag. Every word earns its place, and the main purpose is front-loaded immediately.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's simplicity and the presence of annotations and an output schema, the description adequately covers the main use case. It does not explain return values (not needed due to output schema) and is sufficiently complete for a convenience wrapper.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 33% (canton described). The description mentions 'given canton' but does not elaborate on `language` or `school_type` parameters. It fails to compensate for the low coverage, leaving agents unclear on optional parameters.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool checks if today is a school or public holiday in a given canton, using a specific verb and resource. It distinguishes itself from sibling tool `check_date` as a convenience wrapper for the everyday question.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly says 'one-call convenience for the everyday...are we off today?' and 'convenience wrapper over check_date', providing clear context for when to use this tool over alternatives. However, it does not explicitly state when not to use it.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_cantonsA
Read-onlyIdempotent

List the 26 Swiss cantons with their ISO subdivision codes.

Resolve a canton name to the CH-XX code every other tool needs; call this first when the user gives a canton by name.

Use this first to resolve a canton name to the CH-XX code that every other tool expects.

ParametersJSON Schema
NameRequiredDescriptionDefault
languageNoDE

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
sourceYesAttribution string of the upstream source.
cantonsYes
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint=true and destructiveHint=false, indicating a safe read operation. The description adds that it returns 26 cantons with codes and the CH-XX format, which is helpful but not required.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise, with the core action in the first sentence and additional guidance in a separate use case section. It is well-structured and front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a tool with a single optional parameter and an output schema, the description is mostly adequate but fails to document the language parameter's effect. The use case guidance is helpful, but the parameter gap reduces completeness.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0% and the description does not mention the 'language' parameter, its default, or how it affects the output. The description only says 'list the 26 Swiss cantons', without clarifying that names vary by language.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Description clearly states it lists the 26 Swiss cantons with ISO codes. It uses a specific verb 'list' and resource 'Swiss cantons', and the use case differentiates from sibling tools which focus on holidays and dates.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly advises to 'call this first' when resolving a canton name to the CH-XX code needed by other tools. Provides clear when-to-use and a concrete use case.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_school_typesA
Read-onlyIdempotent

List the Schularten (school types) that publish separate holiday tables.

Discover whether a canton differentiates school holidays by Schulart before querying, so VS/MS/BS/EO filters are used only where they exist.

Only a minority of cantons differentiate. For Zurich the codes are CH-ZH-VS (Volksschulen), CH-ZH-MS (Mittelschulen) and CH-ZH-BS (Berufsfachschulen). Cantons absent from this list publish one table for all school types.

ParametersJSON Schema
NameRequiredDescriptionDefault
cantonNo
languageNoDE

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
sourceYesAttribution string of the upstream source.
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.
school_typesYes

TDQS

A4.1/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, openWorldHint, idempotentHint, and destructiveHint=False. The description adds behavioral context: it lists only school types that publish separate holiday tables, and absence means unified table. It also gives example codes for Zurich, enhancing transparency beyond annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is concise with three sentences plus a use_case tag. It is front-loaded with the main action. The use_case tag is helpful but somewhat redundant. No wasted words.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the simple listing nature and presence of output schema, the description covers all necessary context: what the tool does, when to use, behavior regarding missing cantons, and example codes. Annotations cover safety. Complete for its purpose.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0% and parameters have minimal descriptions ('ISO code', 'Language'). The description does not explain the canton parameter format or language parameter function beyond examples. It mentions canton codes in Zurich example but not the ISO pattern. Description does not compensate for lack of schema coverage.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states 'List the Schularten (school types) that publish separate holiday tables.' It uses specific verb+resource, and distinguishes from sibling tools like list_cantons and get_school_holidays by focusing on differentiation of holiday tables.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit use case: 'Discover whether a canton differentiates school holidays by Schulart before querying.' It also notes that only a minority of cantons differentiate, guiding when to use. However, it does not explicitly state when not to use or suggest alternatives.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

next_school_holidaysA
Read-onlyIdempotent

Return the next upcoming school holiday periods for a canton.

Forward-looking planning: the next N school-holiday periods for a canton from today, without computing a date range by hand.

ParametersJSON Schema
NameRequiredDescriptionDefault
countNo
cantonYesISO code, e.g. CH-ZH
languageNoDE
school_typeNoVS

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
countYes
sourceYesAttribution string of the upstream source.
holidaysYes
match_typeNoHow the lookup key resolved (audit ARCH-003): 'exact' (code or full name / validated canton), 'fuzzy' (a single prefix match was assumed) or 'none' (nothing matched — see `note` for suggestions).
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.

TDQS

A3.7/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint, idempotentHint, and non-destructive behavior. The description adds context about computing from today, which is useful but not extensive. No additional behavioral details like rate limits or caching are provided, but the annotations cover the core safety profile.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is short, with a clear main sentence and a helpful use case block. No redundant text, though the use case could be integrated more concisely.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

The description provides the core purpose and context (forward-looking, from today). However, with low parameter documentation and no mention of output format (despite an output schema existing), it is not fully complete for a tool with 4 parameters and sibling alternatives.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters2/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is only 25% (only 'canton' has a description). The tool description does not mention any parameter details, leaving the other three parameters (count, language, school_type) with no semantic guidance beyond the schema's minimal info.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the verb 'Return' and the resource 'next upcoming school holiday periods for a canton', with a specific use case for forward-looking planning. This distinguishes it from sibling tools like 'get_school_holidays' which likely handle date ranges.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The use case explains when to use this tool (forward-looking planning without manual date range computation). However, it does not explicitly state when not to use it or provide direct alternatives, leaving some ambiguity.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

source_statusA
Read-onlyIdempotent

Report reachability and latency of both upstream sources.

Health check before a batch of queries, or to distinguish 'no data' from 'source down' — always returns an evaluable status.

Always returns an evaluable status rather than an empty result set, so that "no data" can be distinguished from "source down".

ParametersJSON Schema
NameRequiredDescriptionDefault

No parameters

Output Schema

ParametersJSON Schema
NameRequiredDescription
noteNoHuman-readable caveat, set when provenance is 'degraded'.
sourceYesAttribution string of the upstream source.
sourcesYes
provenanceYeslive_api = freshly fetched, cached = in-memory cache, degraded = upstream unreachable, stale or empty payload.
all_healthyYes
retrieved_atYesISO-8601 UTC timestamp of the underlying fetch.
mcp_protocol_versionYesMCP wire protocol version this server is built and tested against.

TDQS

A4.5/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already indicate read-only and non-destructive behavior. The description adds that it always returns an evaluable status, which is a behavioral guarantee not covered by annotations. However, it does not detail how reachability or latency is measured.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is very concise with two sentences and a structured use_case tag. Every sentence adds value and is front-loaded.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no parameters and an output schema, the description fully covers what the tool does, when to use it, and its behavioral guarantee. No gaps are evident.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

There are no parameters, so schema coverage is 100%. Baseline 4 is appropriate; the description does not need to add param information.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool reports reachability and latency of upstream sources, with a specific use case for health checks and distinguishing 'no data' from 'source down'. This is distinct from the sibling holiday/date tools.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description explicitly mentions when to use the tool: as a health check before queries or to differentiate source status. It does not specify when not to use it, but the use case is well-defined.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

TDQS

A4.2/5.0
Disambiguation5/5

All 13 tools have clearly distinct purposes. Each targets a specific aspect of Swiss school calendar queries, from date checks to holiday comparisons and exports. There is no ambiguity or overlap.

Naming Consistency4/5

Most tool names follow a verb_noun pattern (e.g., check_date, list_cantons, get_school_holidays). Two tools (is_holiday_today, source_status) deviate slightly, but the pattern is still predictable and readable.

Tool Count5/5

13 tools is well-scoped for the Swiss school calendar domain. Each tool serves a specific need such as querying holidays, comparing cantons, or exporting calendars, without unnecessary duplication.

Completeness5/5

The tool surface covers the full lifecycle of holiday lookups: enumeration (list_cantons, list_school_types), individual checks (check_date, is_holiday_today), bulk retrieval (get_school_holidays, get_public_holidays, get_local_holidays), comparison (compare_school_holidays, find_common_free_window, next_school_holidays, get_long_weekends), export (export_holidays_ics), and health checks (source_status). No obvious gaps.

Maintenance

ActivityActive
ResponsivenessNo issues

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Connectors

Related MCP Servers

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/malkreide/swiss-holidays-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server