Skip to main content

MCP server for SRG SSR public APIs โ€“ weather, TV/radio metadata, program guide & Swiss votations/elections since 1900

Project description

๐Ÿ‡จ๐Ÿ‡ญ Part of the Swiss Public Data MCP Portfolio

๐Ÿ“บ srgssr-mcp

Version License: MIT Python 3.11+ MCP CI Data Source

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).

๐Ÿ‡ฉ๐Ÿ‡ช Deutsche Version

Demo: Claude asks a question โ†’ srgssr-mcp tool call โ†’ grounded answer from SRG SSR Polis API


Overview

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.


Features

  • ๐ŸŒฆ๏ธ Weather โ€“ location search, current conditions, 24h hourly forecast, 7-day forecast (SRF Meteo)
  • ๐Ÿ“บ Video โ€“ TV show listings, latest episodes, live TV channels across all business units
  • ๐ŸŽ™๏ธ Audio โ€“ radio show listings, audio episodes, live radio stations
  • ๐Ÿ“… EPG โ€“ daily program schedule for any TV or radio channel
  • ๐Ÿ—ณ๏ธ Polis โ€“ popular votes and elections since 1900, national and cantonal results
  • ๐Ÿข Multi-unit โ€“ SRF (DE), RTS (FR), RSI (IT), RTR (RM), SWI (multilingual)
  • ๐Ÿ” OAuth2 โ€“ automatic token management with Client Credentials flow
  • โ˜๏ธ Dual transport โ€“ stdio for Claude Desktop, Streamable HTTP/SSE for cloud deployment

Prerequisites

  • Python 3.11+
  • API keys from developer.srgssr.ch (free registration):
    1. Create an account and log in
    2. Under "My Apps", create a new application
    3. Add the product SRG SSR PUBLIC API V2
    4. Note your Consumer Key and Consumer Secret

โš ๏ธ Terms of use: SRG SSR APIs are available for non-commercial use. For commercial use, contact api@srgssr.ch directly.


Installation

# Clone the repository
git clone https://github.com/malkreide/srgssr-mcp.git
cd srgssr-mcp

# Install
pip install -e .

Or with uvx (no permanent installation):

uvx srgssr-mcp

Or via pip:

pip install srgssr-mcp

Quickstart

# Set credentials
export SRGSSR_CONSUMER_KEY="your-consumer-key"
export SRGSSR_CONSUMER_SECRET="your-consumer-secret"

# Start the server (stdio mode for Claude Desktop)
srgssr-mcp

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?"


Configuration

Claude Desktop

Minimal (recommended):

{
  "mcpServers": {
    "srgssr": {
      "command": "uvx",
      "args": ["srgssr-mcp"],
      "env": {
        "SRGSSR_CONSUMER_KEY": "your-consumer-key",
        "SRGSSR_CONSUMER_SECRET": "your-consumer-secret"
      }
    }
  }
}

Config file locations:

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

After saving, restart Claude Desktop completely.

Other MCP Clients

Compatible with Cursor, Windsurf, VS Code + Continue, LibreChat, Cline, and self-hosted models via mcp-proxy. Set the same environment variables.

Cloud Deployment (SSE for browser access)

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

SRGSSR_CONSUMER_KEY=... \
SRGSSR_CONSUMER_SECRET=... \
SRGSSR_MCP_TRANSPORT=streamable-http \
SRGSSR_MCP_HOST=0.0.0.0 \
SRGSSR_MCP_PORT=8000 \
  python -m srgssr_mcp.server

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."


MCP Primitives

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.

Resources

URI template Description
epg://{bu}/{channel_id}/{date} Daily TV/radio program guide for SRF, RTS, RSI (e.g. epg://srf/srf1/2026-04-30)
votation://{votation_id} Detailed result of a closed Swiss popular vote (e.g. votation://v1)

Prompts

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

Available Tools

Tool Naming Convention

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).

๐ŸŒฆ๏ธ SRF Weather (4 tools)

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

๐Ÿ“บ Video (3 tools)

Tool Description Data Source
srgssr_video_get_shows List TV shows for a business unit 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

๐ŸŽ™๏ธ Audio (3 tools)

Tool Description Data Source
srgssr_audio_get_shows List radio shows for a business unit 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

