Skip to main content

๐Ÿ—ณ๏ธ swiss-democracy-mcp

CI PyPI Python License: MIT MCP Swiss Public Data MCP

๐Ÿ‡จ๐Ÿ‡ญ Part of the Swiss Public Data MCP Portfolio โ€” connecting AI models to Swiss institutional data sources.

๐ŸŒ English | ๐Ÿ‡ฉ๐Ÿ‡ช Deutsche Version

An MCP server providing access to Swiss direct democracy data, covering all federal popular votes since 1848 and elections since 1900.

Demo: Claude using democracy_search_votes, democracy_get_cantonal_results and democracy_get_party_positions


Demo Query

ยซWie hat der Kanton Zรผrich bei der AHV 21 Initiative 2022 abgestimmt,
 und welche Parteien unterstรผtzten die Vorlage?ยป

โ†’ democracy_search_votes(keyword="AHV 21", year_from=2022)
โ†’ democracy_get_cantonal_results(vote_number="551")
โ†’ democracy_get_party_positions(vote_number="551") โ†’ More use cases by audience โ†’


Data Sources

Source Coverage Auth
Swissvotes (Uni Bern) All federal votes since 1848 ยท 874 columns ยท party positions ยท cantonal results None โœ“
BFS / opendata.swiss Real-time & archive (since 1981) ยท municipality level None โœ“
SRGSSR Polis Votes & elections since 1900 ยท municipality detail OAuth2 key

Tools

Phase 1 โ€” Swissvotes (No Auth Required)

Tool Description
democracy_search_votes Search all federal popular votes since 1848 by keyword, date range, legal form, outcome, policy domain
democracy_get_vote_detail Full details for a specific vote: official title, parliamentary positions, national result, signatures
democracy_get_party_positions Party recommendations (FDP, SP, SVP, Die Mitte, GPS, GLP, โ€ฆ) with campaign finance data
democracy_get_cantonal_results Results for all 26 cantons: yes%, turnout, accepted flag
democracy_list_vote_dates List all voting dates with number of proposals per date

Phase 2 โ€” BFS Real-Time (No Auth Required)

Tool Description
democracy_bfs_list_vote_dates List all BFS voting dates (archive + current)
democracy_bfs_get_vote_results Real-time or archived results at national, cantonal, or municipality level

Phase 3 โ€” SRGSSR Polis (API Key Required)

Tool Description
democracy_polis_list_votations Historical votations since 1900 with municipality-level data
democracy_polis_get_votation_detail Full Polis detail, optionally with all municipality results
democracy_polis_list_elections National Council, Council of States, and cantonal elections since 1900

Installation

Claude Desktop (stdio)

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "swiss-democracy": {
      "command": "uvx",
      "args": ["swiss-democracy-mcp"],
      "env": {
        "SRGSSR_CONSUMER_KEY": "your_key_here",
        "SRGSSR_CONSUMER_SECRET": "your_secret_here"
      }
    }
  }
}

The SRGSSR_* variables are optional. Without them, all Swissvotes and BFS tools remain fully functional. Only the Polis tools require credentials.

Cloud / Render.com (Streamable HTTP)

pip install swiss-democracy-mcp
# Bind to all interfaces ONLY inside a container/cloud environment:
MCP_TRANSPORT=streamable_http MCP_HOST=0.0.0.0 MCP_PORT=8000 python -m swiss_democracy_mcp.server

MCP_HOST defaults to 127.0.0.1 (loopback). Set MCP_HOST=0.0.0.0 only inside a sandboxed container/cloud deployment โ€” never on a local machine, where it would expose the server to your whole network.


Architecture

โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚              Claude / LLM Host              โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜
               โ”‚ MCP (stdio / Streamable HTTP)
โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”
โ”‚         swiss-democracy-mcp                 โ”‚
โ”‚                                             โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  Swissvotes CSV Cache (24h TTL)     โ”‚   โ”‚
โ”‚  โ”‚  All 874 columns, since 1848        โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                 โ”‚                           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  BFS / opendata.swiss (no auth)     โ”‚   โ”‚
โ”‚  โ”‚  Real-time & archive since 1981     โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”ฌโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ”‚                 โ”‚                           โ”‚
โ”‚  โ”Œโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ–ผโ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”   โ”‚
โ”‚  โ”‚  SRGSSR Polis (OAuth2, optional)    โ”‚   โ”‚
โ”‚  โ”‚  Votes & elections since 1900       โ”‚   โ”‚
โ”‚  โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜   โ”‚
โ””โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”€โ”˜

Transport: stdio for Claude Desktop ยท Streamable HTTP for cloud/Render.com
Auth pattern: No-Auth-First โ€” Swissvotes & BFS work without any credentials
Cache: Swissvotes CSV is loaded once at startup and cached for 24 hours


Configuration

All configuration is via environment variables (see .env.example):

Variable Default Purpose
MCP_TRANSPORT stdio stdio (local) or streamable_http (cloud)
MCP_HOST 127.0.0.1 HTTP bind address โ€” set 0.0.0.0 only in a container
MCP_PORT 8000 HTTP port
LOG_LEVEL INFO structured JSON logs go to stderr
SRGSSR_CONSUMER_KEY / SRGSSR_CONSUMER_SECRET โ€” optional, only for democracy_polis_* tools

Secrets are held as SecretStr and never logged. See docs/secret-management.md and docs/security.md.

