{"id":51158656,"url":"https://github.com/malkreide/lobbywatch-mcp","last_synced_at":"2026-06-26T12:02:07.111Z","repository":{"id":356734652,"uuid":"1217155699","full_name":"malkreide/lobbywatch-mcp","owner":"malkreide","description":"MCP server for the Lobbywatch.ch lobby database — Swiss parliamentarians' conflicts of interest","archived":false,"fork":false,"pushed_at":"2026-06-07T06:29:26.000Z","size":150,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-07T07:11:55.177Z","etag":null,"topics":["llm","lobbywatch","mcp","model-context-protocol","parlament","python","swiss-open-data","swiss-public-data-mcp","transparency"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/malkreide.png","metadata":{"files":{"readme":"README.de.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":"audits/2026-05-09T115855-Z-lobbywatch-mcp/applicability.json","citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-21T15:46:50.000Z","updated_at":"2026-06-07T06:29:28.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/malkreide/lobbywatch-mcp","commit_stats":null,"previous_names":["malkreide/lobbywatch-mcp"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/malkreide/lobbywatch-mcp","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malkreide%2Flobbywatch-mcp","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malkreide%2Flobbywatch-mcp/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malkreide%2Flobbywatch-mcp/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malkreide%2Flobbywatch-mcp/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/malkreide","download_url":"https://codeload.github.com/malkreide/lobbywatch-mcp/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/malkreide%2Flobbywatch-mcp/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34815669,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-26T02:00:06.560Z","response_time":106,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["llm","lobbywatch","mcp","model-context-protocol","parlament","python","swiss-open-data","swiss-public-data-mcp","transparency"],"created_at":"2026-06-26T12:02:05.640Z","updated_at":"2026-06-26T12:02:07.099Z","avatar_url":"https://github.com/malkreide.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# 🏛️ lobbywatch-mcp\n\n[![CI](https://github.com/malkreide/lobbywatch-mcp/actions/workflows/ci.yml/badge.svg)](https://github.com/malkreide/lobbywatch-mcp/actions/workflows/ci.yml)\n[![PyPI version](https://badge.fury.io/py/lobbywatch-mcp.svg)](https://badge.fury.io/py/lobbywatch-mcp)\n[![Python](https://img.shields.io/badge/python-3.11%2B-blue)](https://www.python.org)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Data: CC BY-SA 4.0](https://img.shields.io/badge/Data-CC%20BY--SA%204.0-lightgrey.svg)](https://creativecommons.org/licenses/by-sa/4.0/)\n[![Swiss Public Data MCP Portfolio](https://img.shields.io/badge/Portfolio-Swiss%20Public%20Data%20MCP-blue)](https://github.com/malkreide)\n\n\u003e Ein MCP-Server, der KI-Modelle mit **Lobbywatch.ch** verbindet — der grössten öffentlichen Datenbank zu Interessenbindungen im Schweizer Bundesparlament.\n\n[🇬🇧 English version](README.md)\n\n\u003e **Teil des [Swiss Public Data MCP Portfolios](https://github.com/malkreide)** — KI-Modelle an Schweizer Public-Data-Quellen anbinden.\n\n---\n\n## 🎯 Anchor-Demo-Query\n\n\u003e *«Welche Mitglieder der WBK-N haben Interessenbindungen zu Bildungsverlagen oder privaten Bildungsträgern, und wie ist ihre Transparenz-Bewertung?»*\n\n[→ Weitere Anwendungsbeispiele nach Zielgruppe →](EXAMPLES.md)\n\n---\n\n## Übersicht\n\nLobbywatch.ch betreibt die grösste öffentliche Datenbank zu Schweizer Parlamentarier:innen und deren Verbindungen zu Lobbyorganisationen: 245 Parlamentarier:innen, rund 7'800 Interessenbindungen, 139 Lobbygruppen, 368 Zutrittsberechtigte, wöchentlich aktualisiert, lizenziert unter CC BY-SA 4.0.\n\n`lobbywatch-mcp` stellt diese Daten per Model Context Protocol für Large Language Models bereit. Der Server ist komplementär zu [`parlament-mcp`](https://github.com/malkreide/parlament-mcp) (offizielle Curia-Vista-Daten) konzipiert: Die Kombination beantwortet *was* eine Person offiziell tut **und** *mit wem* sie verbunden ist — in derselben Konversation.\n\n## Funktionen\n\n- **Dump-first, API-Fallback.** Der wöchentliche JSON-Export ist die Primärquelle (stabil, live verifiziert); die `dataIF` REST-API wird nur dort genutzt, wo sie zuverlässig liefert (Lobbygruppen, Suche).\n- **Sieben Tools in Phase 1** — Profilabfrage, Interessenbindungen, Branchen-Suche, Lobbygruppen, Rankings, Transparenzquote, Cache-Steuerung.\n- **CC-BY-SA-4.0-Namensnennung** wird über Pydantic-Envelopes in jeder Antwort automatisch mitgeliefert.\n- **Duales Transportprotokoll** — `stdio` für Claude Desktop, `streamable-http` / `sse` für Cloud-Deployments.\n- **Unscharfe Namenssuche** (rapidfuzz) für LLM-typische Eingaben wie «Jositsch» oder «Wehrli».\n- **Keine Authentifizierung nötig** (Phase 1 — No-Auth-First).\n\n## Architektur\n\n```\n                    ┌─────────────────────────────┐\n   LLM-Client       │     LobbywatchClient        │\n  (Claude Desktop,  │                             │\n   Inspector, …)    │   ┌───────────────────┐     │\n        │           │   │  Dump-Cache       │     │      cms.lobbywatch.ch\n        │  MCP      │   │  (24 h TTL,       │     │      ┌──────────────────┐\n        ▼  stdio /  │   │   ~80 MB resident)├─────┼─────►│ wöchentlicher    │\n   ┌─────────┐ HTTP │   └───────────────────┘     │      │ JSON-Export      │\n   │ FastMCP │◄────►│                             │      │ (~17 MB)         │\n   │ Server  │      │   ┌───────────────────┐     │      └──────────────────┘\n   └─────────┘      │   │  dataIF REST      ├─────┼─────►┌──────────────────┐\n                    │   │  (Live-Fallback)  │     │      │ /interface/v1/   │\n                    │   └───────────────────┘     │      │   json/…         │\n                    └─────────────────────────────┘      └──────────────────┘\n```\n\nAusgehender HTTP-Verkehr läuft über einen einzigen `httpx.AsyncClient` mit `follow_redirects=False`, einem SSRF-Guard der RFC1918-, Link-local- und Metadata-IPs blockiert, und einem httpx-Event-Hook, der bei jedem Request erneut auflöst. Die Dump-Pfade sind die Primärquelle für Parlamentarier-Abfragen; `dataIF` wird nur für Lobbygruppen-Lookups und das Search-Endpoint verwendet.\n\n## Voraussetzungen\n\n- Python 3.11 oder neuer\n- Internetzugang für den wöchentlichen Lobbywatch-JSON-Export (~17 MB gepackt)\n\n## Installation\n\nVia PyPI (nach dem ersten Release):\n\n```bash\npip install lobbywatch-mcp\n```\n\nAus dem Quellcode:\n\n```bash\ngit clone https://github.com/malkreide/lobbywatch-mcp.git\ncd lobbywatch-mcp\npip install -e \".[dev]\"\n```\n\n## Verwendung\n\n### Standalone\n\n```bash\nlobbywatch-mcp\n```\n\nStartet den Server im `stdio`-Modus. Für HTTP:\n\n```bash\nLOBBYWATCH_MCP_TRANSPORT=http LOBBYWATCH_MCP_PORT=8000 lobbywatch-mcp\n```\n\n### Claude Desktop\n\nEintrag in `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"lobbywatch\": {\n      \"command\": \"uvx\",\n      \"args\": [\"lobbywatch-mcp\"]\n    }\n  }\n}\n```\n\nEin vollständiges Beispiel findet sich in [`claude_desktop_config.json`](claude_desktop_config.json).\n\n### Beispielanfragen\n\nNach dem Verbinden können etwa folgende Prompts verwendet werden:\n\n- *«Zeig mir die Top 10 SP-Mitglieder nach Anzahl Interessenbindungen.»*\n- *«Welche WBK-N-Mitglieder haben Mandate im Verlags- oder Bildungssektor?»*\n- *«Lade die Lobbygruppe 'economiesuisse' und liste die angebundenen Parlamentarier:innen.»*\n- *«Wie ist die Verteilung der Vergütungstransparenz in der Finanzkommission FK-N?»*\n\n## Tools\n\nAlle Tool-Namen tragen seit 0.2.0 das `lobbywatch_`-Namespace-Präfix, um\nKollisionen mit Schwester-Servern im Portfolio zu vermeiden.\n\n| Tool | Zweck | Quelle |\n|---|---|---|\n| `lobbywatch_get_parlamentarier(name_or_id)` | Vollprofil mit allen Interessenbindungen | Dump |\n| `lobbywatch_list_interessenbindungen(name_or_id, nur_hauptberuflich, nur_aktiv)` | Gefilterte Mandatsliste | Dump |\n| `lobbywatch_search_parlamentarier_nach_branche(branche_query, kommission, limit)` | Kreuzfilter Branche × Kommission | Dump |\n| `lobbywatch_get_lobbygruppe(name_or_id)` | Lobbygruppe inkl. verbundener Organisationen \u0026 Parlamentarier:innen | Live dataIF |\n| `lobbywatch_get_ranking(kriterium, kommission, partei, limit)` | Top-N nach Kriterium | Dump |\n| `lobbywatch_get_transparenzquote(kommission)` | Verteilung der Transparenzbewertungen | Dump |\n| `lobbywatch_refresh_dump()` / `lobbywatch_dump_status()` | Cache-Steuerung | Dump |\n\n## Konfiguration\n\nSteuerung vollständig über Umgebungsvariablen:\n\n| Variable | Default | Zweck |\n|---|---|---|\n| `LOBBYWATCH_MCP_TRANSPORT` | `stdio` | Transportmodus (`stdio`, `http`, `sse`) |\n| `LOBBYWATCH_MCP_HOST` | `127.0.0.1` | HTTP-Bind-Host (nur hinter Auth-Gateway auf `0.0.0.0` setzen) |\n| `LOBBYWATCH_MCP_PORT` | `8000` | HTTP-Bind-Port |\n| `LOBBYWATCH_MCP_CACHE_DIR` | `~/.cache/lobbywatch-mcp` | Speicherort für gecachte Dumps |\n| `LOBBYWATCH_MCP_CACHE_TTL` | `86400` (24 h) | Cache-Gültigkeit in Sekunden |\n| `LOBBYWATCH_MCP_HTTP_TIMEOUT` | `60` | HTTP-Timeout in Sekunden |\n| `LOBBYWATCH_MCP_CORS_ORIGINS` | _(unset)_ | Komma-getrennte Origin-Allow-List für HTTP/SSE; falls gesetzt, wird `Mcp-Session-Id` an Browser exponiert |\n| `LOBBYWATCH_MCP_LOG_FORMAT` | `text` | `text` (Standard-Logger) oder `json` (strukturiert via structlog) |\n| `LOBBYWATCH_MCP_LOG_LEVEL` | `INFO` | `DEBUG` / `INFO` / `WARNING` / `ERROR` |\n| `LOBBYWATCH_MCP_OTEL_ENABLED` | `0` | Auf `1` setzen, um OpenTelemetry-Tracing zu aktivieren (`pip install 'lobbywatch-mcp[obs]'`) |\n| `LOBBYWATCH_MCP_OTEL_ENDPOINT` | _(unset)_ | OTLP/HTTP-Collector-Endpoint (z.B. `http://localhost:4318/v1/traces`) |\n\n## Projektstruktur\n\n```\nlobbywatch-mcp/\n├── src/lobbywatch_mcp/\n│   ├── __init__.py\n│   ├── __main__.py        # CLI + Transport-Auswahl\n│   ├── config.py          # URLs, Cache-Pfade, Attribution\n│   ├── client.py          # Dump-Download + dataIF-Client\n│   ├── models.py          # Pydantic-v2-Response-Envelopes\n│   └── server.py          # FastMCP-Tool-Registrierung\n├── tests/\n│   ├── conftest.py        # Fixture-Parlamentarier:innen\n│   ├── test_client.py     # Respx-Mocked Unit-Tests\n│   ├── test_server.py     # Tool-Integrationstests\n│   └── test_live.py       # @pytest.mark.live — in CI ausgeschlossen\n├── .github/workflows/\n│   ├── ci.yml             # Test-Matrix + ruff\n│   └── publish.yml        # PyPI OIDC Trusted Publisher\n├── claude_desktop_config.json\n├── pyproject.toml\n└── ...\n```\n\n## Datenlizenz \u0026 Namensnennung\n\n**Der Code** steht unter MIT-Lizenz.\n\n**Die Daten** sind © Lobbywatch.ch und stehen unter [CC BY-SA 4.0](https://creativecommons.org/licenses/by-sa/4.0/). Jedes Antwort-Envelope trägt automatisch die Attributionszeichenfolge. Weiterverwendende müssen:\n\n1. Lobbywatch.ch als Quelle nennen.\n2. Abgeleitete Datensätze unter denselben CC-BY-SA-4.0-Bedingungen teilen.\n3. Verstehen, dass Lobbywatch eine **gemeinschaftsgestützte Recherchedatenbank** ist — kein amtliches Register. Für Transparenzforschung autoritativ, aber nicht mit den offiziellen Parlamentsdeklarationen zu verwechseln.\n\n## Bekannte Einschränkungen\n\n- Der Upstream-Endpoint `/table/parlamentarier/...` der `dataIF` liefert aktuell leere Ergebnisse zurück. Der Server umgeht das, indem er den wöchentlichen JSON-Dump verwendet.\n- Zutrittsberechtigungen sind im verwendeten «Essential»-Dump nicht enthalten. Ein späteres Release wird sie über den vollständigen Dump ergänzen.\n\n## Beitragen\n\nSiehe [CONTRIBUTING.de.md](CONTRIBUTING.de.md).\n\n## Sicherheit\n\nSiehe [SECURITY.de.md](SECURITY.de.md) für die Sicherheits-Posture, die\nakzeptierten Risiken und wie eine Schwachstelle gemeldet wird.\n\n## Changelog\n\nSiehe [CHANGELOG.md](CHANGELOG.md).\n\n## Lizenz\n\nMIT-Lizenz — siehe [LICENSE](LICENSE). Daten CC BY-SA 4.0 — siehe [LICENSE](LICENSE) § Data notice.\n\n## Autor\n\n**malkreide** · [GitHub](https://github.com/malkreide)\n\n---\n\n*Teil des [Swiss Public Data MCP Portfolios](https://github.com/malkreide).*\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalkreide%2Flobbywatch-mcp","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmalkreide%2Flobbywatch-mcp","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmalkreide%2Flobbywatch-mcp/lists"}