๐Ÿ“… EPG โ€“ Electronic Program Guide (1 tool)

Tool Description Data Source
srgssr_epg_get_programs Daily program schedule for a TV or radio channel SRG SSR IL

๐Ÿ—ณ๏ธ Polis โ€“ Swiss Democracy (3 tools)

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

Supported Business Units

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

Example Use Cases

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_shows

โ†’ More use cases by audience โ†’


Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ Claude / LLMโ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”˜
       โ”‚ MCP (stdio)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ srgssr-mcp Server        โ”‚
โ”‚  โ”œโ”€ Weather Tools (4)    โ”‚
โ”‚  โ”œโ”€ EPG Tools (1)        โ”‚
โ”‚  โ”œโ”€ Polis Tools (3)      โ”‚
โ”‚  โ”œโ”€ Video Tools (3)      โ”‚
โ”‚  โ””โ”€ Audio Tools (3)      โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
       โ”‚ HTTPS (OAuth2)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚ SRG SSR Public APIs โ”‚
โ”‚  developer.srgssr.chโ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Data Sources

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.


Development Phase

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.

Phase 1 Completion Criteria

  • 14 read-only tools across five thematic clusters (Weather, Video, Audio, EPG, Polis)
  • OAuth2 Client Credentials authentication with token caching
  • Bilingual documentation (EN/DE)
  • Test suite (unit + live) โ€” see OPS-001
  • Structured logging โ€” see OBS-003 and CHANGELOG
  • Production-ready error handling (uniform retry/backoff, typed error envelopes)

Future Phases

  • Phase 2 (Write): Not planned. The SRG SSR Public APIs are read-only by contract; there is no upstream surface to write to.
  • Phase 3 (Multi-Agent): Evaluation deferred. Will be reconsidered once user feedback indicates concrete multi-agent workflows that this server should orchestrate (e.g. cross-server aggregation with swiss-statistics-mcp or swiss-transport-mcp).

MCP Protocol Version

This server is built and tested against MCP protocol version 2025-06-18.

The version is pinned explicitly as PROTOCOL_VERSION in src/srgssr_mcp/_app.py and validated at import time against the installed SDK's SUPPORTED_PROTOCOL_VERSIONS โ€” a fastmcp/mcp upgrade that drops support for the pinned revision will fail fast at startup instead of silently changing wire-level behaviour. Bumps are tracked in CHANGELOG.md under the matching release.

Update Policy

  • SDK dependency updates land via Dependabot (.github/dependabot.yml, monthly cadence, grouped under the mcp-sdk label) and run the full test suite before merge.
  • Spec bumps are evaluated on a feature branch against the relevant MCP SDK release; the official MCP changelog is the source of truth for breaking changes.
  • A spec-version bump is always documented in CHANGELOG.md and, if it changes the externally observable wire contract, triggers a minor or major release per Semantic Versioning.

Project Structure

srgssr-mcp/
โ”œโ”€โ”€ src/srgssr_mcp/
โ”‚   โ”œโ”€โ”€ __init__.py          # Package
โ”‚   โ””โ”€โ”€ server.py            # FastMCP server: 14 tools, OAuth2 client
โ”œโ”€โ”€ .github/
โ”‚   โ””โ”€โ”€ workflows/
โ”‚       โ””โ”€โ”€ ci.yml           # GitHub Actions CI (Python 3.11โ€“3.13)
โ”œโ”€โ”€ pyproject.toml           # Build configuration (hatchling)
โ”œโ”€โ”€ CHANGELOG.md
โ”œโ”€โ”€ CONTRIBUTING.md          # English
โ”œโ”€โ”€ CONTRIBUTING.de.md       # German
โ”œโ”€โ”€ SECURITY.md              # Security policy (English)
โ”œโ”€โ”€ SECURITY.de.md           # Security policy (German)
โ”œโ”€โ”€ LICENSE                  # MIT
โ”œโ”€โ”€ README.md                # This file (English)
โ””โ”€โ”€ README.de.md             # German version

๐Ÿ›ก๏ธ Safety & Limits

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

