Skip to main content
ClaudeWave
malkreide avatar
malkreide

swiss-democracy-mcp

View on GitHub

MCP server for Swiss direct democracy: Swissvotes (1848+), BFS opendata.swiss, SRGSSR Polis (1900+)

MCP ServersOfficial Registry2 stars0 forks● PythonMITUpdated today
ClaudeWave Trust Score
95/100
✓ Verified
Passed
  • ✓Open-source license (MIT)
  • ✓Actively maintained (<30d)
  • ✓Clear description
  • ✓Topics declared
  • ✓Documented (README)
Last scanned: 9/26/2026
Install in Claude Code / Claude Desktop
Method: pip / Python · swiss-democracy-mcp
Claude Code CLI
claude mcp add swiss-democracy-mcp -- python -m swiss-democracy-mcp
claude_desktop_config.json (Claude Desktop)
{
  "mcpServers": {
    "swiss-democracy-mcp": {
      "command": "python",
      "args": ["-m", "swiss_democracy_mcp.server"],
      "env": {
        "MCP_HOST": "<mcp_host>"
      }
    }
  }
}
1. Run the command above in your terminal (Claude Code), or paste the JSON config into claude_desktop_config.json (Claude Desktop).
2. Replace any <placeholder> values with your API keys or paths.
3. Restart Claude. The MCP server and its tools appear automatically.
💡 Install first: pip install swiss-democracy-mcp
Detected environment variables
MCP_HOST
Use cases

MCP Servers overview

# 🗳️ swiss-democracy-mcp

