The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Srgssr MCP listing page.
🇨🇭 Part of the Swiss Public Data MCP Portfolio
MCP server connecting AI models to SRG SSR public APIs – weather, TV/radio metadata, program guide and Swiss votations/elections since 1900 (SRF, RTS, RSI, RTR, SWI).
srgssr-mcp gives AI assistants like Claude direct access to the public APIs of SRG SSR – Switzerland's national public broadcaster. Weather forecasts, TV and radio metadata, electronic program guides, and historical democratic data (votations and elections since 1900) are all accessible through a single standardised MCP interface.
The server covers five thematic clusters: SRF Weather, Video, Audio, EPG and Polis (Swiss Democracy). Each cluster maps to a group of purpose-built tools that translate raw SRG SSR API data into clean JSON responses.
Anchor demo query: "What were the cantonal results of the popular vote on initiative X in Zurich?" – answered with historical real-time data from the Polis system, not a hallucination.
⚠️ Terms of use: SRG SSR APIs are available for non-commercial use. For commercial use, contact api@srgssr.ch directly.
Or with uvx (no permanent installation):
Or via pip:
Try it immediately in Claude Desktop:
"What will the weather be like in Zurich tomorrow?" "What's on SRF 1 tonight?" "Which popular votes took place in the canton of Bern between 2010 and 2020?"
Minimal (recommended):
Config file locations:
~/Library/Application Support/Claude/claude_desktop_config.json%APPDATA%\Claude\claude_desktop_config.jsonAfter saving, restart Claude Desktop completely.
Compatible with Cursor, Windsurf, VS Code + Continue, LibreChat, Cline, and self-hosted models via mcp-proxy. Set the same environment variables.
For use via claude.ai in the browser (e.g. on managed workstations without local software):
Transport, host, port and mount path are all driven by environment variables
(see srgssr_mcp.server.Settings). Valid values for SRGSSR_MCP_TRANSPORT
are stdio (default), sse, and streamable-http.
💡 "stdio for the developer laptop, SSE for the browser."
This server exposes all three orthogonal MCP primitives:
| Primitive | Mental model | What's here |
|---|---|---|
| Tools (verbs) | Executable functions / parametrized queries | 15 tools — search, list, fetch, aggregate |
| Resources (nouns) | Cache-friendly passive data behind URIs | EPG entries and immutable votation results |
| Prompts (recipes) | Reusable workflow templates | Voting analysis & daily briefing |
Tools cover parametrized searches (year ranges, free-text, paginated listings) where every call may yield different results. Resources expose stable data points that are safe to cache: a published EPG for a given channel/date, or the final result of a closed Swiss votation. Prompts standardise recurring multi-step analyses so users don't have to phrase them from scratch.
| URI template | Description |
|---|---|
epg://{bu}/{channel_id}/{date} | Daily TV/radio program guide for SRF, RTS, RSI (e.g. epg://srf/srf-1/2026-04-30) |
votation://{votation_id} | Detailed result of a closed Swiss popular vote (e.g. votation://v1) |
EPG station ids — hyphenated, and not the same as the livestream ids:
| Business unit | TV | Radio |
|---|---|---|
| SRF | srf-1, srf-2, srf-info | srf-1, srf-2, srf-2-kultur, srf-3, srf-4, srf-musikwelle, srf-virus |
| RTS | rts-1, rts-2, rts-info | LA1ERE, ESPACE2, COULEUR3, OPTION_MUSIQUE |
| RSI | la-1, la-2 | rete-uno, rete-due, rete-tre |
| Name | Arguments | Purpose |
|---|---|---|
analyse_abstimmungsverhalten | votation_id, focus (stadt_land / sprachregionen / kantone) | Structured analysis of a Swiss popular vote |
tagesbriefing_kanton | location, channel_id, business_unit, date | Daily briefing combining weather and EPG |
This server uses snake_case for tool names, following Python ecosystem idioms. While MCP best practice favors camelCase for optimal LLM tokenization, snake_case remains acceptable and keeps tool names aligned with the underlying Python function identifiers.
All tools follow the pattern srgssr_<domain>_<action> with the namespace prefix srgssr_ and a semantically meaningful <domain>_<action> suffix (e.g. srgssr_weather_current, srgssr_polis_get_votations).
| Tool | Description | Data Source |
|---|---|---|
srgssr_weather_search_location | Search for a location by name or postal code to obtain a geolocationId | SRF Meteo |
srgssr_weather_current | Current weather conditions for a Swiss location | SRF Meteo |
srgssr_weather_forecast_24h | Hourly 24-hour forecast | SRF Meteo |
srgssr_weather_forecast_7day | Daily 7-day forecast | SRF Meteo |
| Tool | Description | Data Source |
|---|---|---|
srgssr_video_get_shows | List TV shows for a business unit (character_filter a–z/# selects one initial; omit it to fan out over all 27) | SRG SSR IL |
srgssr_video_get_episodes | Retrieve latest episodes of a show | SRG SSR IL |
srgssr_video_get_livestreams | List live TV channels | SRG SSR IL |
| Tool | Description | Data Source |
|---|---|---|
srgssr_audio_get_shows | List radio shows for one radio channel (channel_id required — the v2 API has no per-unit listing) | SRG SSR IL |
srgssr_audio_get_episodes | Retrieve audio episodes of a show | SRG SSR IL |
srgssr_audio_get_livestreams | List live radio stations | SRG SSR IL |
| Tool | Description | Data Source |
|---|---|---|
srgssr_epg_get_programs | Daily program schedule for a TV or radio channel | SRG SSR IL |
| Tool | Description | Data Source |
|---|---|---|
srgssr_polis_get_votations | Popular votes since 1900 (national or cantonal) | Polis API |
srgssr_polis_get_votation_results | Detailed results of a specific vote | Polis API |
srgssr_polis_get_elections | Election results since 1900 | Polis API |
| Code | Unit | Language |
|---|---|---|
srf | SRF (Schweizer Radio und Fernsehen) | German |
rts | RTS (Radio Télévision Suisse) | French |
rsi | RSI (Radiotelevisione svizzera) | Italian |
rtr | RTR (Radiotelevisiun Svizra Rumantscha) | Romansh |
swi | SWI swissinfo.ch | Multilingual |
| Query | Tool |
|---|---|
| "Weather in Zurich tomorrow?" | srgssr_weather_forecast_24h |
| "What's on SRF 1 tonight?" | srgssr_epg_get_programs |
| "Latest Tagesschau episodes?" | srgssr_video_get_episodes |
| "Popular votes in Canton Bern 2010–2020?" | srgssr_polis_get_votations |
| "Cantonal results of the mask initiative vote?" | srgssr_polis_get_votation_results |
| "All current RTS radio shows?" | srgssr_audio_get_livestreams → srgssr_audio_get_shows |
→ More use cases by audience →
| Source | Data | Access |
|---|---|---|
| developer.srgssr.ch | SRG SSR PUBLIC API V2 (weather, A/V, EPG, Polis) | OAuth2 (free registration) |
Attribution: SRG SSR APIs are subject to the SRG SSR Terms of Use.
This server is in Phase 1: Read-only Wrapper.
The server exposes only GET-style operations against public SRG SSR APIs. There are no write, mutate or delete capabilities by design — see Safety & Limits for the threat-model implications.
swiss-statistics-mcp or swiss-transport-mcp).mcp 2.x serves two protocol eras over the same server, and the client's
first request on a connection decides which one applies:
| Era | Revision | Who reaches it |
|---|---|---|
initialize handshake | 2024-11-05 … 2025-11-25 | What today's clients speak. The server answers with the revision asked for, or with the 2025-11-25 ceiling when the request asks for something newer. |
| Per-request envelope | 2026-07-28 | A request carrying the 2026-07-28 _meta envelope opens a modern connection. |
PROTOCOL_VERSION in src/srgssr_mcp/_app.py names
the modern era. It is validated at import time against the installed SDK's
SUPPORTED_PROTOCOL_VERSIONS — but that list is backwards-compatible and still
contains 2024-11-05, so the membership check catches a revision being dropped,
never a drift. tests/test_protocol_version.py
holds both eras against the SDK and is the check that catches drift. Bumps are
tracked in CHANGELOG.md under the matching release.
.github/dependabot.yml, monthly cadence, grouped under the mcp-sdk label) and run the full test suite before merge.CHANGELOG.md and, if it changes the externally observable wire contract, triggers a minor or major release per Semantic Versioning.| Aspect | Details |
|---|---|
| Access | Read-only — the server only reads from SRG SSR APIs and cannot post, modify or delete any content |
| Personal data | No personal data — all endpoints serve public broadcast metadata, weather observations and historical votation/election results |
| Rate limits | Subject to the tier of your OAuth2 application on developer.srgssr.ch; the server adds sensible per-query caps (e.g. max 100 episodes, 50 shows per list call) |
| Timeout | 30 seconds per upstream API call |
| Authentication | OAuth2 Client Credentials (free registration); secrets stay local, never logged |
| Licensing & use | SRG SSR APIs are for non-commercial use; commercial use requires written permission from api@srgssr.ch |
| Terms of Service | Subject to the SRG SSR Developer Terms of Use — users remain responsible for attribution and compliance |
See CONTRIBUTING.md (English) · CONTRIBUTING.de.md (German)
For the full security posture, vulnerability reporting process and accepted-risk register, see SECURITY.md (English) · SECURITY.de.md (German). The key egress control is summarised below.
The server implements a code-layer egress allowlist (SEC-021, combined with SEC-004 SSRF defense) to prevent unintended external requests. Every outbound HTTP request is validated by _validate_url_safe() in src/srgssr_mcp/_http.py before it is issued.
Three controls per request:
http://, file://, ftp:// and other non-HTTPS schemes are rejected.ALLOWED_HOSTS = {"api.srgssr.ch"} (exact match — subdomain tricks like api.srgssr.ch.attacker.example are blocked). One host covers everything: the OAuth2 token endpoint and every data endpoint.169.254.169.254 cloud-metadata), CGNAT, multicast and reserved ranges (IPv4 + IPv6). Any single match aborts the request — defense-in-depth against DNS rebinding.Violations surface as ValueError and are mapped to a localized Konfigurationsfehler: … message by _handle_error, so internal network details never leak to the MCP client.
Adding a new SRG SSR domain:
ALLOWED_HOSTS in src/srgssr_mcp/_http.py.CHANGELOG.md.tests/test_unit.py (mirror test_validate_url_safe_accepts_public_srgssr_host).Network-Layer Egress (for future SSE/HTTP deployments): see docs/network-egress.md. For the current stdio transport, network-layer controls do not apply — the process runs in the MCP client's user context.
The server uses structured logging (OBS-003) via structlog with JSON output to stderr — keeping stdout clean for the stdio transport's JSON-RPC traffic.
Format:
timestamp on every recorddebug, info, notice, warning, error, critical, alert, emergencytool, business_unit, channel_id, query, etc.Example output:
Log levels (RFC 5424):
| Level | Used for |
|---|---|
debug | OAuth token cache hits, internal state |
info | Tool invocations, successful responses, server lifecycle |
warning | Recoverable conditions (rate-limit approaching, unsupported business unit) |
error | API failures, timeouts (recoverable) |
critical | Credential issues, service degradation |
Configuration:
The default level is info. Override via the SRGSSR_LOG_LEVEL environment variable (debug, info, warning, error, critical):
JSON output is aggregator-friendly — pipe stderr to Datadog, Splunk, Loki, etc., and filter by structured fields (tool, business_unit, level) without regex parsing.
See CHANGELOG.md
All data exposed by this server is fetched live from a single upstream
provider, SRG SSR Public API V2 (https://api.srgssr.ch). Every tool
return is a typed Pydantic BaseModel that
embeds source / license / provenance_url / fetched_at at the top
level — so downstream consumers can record the data origin without
round-tripping through this README. The SDK exposes the corresponding
outputSchema in the tools/list manifest so MCP clients can plan
follow-up calls precisely.
| Cluster | Provider | License | Notes |
|---|---|---|---|
| Weather | SRF Meteo (api.srgssr.ch) | SRG SSR Terms of Use | Geo-restricted to Switzerland |
| Video / Audio / EPG | SRF · RTS · RSI · RTR · SWI | SRG SSR Terms of Use | Metadata only — stream URLs are not redistributed |
| Polis (Votations / Elections) | SRG SSR Polis | SRG SSR Terms of Use | Historical data since 1900 |
Use of the SRG SSR APIs
This server's MIT license covers the source code only; it does not relicense the upstream data.
MIT License — see LICENSE
The SRG SSR APIs used in this project are subject to the SRG SSR Terms of Use.
Hayal Oezkan · github.com/malkreide
| Server | Description |
|---|---|
| zurich-opendata-mcp | City of Zurich open data (OSTLUFT air quality, weather, parking, geodata) |
| swiss-transport-mcp | Swiss public transport – OJP 2.0 journey planning, SIRI-SX disruptions |
| swiss-environment-mcp | BAFU environmental data – air quality, hydrology, natural hazards |
| swiss-statistics-mcp | BFS STAT-TAB – 682 statistical datasets |
| fedlex-mcp | Swiss federal law via Fedlex SPARQL |
Synergy example: "What were the results of the 2020 popular votes in Canton Zurich – and how did turnout compare to the national average?"
→ srgssr-mcp (Polis, cantonal results) + swiss-statistics-mcp (BFS, turnout data)
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):