DIP Parliamentary Analyser
Analyzes German Bundestag parliamentary group membership distribution via the DIP API and exposes analysis through MCP tools for natural language interaction.
README
DIP Parliamentary Analyser
A production-quality proof-of-concept that connects to the German Bundestag DIP API, analyses Fraktion (parliamentary group) membership distribution, and exposes the analysis through an MCP (Model Context Protocol) server with Groq LLM tool-calling.
Built for the PwC AIMoS Coding Challenge.
Project Overview
The system fetches real politician data from the official German Bundestag open-data API, determines each politician's Fraktion membership, computes percentage distribution across all parliamentary groups, and uses a large language model to generate a human-readable German-language summary.
The architecture has four modes of interaction:
BundesBot UI— a Streamlit chat interface for asking natural language questions about the Bundestaganalyse— a one-shot CLI command that fetches data, computes distribution, and generates an LLM summaryserve— exposes MCP tools over stdio transport so any MCP-compatible client (e.g. Claude Desktop) can call themchat— an interactive REPL where the LLM automatically selects and calls the right tool based on your natural language question
Key technologies: Python 3.11, FastMCP, Groq (llama-3.3-70b-versatile), httpx, Pydantic v2, Rich, Typer, Poetry, Docker.
Prerequisites
| Requirement | Version | Notes |
|---|---|---|
| Python | 3.11+ | 3.12 recommended for Docker |
| Poetry | 1.8+ | Dependency and packaging manager |
| Docker | 24+ | Optional — for containerised runs |
| DIP API key | — | German Bundestag open-data portal |
| Groq API key | — | Free at console.groq.com |
Installation
# 1. Clone the repository
git clone https://github.com/Indrasena-reddy/DIP-mcp.git
cd DIP-mcp
# 2. Copy the environment file and fill in your API keys
cp .env.example .env
# 3. Install dependencies
poetry install
Open .env in any text editor and replace the placeholder values:
DIP_API_KEY=your_dip_api_key_here
GROQ_API_KEY=your_groq_api_key_here
Configuration
All configuration is read from environment variables (or the .env file). Never commit .env to version control — it is listed in .gitignore.
| Variable | Required | Default | Description |
|---|---|---|---|
DIP_API_KEY |
Yes | — | German Bundestag DIP API key |
GROQ_API_KEY |
Yes | — | Groq LLM API key |
DIP_API_BASE_URL |
No | https://search.dip.bundestag.de/api/v1 |
DIP API base URL |
GROQ_MODEL |
No | llama-3.3-70b-versatile |
Groq model identifier |
LOG_LEVEL |
No | INFO |
Python logging level |
REQUEST_TIMEOUT_SECONDS |
No | 30 |
HTTP request timeout |
MAX_CONCURRENT_REQUESTS |
No | 5 |
Max parallel DIP API requests |
Where to get your keys:
- DIP API key: Register at dip.bundestag.de or use the public demo key available in the portal documentation.
- Groq API key: Create a free account at console.groq.com and generate an API key under API Keys.
Usage
BundesBot UI — Streamlit chat interface
poetry run streamlit run frontend/app.py
Opens the chat UI at http://localhost:8501. Ask questions in natural language (German or English) — BundesBot selects the right MCP tool, fetches live data from the DIP API, and returns a formatted answer.
Example questions:
- Fraktion split in WP 20?
- Who is Friedrich Merz?
- How many MdBs in WP 20?
The UI runs on port 8501 by default. To change the port:
poetry run streamlit run frontend/app.py --server.port 8502
Analyse — fetch distribution and generate LLM summary
poetry run dip-mcp analyse --wahlperiode 20
Fetches all politicians for Wahlperiode 20 (2021–2025), computes the Fraktion distribution table, and generates a German-language summary via Groq. The --wahlperiode / -w flag accepts any valid election period number.
# Example: analyse Wahlperiode 19 (2017–2021)
poetry run dip-mcp analyse --wahlperiode 19
Serve — start the MCP server
poetry run dip-mcp serve
Starts the MCP server on stdio transport. Connect any MCP-compatible client (e.g. Claude Desktop, an MCP inspector) to this process. Two tools are registered:
| Tool | Description |
|---|---|
get_fraktion_distribution |
Fraktion distribution for a given Wahlperiode |
get_person_info |
Biographical and parliamentary data for a politician by name |
Chat — interactive natural language assistant
poetry run dip-mcp chat
Starts an interactive REPL. Ask questions in natural language (German or English). The LLM automatically selects the correct tool, fetches live data from the DIP API, and returns a formatted answer.
Example questions:
- Wie ist die Fraktionsverteilung in der 20. Wahlperiode?
- Wer ist Friedrich Merz?
- Which parties are in the Bundestag?
Type exit, quit, or press Ctrl+C to quit.
Docker
Ensure Docker Desktop is running, then:
# Build the image
docker build -t dip-mcp:latest .
# Run the analyse command (default)
docker run --env-file .env dip-mcp:latest
# Run with a specific Wahlperiode
docker run --env-file .env dip-mcp:latest analyse --wahlperiode 19
Docker Compose
docker compose up
This builds the image and runs analyse --wahlperiode 20 by default.
For the interactive chat, run with a TTY:
docker compose run --rm -it dip-mcp chat
Development
Install development dependencies
poetry install
Quality gates
Run all checks before committing:
# Static type checking (strict mode)
poetry run mypy src/ --strict
# Linting and formatting
poetry run ruff check src/
# Docstring style
poetry run pydocstyle src/
# Security scan
poetry run bandit -r src/
# Tests
poetry run pytest tests/ -v
Project structure
src/dip_mcp/
├── api/
│ ├── client.py # Async DIP API client with pagination and retries
│ └── models.py # Pydantic v2 data models
├── cli/
│ ├── app.py # Typer root application and command registration
│ ├── analyse.py # analyse command — end-to-end pipeline
│ └── chat.py # chat command — interactive MCP tool-calling REPL
├── core/
│ └── analytics.py # Fraktion counting and percentage calculation
├── llm/
│ └── groq_client.py # Groq async client — summarisation and tool-calling
├── mcp/
│ ├── server.py # FastMCP server with three registered tools
│ └── tools.py # Business logic functions called by MCP tools
└── config.py # Pydantic Settings — env var loading and validation
Architecture
The system is organised into four independent layers:
DIP API layer (api/) — An async httpx client with cursor-based pagination, a tenacity retry decorator (retries only on 5xx server errors), and an anyio semaphore for bounded concurrency. Pydantic v2 validates every document returned by the API.
Analytics layer (core/) — Pure Python functions that count Fraktion membership using a Counter, calculate percentage shares, and build a validated DistributionReport model. No external dependencies.
MCP layer (mcp/) — A FastMCP server that exposes two tools over stdio transport. All tool calls — both from the chat REPL and from external MCP clients — are routed through FastMCP.call_tool(), so every invocation genuinely flows through the MCP protocol layer. Person data is cached in-process per Wahlperiode to avoid redundant API fetches.
LLM layer (llm/) — An async Groq client that supports two interaction patterns: (1) single-shot summarisation of a finished distribution report, and (2) multi-turn tool-calling where Groq selects which MCP tool to invoke and composes the final answer from the tool result.
Data flow (chat mode)
User question
→ Groq (tool selection) — first LLM call
→ _dispatch_tool()
→ FastMCP.call_tool() — MCP protocol layer
→ tools.py (_get_persons cache)
→ DipApiClient → DIP API — cursor-paginated fetch (first request only)
→ client-side WP filter — keeps only members of requested period
→ analytics.py — WP-specific Fraktion distribution
→ Groq (answer composition) — second LLM call
→ displayed to user
Bonus: Interactive Chat
The chat command implements a full MCP tool-calling loop in a terminal REPL. The LLM receives your natural language question alongside the three tool schemas, autonomously decides which tool to invoke and with what arguments, receives the live DIP API result, and composes a final answer — all without any hardcoded routing logic.
poetry run dip-mcp chat
The session maintains full conversation history, so follow-up questions work naturally. Type exit or press Ctrl+C to quit.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。