swiss-democracy-mcp について
swiss-democracy-mcpは、研究者や公共データ分析者向けに、スイスの連邦国民投票、選挙、関連結果をMCPクライアントへ提供します。Swissvotes、BFS、SRGSSR Polisのデータを扱い、Polis以外の大半のツールは認証不要です。
主な機能
- 011848年以降の連邦国民投票検索
- 02政党の立場と州別結果の取得
- 03BFSの最新・過去の投票結果取得
- 04Polisの投票・選挙記録の照会
活用シーン
- 01投票の全国・州別結果の分析
- 02提案に対する政党の推奨意見の比較
- 03市町村単位の過去の投票や選挙の照会
MCP 対応
MCP サーバーとして、クライアントに読み取り専用ツールを公開し、リソースやプロンプトは提供しません。Swissvotes、BFS、SRGSSR Polisのデータを取得し、PolisのツールにはOAuth2認証情報が必要です。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
10掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| params | any | はい |
詳細
🗳️ swiss-democracy-mcp
🇨🇭 Swiss Public Data MCP Portfolio の一部 — AI モデルをスイスの公的機関のデータソースに接続します。
🌐 英語 | 🇩🇪 ドイツ語版
1848 年以降の連邦国民投票と、1900 年以降の選挙を網羅する、スイスの直接民主制データにアクセスできる MCP サーバーです。
デモクエリ
«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")
→ 対象別のその他のユースケース →
データソース
| ソース | 対象範囲 | 認証 |
|---|---|---|
| Swissvotes(ベルン大学) | 1848 年以降のすべての連邦投票 · 874 列 · 政党の立場 · 州別結果 | 不要 ✓ |
| BFS / opendata.swiss | リアルタイムおよびアーカイブ(1981 年以降) · 市町村レベル | 不要 ✓ |
| SRGSSR Polis | 1900 年以降の投票・選挙 · 市町村の詳細データ | OAuth2 キー |
ツール
フェーズ 1 — Swissvotes(認証不要)
| ツール | 説明 |
|---|---|
democracy_search_votes | キーワード、日付範囲、法形式、結果、政策分野で、1848 年以降のすべての連邦国民投票を検索します |
democracy_get_vote_detail | 特定の投票の詳細情報:正式名称、議会での立場、全国結果、署名 |
democracy_get_party_positions | 政党の推奨(FDP、SP、SVP、Die Mitte、GPS、GLP、…)と選挙運動資金データ |
democracy_get_cantonal_results | 26 州すべての結果:賛成率、投票率、可決フラグ |
democracy_list_vote_dates | 各日付の議案数とともに、すべての投票日を一覧表示します |
フェーズ 2 — BFS リアルタイム(認証不要)
| ツール | 説明 |
|---|---|
democracy_bfs_list_vote_dates | すべての BFS 投票日を一覧表示します(アーカイブ+現在) |
democracy_bfs_get_vote_results | 全国、州、または市町村レベルのリアルタイムまたはアーカイブ結果を取得します |
フェーズ 3 — SRGSSR Polis(API キーが必要)
| ツール | 説明 |
|---|---|
democracy_polis_list_votations | 1900 年以降の過去の投票と、市町村レベルのデータを一覧表示します |
democracy_polis_get_votation_detail | Polis の詳細情報を取得します。オプションですべての市町村の結果を含められます |
democracy_polis_list_elections | 1900 年以降の国民議会、全州議会、および州議会の選挙を一覧表示します |
インストール
Claude Desktop(stdio)
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"
}
}
}
}
SRGSSR_*変数は省略可能です。設定しなくても、Swissvotes と BFS のすべてのツールを引き続き完全に利用できます。認証情報が必要なのは Polis ツールのみです。
クラウド / 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 のデフォルト値は 127.0.0.1(ループバック)です。MCP_HOST=0.0.0.0 を設定するのは、サンドボックス化されたコンテナー/クラウド環境へのデプロイ時に限ります。ローカルマシンでは設定しないでください。設定すると、サーバーがネットワーク全体に公開されます。
アーキテクチャ
┌─────────────────────────────────────────────┐
│ 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 │ │
│ └─────────────────────────────────────┘ │
└─────────────────────────────────────────────┘
トランスポート: Claude Desktop では stdio、クラウド/Render.com では Streamable HTTP
認証パターン: 認証不要を優先 — Swissvotes と BFS は認証情報なしで動作します
キャッシュ: Swissvotes の CSV は起動時に一度読み込まれ、24 時間キャッシュされます
設定
すべての設定は環境変数で行います(.env.example を参照)。
| 変数 | デフォルト | 用途 |
|---|---|---|
MCP_TRANSPORT | stdio | stdio(ローカル)または streamable_http(クラウド) |
MCP_HOST | 127.0.0.1 | HTTP のバインドアドレス — コンテナ内のみ0.0.0.0 に設定してください |
MCP_PORT | 8000 | HTTP ポート |
LOG_LEVEL | INFO | 構造化 JSON ログは stderr に出力されます |
MCP_CORS_ORIGINS | — | HTTP トランスポートで許可する CORS オリジンをカンマ区切りで指定します。空の場合、ブラウザクライアントは許可されません。* を指定するとすべてのオリジンが許可され、警告がログに記録されます。stdio クライアントには影響しません |
MCP_ALLOWED_HOSTS | — | 受信 Host の許可リストをカンマ区切りで指定します。ループバック以外にバインドする場合のみ必要です |
SRGSSR_CONSUMER_KEY / SRGSSR_CONSUMER_SECRET | — | 任意。democracy_polis_* ツールでのみ使用します |
シークレットは SecretStr として保持され、ログに記録されることはありません。docs/secret-management.md と docs/security.md を参照してください。
MCP プリミティブ
このサーバーが公開するのは意図的にツールのみです(リソースやプロンプトはありません)。これはフェーズ 1 の読み取り専用データラッパーです(docs/roadmap.md を参照)。ツールの範囲は小さく(ユースケース指向のツール 10 個)、すべての応答には出典情報が含まれます。リソース(例:vote://{anr})は、URI スキームが安定した後のフェーズで導入する候補です。
MCP プロトコルバージョン
このサーバーは、同じエンドポイント上で2 つのプロトコル世代に対応しています。接続時のクライアントの最初のリクエストによって、どちらを適用するかが決まります。以降、もう一方の世代を使う要求は拒否されます。
| 世代 | リビジョン | 利用するクライアント |
|---|---|---|
initialize ハンドシェイク | 2024-11-05 … 2025-11-25 | 現在のクライアントが使用するリビジョンです。サーバーは要求されたリビジョンで応答します。ただし、リクエストがそれより新しいリビジョンを要求した場合は、上限の 2025-11-25 で応答します。 |
| リクエストごとのエンベロープ | 2026-07-28 | 2026-07-28 の _meta エンベロープを含むリクエストによって、モダン接続が開始されます。 |
両方のリビジョンは tests/test_protocol_version.py で固定され、インストール済み SDK に対して検証されます。これにより、Dependabot による mcp の更新で、どちらかのリビジョンが気付かないうちに変わることはありません。さらに、tests/test_server_identity.py では、組み立て済みの ASGI アプリに実際のリクエストを送信します。リクエストごとのエンベロープにはツール一覧が応答され、モダンリビジョンを提示する initialize に対しても、ハンドシェイクの上限が返されます。定数が示すのは SDK が認識するリビジョンであり、実測値が示すのはこのサーバーが対応するリビジョンです。
サーバーの識別情報。 ハンドシェイク世代では、serverInfo は initialize の応答で一度だけ指定されます。モダン世代にはハンドシェイクがなく、代わりにすべての応答に _meta["io.modelcontextprotocol/serverInfo"] として識別情報が付与されます。Implementation.version は必須のスキーマフィールドです。コンストラクターで省略すると SDK が "" を事前入力するため、バージョンが未設定でも欠落ではなく、通信上の値となります。そして、テストスイートがすべて成功していても、それを見落とすことがあります。このサーバーは配布バージョンを明示的に渡します。test_server_identity.py では、MCPServer をそのまま使うケースを負の対照として、両方の通信方式でバージョンを実測します。
SDK の LATEST_PROTOCOL_VERSION はハンドシェイク世代ではなくモダン世代の別名です。これだけを基準に固定すると、現在のクライアントが実際にネゴシエーションする世代が、変更されても検知されない状態になります。
更新ポリシー。 ゲートに失敗した場合、定数をむやみに編集しないでください。2 つのリビジョン間の仕様変更履歴を読み、サーバーが引き続き正しく動作することを確認したうえで、定数、このセクション、README.de.md、CHANGELOG.md をまとめて更新してください。
ポートフォリオの連携
Swiss Public Data MCP ポートフォリオの他のサーバーと組み合わせられます。
- zurich-opendata-mcp — チューリッヒ市レベルの統計を投票分析に追加します
- swiss-statistics-mcp — カントン別の BFS 人口統計データで情報を充実させます
- srgssr-mcp — SRF ニュースアーカイブのコンテンツを特定の投票日に関連付けます
複数サーバーを使ったクエリの例:
«Vergleiche die Abstimmungsresultate zur AHV-Reform mit der Altersstruktur der Kantone»
→ swiss-democracy-mcp + swiss-statistics-mcp
安全性と制限
- 読み取り専用: すべてのツールは HTTP GET リクエストのみを実行します。上流でデータが書き込まれたり、変更されたり、削除されたりすることはありません。
- 送信先許可リスト(SSRF 保護): 外部へのリクエストは、信頼できるホスト(
swissvotes.ch、opendata.swiss、*.bfs.admin.ch、api.srgssr.ch)の固定許可リストに制限され、HTTPS のみを使用します。呼び出し元が指定した URL(BFS のresult_url)は、さらに名前解決され、プライベート、ループバック、またはクラウドメタデータの IP 範囲を指している場合は拒否されます。 - 個人データなし: Swissvotes、BFS、SRGSSR Polis が公開するのは、集計された民主主義関連データ(投票結果、政党の立場、カントン/自治体別の集計)です。このサーバーが個人を特定できる情報(PII)を処理または保存することはありません。
- レート制限: Swissvotes は単一の CSV ファイルで、24 時間に 1 回ダウンロードされ、メモリ内にキャッシュされます。BFS/opendata.swiss と SRGSSR Polis は、文書化されたレート制限のない公開 API です。
limitと日付範囲は控えめに設定してください。サーバーはリクエストごとに 30 秒のタイムアウトを適用します。 - データの鮮度: BFS のリアルタイム結果は、クエリ時点の上流フィードを反映します(ローカルキャッシュなし)。Swissvotes は Uni Bern のミラーから 24 時間ごとに更新されます。
- 利用規約: データには各ソースの利用規約が適用されます。swissvotes.ch(CC BY 4.0、Uni Bern)、opendata.swiss(大半は CC-BY/Open by Default)、SRGSSR Polis(無料プラン、非商用利用のみ)。下流の製品では、必ず上流のソースを明記してください。
- 保証なし: このサーバーはコミュニティプロジェクトであり、ベルン大学、連邦統計局、SRG SSR とは提携していません。利用可能性は上流 API に依存します。
既知の制限事項
- Swissvotes の対象範囲: カントンレベルの結果は 1848 年以降利用できます。自治体レベルの結果は SRGSSR Polis 経由でのみ利用でき、時期は投票によって異なります(およそ 1990 年代以降)。
- BFS アーカイブ: リアルタイムサービスが対象とするのは、1981 年以降の連邦投票のみです。
- Polis ツール: developer.srgssr.ch での無料登録が必要です。非商用利用のみです。
- CSV キャッシュ: Swissvotes のデータセットは数 MB 程度で、24 時間メモリ内にキャッシュされます。そのため、API のみを使うサーバーよりもメモリ使用量が多くなります。
テスト
# 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
テストデータの出典
tests/fixtures/ 内のフィクスチャは、稼働中のソースから記録されたもので、日付が付されています。
各ファイルの出典、取得日、選択ルール、SHA-256 については、tests/fixtures/PROVENANCE.md を参照してください。
python scripts/record_fixtures.py # re-record
ここで重要なのは選択ルールです。 Swissvotes のデータセットには 714 行、874 列があり、記録された行は位置ではなく、プロパティに基づいて選択されています。「先頭から N 行」では、フィクスチャが必要とするセルそのものが除外されてしまいます。つまり、714 件の投票のうち 667 件に含まれるプレースホルダー 9999(「情報なし」)と .(「該当なし」)です。これらを含まないフィクスチャは一見きれいに見えますが、何も証明しません。だからこそ、ツールがこれらを値としてそのまま渡していたことに誰も気づきませんでした。
バイトオーダーマークも、ソースに含まれておりサーバーが明示的に削除するため、ファイルに残しています。これがなければ、削除が必要であることをフィクスチャで示せません。
SRGSSR Polis には OAuth 認証情報が必要です。日付をでっち上げて記載する代わりに、PROVENANCE.md では NOT RECORDED に分類しています。
コントリビューション
CONTRIBUTING.md(🇩🇪 Deutsch)をご覧ください。
セキュリティ
セキュリティへの取り組みと脆弱性の報告方法については、SECURITY.md(🇩🇪 Deutsch)をご覧ください。
ライセンス
MIT — LICENSEをご覧ください。
データライセンス:
- Swissvotes:Creative Commons BY 4.0
- BFS / opendata.swiss:Open use
- SRGSSR Polis:非商用利用のみ — developer.srgssr.chをご覧ください。
作者
Hayal Oezkan · github.com/malkreide
インストール
uv の uvx で実行できます。リポジトリのクローンや手動でのインストールは不要です。MCP クライアントの設定に追加してください(Claude Desktop、Cursor、Windsurf では mcpServers を使用し、VS Code では .vscode/mcp.json の最上位にある servers キーを使用します)。
{
"mcpServers": {
"swiss-democracy-mcp": {
"command": "uvx",
"args": [
"swiss-democracy-mcp"
]
}
}
}
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。