[![CI](https://github.com/malkreide/swiss-democracy-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/malkreide/swiss-democracy-mcp/actions/workflows/ci.yml)
[![PyPI](https://img.shields.io/pypi/v/swiss-democracy-mcp.svg)](https://pypi.org/project/swiss-democracy-mcp/)
[![Python](https://img.shields.io/pypi/pyversions/swiss-democracy-mcp.svg)](https://pypi.org/project/swiss-democracy-mcp/)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
[![MCP](https://img.shields.io/badge/MCP-Model%20Context%20Protocol-purple)](https://modelcontextprotocol.io/)
[![Swiss Public Data MCP](https://img.shields.io/badge/portfolio-swiss--public--data--mcp-blue)](https://github.com/malkreide/swiss-public-data-mcp)

> 🇨🇭 **Part of the [Swiss Public Data MCP Portfolio](https://github.com/malkreide/swiss-public-data-mcp)** — connecting AI models to Swiss institutional data sources.

🌐 **English** | **[🇩🇪 Deutsche Version](README.de.md)**

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](docs/assets/demo.svg)

---

## 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 →](EXAMPLES.md)

---

## Data Sources

| Source | Coverage | Auth |
|---|---|---|
| **[Swissvotes](https://swissvotes.ch)** (Uni Bern) | All federal votes since 1848 · 874 columns · party positions · cantonal results | None ✓ |
| **[BFS / opendata.swiss](https://opendata.swiss/de/dataset/echtzeitdaten-am-abstimmungstag-zu-eidgenoessischen-abstimmungsvorlagen)** | Real-time & archive (since 1981) · municipality level | None ✓ |
| **[SRGSSR Polis](https://developer.srgssr.ch/api-catalog/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`:

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

```bash
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`](.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** |
| `MCP_CORS_ORIGINS` | — | comma-separated CORS allow-origins for the HTTP transport. **Empty means no browser client is permitted**; `*` allows any origin and is logged as a warning. stdio clients are unaffected |
| `MCP_ALLOWED_HOSTS` | — | comma-separated inbound `Host` allow-list. Only needed for a non-loopback bind |
| `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](docs/secret-management.md) and
[docs/security.md](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](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

This server speaks **two protocol eras** over the same endpoint. The client's
first request on a connection decides which one applies; a later claim from the
other era is refused.

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

Both revisions are pinned in
[`tests/test_protocol_version.py`](tests/test_protocol_version.py) and asserted
against the installed SDK, so a Dependabot bump of `mcp` cannot move either one
silently. Next to them,
[`tests/test_server_identity.py`](tests/test_server_identity.py) sends real
requests through the assembled ASGI app: a per-request envelope is answered
with the tool list, and an `initialize` that offers the modern revision still
gets the handshake ceiling back. The constants say which revisions the SDK
knows; the measurement says which ones this server serves.

**Server identity.** Under the handshake era `serverInfo` is named once, in the
`initialize` reply. The modern era has no handshake and stamps the identity
onto **every** response instead, as
`_meta["io.modelcontextprotocol/serverInfo"]`. `Implementation.version` is a
required schema field that the SDK pre-fills with `""` when the constructor
omits it, so an unset version is not a gap but a value on the wire — and one
that a green test suite will not show you. This server passes its distribution
version explicitly; `test_server_identity.py` measures it on both wires, with a
bare `MCPServer` as the negative control.

Note that the SDK's `LATEST_PROTOCOL_VERSION` is an alias for the **modern**
era, not for the handshake era — pinning against it alone would leave the era
that current clients actually negotiate free to drift.

**Update policy.** When the gate fails, do not edit the constant blindly: read
the spec changelog between the two revisions, verify the server still behaves,
then move the constant, this section, `README.de.md` and
[`CHANGELOG.md`](CHANGELOG.md) together.

---

## Portfolio Synergy

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

- **[zurich-opendata-mcp](https://github.com/malkreide/zurich-opendata-mcp)** — add Zurich city-level statistics to vote analysis
- **[swiss-statistics-mcp](https://github.com/malkreide/swiss-statistics-mcp)** — enrich with BFS demographic data by canton
- **[srgssr-mcp](https://github.com/malkreide/srgssr-mcp)** — link SRF news archive content to specific vote dates

Example multi-server query:  
*«Vergleiche die Ab
democracymcpmodel-context-protocolopen-datapythonswiss-open-dataswiss-public-data-mcpswissvotesswitzerlandvolksabstimmung

What people ask about swiss-democracy-mcp

What is malkreide/swiss-democracy-mcp?

+

malkreide/swiss-democracy-mcp is mcp servers for the Claude AI ecosystem. MCP server for Swiss direct democracy: Swissvotes (1848+), BFS opendata.swiss, SRGSSR Polis (1900+) It has 2 GitHub stars and its last recorded update is dated 2026-09-26.

How do I install swiss-democracy-mcp?

+

You can install swiss-democracy-mcp by cloning the repository (https://github.com/malkreide/swiss-democracy-mcp) or following the README instructions on GitHub. ClaudeWave also provides quick install blocks on this page.

Is malkreide/swiss-democracy-mcp safe to use?

+

Our security agent has analyzed malkreide/swiss-democracy-mcp and assigned a Trust Score of 95/100 (tier: Verified). See the full breakdown of passed checks and flags on this page.

Who maintains malkreide/swiss-democracy-mcp?

+

malkreide/swiss-democracy-mcp is maintained by malkreide. The last recorded GitHub activity is dated 2026-09-26, with 0 open issues.

Are there alternatives to swiss-democracy-mcp?

+

Yes. On ClaudeWave you can browse similar mcp servers at /categories/mcp, sorted by popularity or recent activity.

Deploy swiss-democracy-mcp to your cloud

Ship this repo to production in minutes. Each platform spins up its own environment with editable env vars.

Maintain this repo? Add a badge to your README

Drop the badge into your GitHub README to show it's tracked on ClaudeWave. Each badge links back to this page and reflects the live Trust Score.

Featured on ClaudeWave: malkreide/swiss-democracy-mcp
[![Featured on ClaudeWave](https://claudewave.com/api/badge/malkreide-swiss-democracy-mcp)](https://claudewave.com/repo/malkreide-swiss-democracy-mcp)
<a href="https://claudewave.com/repo/malkreide-swiss-democracy-mcp"><img src="https://claudewave.com/api/badge/malkreide-swiss-democracy-mcp" alt="Featured on ClaudeWave: malkreide/swiss-democracy-mcp" width="320" height="64" /></a>

More MCP Servers

swiss-democracy-mcp alternatives