Known Limits

  • Rate Limits: SRG SSR APIs enforce rate limits โ€” see developer.srgssr.ch for details on the tier of your OAuth2 application
  • Data Freshness: EPG data may be delayed by up to 6 hours
  • Historical Data: Polis data goes back to 1900 โ€” older data is not available
  • Geo-Restriction: Some streaming APIs are only available within Switzerland
  • API keys required: SRG SSR APIs require free OAuth2 credentials from developer.srgssr.ch
  • Non-commercial use: SRG SSR API terms restrict commercial use without explicit permission from api@srgssr.ch
  • Weather coverage: SRF Meteo covers Switzerland only

Security

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.

Egress Allowlist

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:

  1. HTTPS-only โ€” http://, file://, ftp:// and other non-HTTPS schemes are rejected.
  2. Host allowlist โ€” the URL hostname must equal one of ALLOWED_HOSTS = {"api.srgssr.ch"} (exact match โ€” subdomain tricks like api.srgssr.ch.attacker.example are blocked).
  3. IP blocklist โ€” every resolved IP for the hostname is checked against private, loopback, link-local (incl. 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:

  1. Update ALLOWED_HOSTS in src/srgssr_mcp/_http.py.
  2. Document the reason in the PR and CHANGELOG.md.
  3. Add a positive test case in 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.


Logging

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:

  • JSON-encoded events, one per line
  • ISO 8601 UTC timestamp on every record
  • RFC 5424 severity levels: debug, info, notice, warning, error, critical, alert, emergency
  • Per-call bound context: tool, business_unit, channel_id, query, etc.

Example output:

{"event": "tool_invoked", "tool": "srgssr_weather_search_location", "query": "Bern", "level": "info", "logger": "mcp.srgssr.weather", "timestamp": "2026-04-30T14:23:45.123Z"}
{"event": "tool_succeeded", "tool": "srgssr_weather_search_location", "query": "Bern", "result_count": 3, "matched_variant": "Bern", "level": "info", "logger": "mcp.srgssr.weather", "timestamp": "2026-04-30T14:23:45.456Z"}

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):

SRGSSR_LOG_LEVEL=debug srgssr-mcp

JSON output is aggregator-friendly โ€” pipe stderr to Datadog, Splunk, Loki, etc., and filter by structured fields (tool, business_unit, level) without regex parsing.


Testing

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

# Integration tests (requires SRG SSR API keys)
PYTHONPATH=src pytest tests/ -m "live"

# Linting
ruff check src/

Contributing

See CONTRIBUTING.md (English) ยท CONTRIBUTING.de.md (German)


Changelog

See CHANGELOG.md


Data Sources & Licenses

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. FastMCP 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

  • Non-commercial use: free, no application required.
  • Commercial use: written permission required via api@srgssr.ch.

This server's MIT license covers the source code only; it does not relicense the upstream data.


License

MIT License โ€” see LICENSE

The SRG SSR APIs used in this project are subject to the SRG SSR Terms of Use.


Author

Hayal Oezkan ยท github.com/malkreide


Credits & Related Projects

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)

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

srgssr_mcp-1.0.3.tar.gz (165.3 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

srgssr_mcp-1.0.3-py3-none-any.whl (45.4 kB view details)

Uploaded Python 3

File details

Details for the file srgssr_mcp-1.0.3.tar.gz.

File metadata

  • Download URL: srgssr_mcp-1.0.3.tar.gz
  • Upload date:
  • Size: 165.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for srgssr_mcp-1.0.3.tar.gz
Algorithm Hash digest
SHA256 3fcc539f5f5585924118c8c2378d05ff4d0eac09173d4ad858d136457e4196fd
MD5 f14cb8b09db39f7b4bce9a52e362cf61
BLAKE2b-256 24344ae004e32ffb0a4606fb2ae434d00279335c21416185c6380583eba50851

See more details on using hashes here.

File details

Details for the file srgssr_mcp-1.0.3-py3-none-any.whl.

File metadata

  • Download URL: srgssr_mcp-1.0.3-py3-none-any.whl
  • Upload date:
  • Size: 45.4 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.14.0

File hashes

Hashes for srgssr_mcp-1.0.3-py3-none-any.whl
Algorithm Hash digest
SHA256 32f6a2f3553613fa5d1da7c9c4f637629762456d5b85c5f20a16ba538dd55416
MD5 cd19675150df87e91a822908e31dd16e
BLAKE2b-256 57e9e31bba44e904937a940a0855bd600605f44630489b56704e4bda01d1b258

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page