MCP Primitives

This server intentionally exposes Tools only (no Resources or Prompts). It is a Phase-1 read-only data wrapper (see docs/roadmap.md); the tool surface is small (10 use-case-oriented tools) and every response is self-contained with source provenance. Resources (e.g. vote://{anr}) are a candidate for a later phase once the URI scheme stabilises.

MCP Protocol Version

The protocol version is the one negotiated by mcp[cli]>=1.6.0 (FastMCP). SDK updates are tracked monthly via Dependabot; protocol bumps are recorded in CHANGELOG.md.


Portfolio Synergy

Combine with other servers in the Swiss Public Data MCP portfolio:

Example multi-server query:
ยซVergleiche die Abstimmungsresultate zur AHV-Reform mit der Altersstruktur der Kantoneยป
โ†’ swiss-democracy-mcp + swiss-statistics-mcp


Safety & Limits

  • Read-only: All tools perform HTTP GET requests only โ€” no data is written, modified, or deleted upstream.
  • Egress allow-list (SSRF protection): Outbound requests are restricted to a fixed allow-list of trusted hosts (swissvotes.ch, opendata.swiss, *.bfs.admin.ch, api.srgssr.ch), HTTPS only. Caller-supplied URLs (the BFS result_url) are additionally resolved and rejected if they point at private, loopback or cloud-metadata IP ranges.
  • No personal data: Swissvotes, BFS and SRGSSR Polis expose aggregate democratic data (vote results, party positions, cantonal/municipality tallies). No personally identifiable information (PII) is processed or stored by this server.
  • Rate limits: Swissvotes is a single CSV downloaded once per 24h and cached in memory. BFS / opendata.swiss and SRGSSR Polis are public APIs without documented rate limits โ€” keep limit and date ranges conservative. The server enforces a 30s timeout per request.
  • Data freshness: Real-time BFS results reflect the upstream feed at query time (no local caching). Swissvotes is refreshed every 24h from the Uni Bern mirror.
  • Terms of service: Data is subject to the ToS of each source โ€” swissvotes.ch (CC BY 4.0, Uni Bern), opendata.swiss (mostly CC-BY / Open by Default), SRGSSR Polis (free tier, non-commercial use only). Always cite the upstream source in downstream products.
  • No guarantees: This server is a community project, not affiliated with the University of Bern, the Federal Statistical Office, or SRG SSR. Availability depends on upstream APIs.

Known Limitations

  • Swissvotes coverage: Cantonal-level results are available since 1848; municipality-level results only via SRGSSR Polis (since ~1990s depending on the vote).
  • BFS archive: Real-time service covers federal votes since 1981 only.
  • Polis tools: Require free registration at developer.srgssr.ch. Non-commercial use only.
  • CSV cache: The Swissvotes dataset is ~several MB and is cached in memory for 24 hours. Memory footprint is accordingly higher than API-only servers.

Testing

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

# Live tests (require network access)
PYTHONPATH=src pytest tests/ -m "live" -v

Contributing

See CONTRIBUTING.md (๐Ÿ‡ฉ๐Ÿ‡ช Deutsch).


Security

See SECURITY.md (๐Ÿ‡ฉ๐Ÿ‡ช Deutsch) for the security posture and vulnerability reporting.


License

MIT โ€” see LICENSE.

Data licenses:


Author

Hayal Oezkan ยท github.com/malkreide

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": {
    "swiss-democracy-mcp": {
      "command": "uvx",
      "args": [
        "swiss-democracy-mcp"
      ]
    }
  }
}

Download files

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

Source Distribution

swiss_democracy_mcp-0.2.4.tar.gz (86.2 kB view details)

Uploaded Source

Built Distribution

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

swiss_democracy_mcp-0.2.4-py3-none-any.whl (23.7 kB view details)

Uploaded Python 3

File details

Details for the file swiss_democracy_mcp-0.2.4.tar.gz.

File metadata

  • Download URL: swiss_democracy_mcp-0.2.4.tar.gz
  • Upload date:
  • Size: 86.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for swiss_democracy_mcp-0.2.4.tar.gz
Algorithm Hash digest
SHA256 220e1f4cc2e09c288356b67c6656c6d9a05fe9b986809f48405d57906cc724cb
MD5 3a47b0e4493dfd10126b19ab81706fc5
BLAKE2b-256 ae6be891cb964e5ab7c16d54a31fd6e40ece09edd7150e5a741218a6c5c055e2

See more details on using hashes here.

Provenance

The following attestation bundles were made for swiss_democracy_mcp-0.2.4.tar.gz:

Publisher: publish.yml on malkreide/swiss-democracy-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file swiss_democracy_mcp-0.2.4-py3-none-any.whl.

File metadata

File hashes

Hashes for swiss_democracy_mcp-0.2.4-py3-none-any.whl
Algorithm Hash digest
SHA256 b3af7ee45906cf2827d3df42388cebbb443cb1d454c958ea7963661312a84c3b
MD5 39c5a18e421b31651d707371c5d2158f
BLAKE2b-256 84f52c806bba779dbd7de2946a41dcb271f2a5f459b77e2062e6cf4ab0f560ab

See more details on using hashes here.

Provenance

The following attestation bundles were made for swiss_democracy_mcp-0.2.4-py3-none-any.whl:

Publisher: publish.yml on malkreide/swiss-democracy-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

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