Back to Discover

srgssr-mcp

connector

malkreide

SRG SSR weather, video, audio, EPG, Polis

View on GitHub
0 starsSynced Aug 2, 2026

Install to Claude Code

/plugin marketplace add malkreide/srgssr-mcp

README

πŸ‡¨πŸ‡­ 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:

PrimitiveMental modelWhat's here
Tools (verbs)Executable functions / parametrized queries15 tools β€” search, list, fetch, aggregate
Resources (nouns)Cache-friendly passive data behind URIsEPG entries and immutable votation results
Prompts (recipes)Reusable workflow templatesVoting 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 templateDescription
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 unitTVRadio
SRFsrf-1, srf-2, srf-infosrf-1, srf-2, srf-2-kultur, srf-3, srf-4, srf-musikwelle, srf-virus
RTSrts-1, rts-2, rts-infoLA1ERE, ESPACE2, COULEUR3, OPTION_MUSIQUE
RSIla-1, la-2rete-uno, rete-due, rete-tre

Prompts

NameArgumentsPurpose
analyse_abstimmungsverhaltenvotation_id, focus (stadt_land / sprachregionen / kantone)Structured analysis of a Swiss popular vote
tagesbriefing_kantonlocation, channel_id, business_unit, dateDaily 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)

ToolDescriptionData Source
srgssr_weather_search_locationSearch for a location by name or postal code to obtain a geolocationIdSRF Meteo
srgssr_weather_currentCurrent weather conditions for a Swiss locationSRF Meteo
srgssr_weather_forecast_24hHourly 24-hour forecastSRF Meteo
srgssr_weather_forecast_7dayDaily 7-day forecastSRF Meteo

πŸ“Ί Video (3 tools)

ToolDescriptionData Source
srgssr_video_get_showsList 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_episodesRetrieve latest episodes of a showSRG SSR IL
srgssr_video_get_livestreamsList live TV channelsSRG SSR IL

πŸŽ™οΈ Audio (3 tools)

ToolDescriptionData Source
srgssr_audio_get_showsList radio shows for one radio channel (channel_id required β€” the v2 API has no per-unit listing)SRG SSR IL
srgssr_audio_get_episodesRetrieve audio episodes of a showSRG SSR IL
srgssr_audio_get_livestreamsList live radio stationsSRG SSR IL

πŸ“… EPG – Electronic Program Guide (1 tool)

ToolDescriptionData Source
srgssr_epg_get_programsDaily program schedule for a TV or radio channelSRG SSR IL

πŸ—³οΈ Polis – Swiss Democracy (3 tools)

ToolDescriptionData Source
srgssr_polis_get_votationsPopular votes since 1900 (national or cantonal)Polis API
srgssr_polis_get_votation_resultsDetailed results of a specific votePolis API
srgssr_polis_get_electionsElection results since 1900Polis API

Supported Business Units

CodeUnitLanguage
srfSRF (Schweizer Radio und Fernsehen)German
rtsRTS (Radio TΓ©lΓ©vision Suisse)French
rsiRSI (Radiotelevisione svizzera)Italian
rtrRTR (Radiotelevisiun Svizra Rumantscha)Romansh
swiSWI swissinfo.chMultilingual

Example Use Cases

QueryTool
"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 β†’


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

SourceDataAccess
developer.srgssr.chSRG 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: 15 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

AspectDetails
AccessRead-only β€” the server only reads from SRG SSR APIs and cannot post, modify or delete any content
Personal dataNo personal data β€” all endpoints serve public broadcast metadata, weather observations and historical votation/election results
Rate limitsSubject 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)
Timeout30 seconds per upstream API call
AuthenticationOAuth2 Client Credentials (free registration); secrets stay local, never logged
Licensing & useSRG SSR APIs are for non-commercial use; commercial use requires written permission from api@srgssr.ch
Terms of ServiceSubject 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

Contributing

See CONTRIBUTING.md (English) Β· CONTRIBUTING.de.md (German)


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

LevelUsed for
debugOAuth token cache hits, internal state
infoTool invocations, successful responses, server lifecycle
warningRecoverable conditions (rate-limit approaching, unsupported business unit)
errorAPI failures, timeouts (recoverable)
criticalCredential 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/

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.

ClusterProviderLicenseNotes
WeatherSRF Meteo (api.srgssr.ch)SRG SSR Terms of UseGeo-restricted to Switzerland
Video / Audio / EPGSRF Β· RTS Β· RSI Β· RTR Β· SWISRG SSR Terms of UseMetadata only β€” stream URLs are not redistributed
Polis (Votations / Elections)SRG SSR PolisSRG SSR Terms of UseHistorical 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

ServerDescription
zurich-opendata-mcpCity of Zurich open data (OSTLUFT air quality, weather, parking, geodata)
swiss-transport-mcpSwiss public transport – OJP 2.0 journey planning, SIRI-SX disruptions
swiss-environment-mcpBAFU environmental data – air quality, hydrology, natural hazards
swiss-statistics-mcpBFS STAT-TAB – 682 statistical datasets
fedlex-mcpSwiss 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)

Installation

Run via uv's uvx β€” no clone or manual install needed. Add to your MCP client config (mcpServers for Claude Desktop, Cursor and Windsurf; use a top-level servers key for VS Code in .vscode/mcp.json):

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

Rendered live from malkreide/srgssr-mcp's GitHub README β€” not stored, always reflects the source repo.

1 Install Method

NameDescriptionCategorySource
pypi packageInstall via pypi (stdio transport)mcp-serversrgssr-mcp

0 Comments

Login required
Log in to post a comment or update on this repo.

No comments yet β€” be the first to share an update.