Rhein-Ruhr Fahrplan MCP
Public transit data for the Rhein-Ruhr region: live departures, trips, disruptions, GTFS schedules.
Install
Add this to your client's MCP configuration (Claude Desktop: claude_desktop_config.json; Cursor: .cursor/mcp.json; VS Code and others use the same "mcpServers" shape).
rhein-ruhr-fahrplan-mcpclaude mcp add rhein-ruhr-fahrplan-mcp -e 'FAHRPLAN_AGENCY_IDS=<FAHRPLAN_AGENCY_IDS>' -e 'FAHRPLAN_OPERATOR=<FAHRPLAN_OPERATOR>' -e 'FAHRPLAN_DEFAULT_START=<FAHRPLAN_DEFAULT_START>' -- uvx rhein-ruhr-fahrplan-mcp==1.2.2
{
"mcpServers": {
"rhein-ruhr-fahrplan-mcp": {
"command": "uvx",
"args": [
"rhein-ruhr-fahrplan-mcp==1.2.2"
],
"env": {
"FAHRPLAN_AGENCY_IDS": "<FAHRPLAN_AGENCY_IDS>",
"FAHRPLAN_OPERATOR": "<FAHRPLAN_OPERATOR>",
"FAHRPLAN_DEFAULT_START": "<FAHRPLAN_DEFAULT_START>"
}
}
}
}
Environment variables
FAHRPLAN_AGENCY_IDSComma-separated GTFS agency IDs to enable the schedule database (e.g. 'nia-25'). Without it the server runs live-only; schedule tools return a configuration hint. An unfiltered import would create a ~500 MB database and is intentionally not the default.FAHRPLAN_OPERATOROptional: filter live departures/arrivals by operator code (e.g. 'NIAG'). Empty = all operators.FAHRPLAN_DEFAULT_STARTOptional: default start stop (DHID like 'de:05154:35739', EFA ID or unique name), available via the get_default_start tool.
Documentation
From the project's README on GitHub, refreshed weekly. Links open on GitHub.
Contents
rhein-ruhr-fahrplan-mcp
MCP-Server für ÖPNV-Fahrplandaten im Rhein-Ruhr-Gebiet (Datenbasis: Open Data des Verkehrsverbunds Rhein-Ruhr). Auf PyPI: https://pypi.org/project/rhein-ruhr-fahrplan-mcp/
Zwei Datenpfeiler, beide keyless:
| Pfeiler | Quelle | Inhalt |
|---|---|---|
| Sollfahrplan (optional) | VRR-GTFS (Open Data ÖPNV, CKAN-API) → SQLite | Nur die konfigurierten Verkehrsunternehmen (FAHRPLAN_AGENCY_IDS); z. B. NIAG: 123 Routen, 6.975 Fahrten, 3.869 Haltestellen |
| Echtzeit (immer aktiv) | VRR-EFA efa.vrr.de | Live-Abfahrten/-Ankünfte mit Prognose, Verspätungen, Steige, Störungshinweise – im gesamten Verbundgebiet |
Default = Live-Only: Ohne Konfiguration startet der Server sofort und liefert alle Live-Tools über die EFA-Schnittstelle. GTFS-Tools (Sollplan, Haltestellen-Index) melden dann einen klaren Hinweis mit Einrichtungsanleitung – bewusst so, weil ein ungefilterter Import die komplette Datenbank (~500 MB, ~7 Mio. Stop-Times) anlegen würde.
Tools (9)
| Tool | Quelle | Zweck |
|---|---|---|
next_departures | EFA (live) | Live-Abfahrten mit Echtzeitprognose |
next_arrivals | EFA (live) | Live-Ankünfte mit Echtzeitprognose |
plan_connection | EFA (live) | Verbindungen von A nach B im Gesamtnetz |
line_disruptions | EFA (live) | Aktuelle Störungen/Baustellen/Umleitungen |
find_stop | GTFS → EFA-Fallback | Haltestelle finden (DHID auflösen) |
stop_schedule | GTFS | Sollfahrplan (auch morgen/übermorgen) |
sync_status | GTFS | Feed-Status: Version, Gültigkeit, Zeilenzahlen |
update_feed | GTFS | Feed aktualisieren (nur bei neuer Ressource – idempotent) |
get_default_start | GTFS → EFA | Konfigurierte Standard-Start-Haltestelle (FAHRPLAN_DEFAULT_START) auflösen |
Schnellstart
Variante A: uvx (stdio, ohne Docker)
uvx rhein-ruhr-fahrplan-mcp
Oder dauerhaft installiert:
uv tool install rhein-ruhr-fahrplan-mcp
rhein-ruhr-fahrplan-mcp
- Startet sofort (Live-Only). Für den GTFS-Sollplan einmalig die Umgebungsvariablen setzen (siehe unten) und
update_feedaufrufen bzw. Server neu starten – der Import läuft dann automatisch im Hintergrund (~1–2 min, 39 MB Download). - Datenbank-Pfad fest:
~/.local/share/rhein-ruhr-fahrplan-mcp/fahrplan.db(XDG, cwd-unabhängig; viaFAHRPLAN_DB_PATHüberschreibbar).
mcphub/Client-Registrierung (stdio-Typ):
{
"fahrplan-mcp": {
"type": "stdio",
"command": "uvx",
"args": ["rhein-ruhr-fahrplan-mcp"],
"env": {"FAHRPLAN_AGENCY_IDS": "nia-25"}
}
}
(env optional – ohne Agencies reiner Live-Only-Betrieb.)
Variante B: Docker (Streamable HTTP)
docker compose up -d --build
Im Hub als Streamable-HTTP-Server registrieren (Netz-Anbindung via compose.override.yaml, siehe Deployment):
http://fahrplan-mcp:8080/mcp
Konfiguration: Verkehrsunternehmen (FAHRPLAN_AGENCY_IDS)
Der GTFS-Import filtert auf die agency_ids des VRR-Feeds. Setze eine oder mehrere:
# z. B. nur NIAG (Kreise Kleve & Wesel):
export FAHRPLAN_AGENCY_IDS=nia-25
# oder mehrere Unternehmen:
export FAHRPLAN_AGENCY_IDS=nia-25,swk-02,dvg-20
in compose.yaml:
environment:
- FAHRPLAN_AGENCY_IDS=nia-25
# - FAHRPLAN_OPERATOR=NIAG # optional: Live-Abfahrten auch filtern
Ohne FAHRPLAN_AGENCY_IDS:
- Live-Tools (next_departures, next_arrivals, plan_connection, line_disruptions) funktionieren normal (ganzes Gebiet, alle Unternehmen)
- GTFS-Tools (find_stop mit Index, stop_schedule, sync_status) und der Auto-Import antworten mit einem Konfigurationshinweis statt zu importieren
Verkehrsunternehmen (Auswahl)
Die agency_ids stammen aus dem VRR-GTFS-Feed (agency.txt, Stand August 2026). Häufige Unternehmen:
| agency_id | Unternehmen | Gebiet/Angebot |
|---|---|---|
nia-25 | Niederrheinische Verkehrsbetriebe | Bus, Kreise Kleve & Wesel |
dvg-20 | Duisburger Verkehrsgesellschaft | Bus/Tram Duisburg |
swk-02 | SWK MOBIL | Krefeld |
new-80 | NEW mobil und aktiv M'gladbach | Mönchengladbach |
vvg-65 | NEW mobil und aktiv Viersen | Viersen |
btm-70, rbg-70 | Rheinbahn | Düsseldorf |
bgs-00, bgs-30–bgs-34 | BOGESTRA | Bochum/Gelsenkirchen |
btm-13, eva-10–eva-12 | Ruhrbahn | Essen/Mülheim |
dsw-36–dsw-39 | DSW21 | Dortmund |
sto-15, btm-15, eva-15 | STOAG | Oberhausen |
wsw-16, wsw-66 | WSW mobil | Wuppertal |
hst-00, hst-50 | Hagener Straßenbahn | Hagen |
sws-18 | Stadtwerke Solingen | Solingen |
swr-16 | Stadtwerke Remscheid | Remscheid |
ver-45 | VER | Ennepe-Ruhr-Kreis |
ves-40 | Vestische | Recklinghausen/Marl |
bvr-88 | BVR Busverkehr Rheinland | Rheinland-Bus |
bsm-76 | Bahnen der Stadt Monheim | Monheim |
hcr-35 | Straßenbahn Herne-Castrop | Herne/Castrop |
swn-60 | Stadtwerke Neuss | Neuss |
ddb-8003 | DB Regio NRW | Regionalzug NRW |
ddb-NX | National Express | Regionalzug Ruhrgebiet |
ddb-RR | RheinRuhrBahn | Regionalzug |
ddb-R2 | eurobahn | Regionalzug |
ddb-W3 | WestfalenBahn | Regionalzug |
ddb-N2 | NordWestBahn | Regionalzug |
ddb-M2 | REGIOBAHN | Regionalzug |
Rail-Freight-/Charter-Einträge im Feed (Train Charter Services, Train Rental International, Ulmer Eisenbahnfreunde u. a.) sind für den Personenverkehr nicht relevant.
Komplette Liste: agency.txt aus dem aktuellen Feed (Download via CKAN-API, siehe unten) – alle 58 IDs mit Namen. Ein Blick per Python:
python3 -c "import csv; [print(r['agency_id'], '|', r['agency_name'])
for r in csv.DictReader(open('agency.txt'))]"
Architektur
┌─────────────────────── Server (stdio | http) ─────────────────────────┐
│ │
│ FastMCP │
│ ├── Live: EFA-Client (urllib, keyless) ← immer aktiv │
│ │ efa.vrr.de/standard/XML_DM_REQUEST (rapidJSON) │
│ │ XML_TRIP_REQUEST2, XML_STOPFINDER_REQUEST │
│ └── Soll: GTFS-SQLite (nur mit FAHRPLAN_AGENCY_IDS) ← Auto-Update │
│ CKAN-API (alle 6 h) → bei Neuheit: atomarer Import │
└────────────────────────────────────────────────────────────────────────┘
Eigenschaften
- Live-Only-Default: Ohne Konfiguration voll nutzbar (Live-Tools); GTFS-Teil schaltet sich mit
FAHRPLAN_AGENCY_IDSdazu. - Selbst-aktualisierend (mit Agencies): Daemon-Thread prüft alle
FAHRPLAN_FEED_CHECK_INTERVALSekunden (Default 6 h) die CKAN-API; Import nur bei neuer Ressource – atomar per.tmp+os.replace(). Initial- und Auto-Import laufen über dasselbe Lock (kein Doppel-Import). - Operator-Filter für Live-Daten:
FAHRPLAN_OPERATOR(z. B.NIAG) filtert next_departures/next_arrivals; plan_connection sortiert passend bevorzugt. Leer = alle Unternehmen. - Keine API-Keys, keine Accounts. VRR-Open-Data-Nutzungsbedingungen: Test-/Hobby-/Entwicklungsnutzung erlaubt; bei dauerhafter öffentlicher Nutzung Mail an openvrr@vrr.de.
Deployment (Docker)
Der HTTP-Modus lauscht nur im Container-Netz auf :8080/mcp (kein Host-Port). Für die Anbindung an einen MCP-Hub in einem bestehenden Docker-Netz eine lokale Datei compose.override.yaml neben compose.yaml anlegen:
services:
fahrplan-mcp:
networks:
- mein-hub-netz # Name des Netzes, in dem der Hub läuft
networks:
mein-hub-netz:
external: true
docker compose up -d merged das Override automatisch. Die Override-Datei ist umgebungsspezifisch und gehört nicht ins Repository (bereits in .gitignore).
Konfiguration (Env)
| Variable | Default | Bedeutung |
|---|---|---|
FAHRPLAN_AGENCY_IDS | (leer) | Kommaseparierte GTFS-Agency-IDs für den Sollplan-Import. Leer = Live-Only; GTFS-Tools antworten mit Konfigurationshinweis |
FAHRPLAN_DEFAULT_START | (leer) | Standard-Start-Haltestelle (DHID, EFA-ID oder eindeutiger Name – passende IDs liefert find_stop); abrufbar via get_default_start |
FAHRPLAN_OPERATOR | (leer) | Live-Operator-Filter (z. B. NIAG); leer = alle Unternehmen |
FAHRPLAN_DB_PATH | ~/.local/share/rhein-ruhr-fahrplan-mcp/fahrplan.db | SQLite-DB-Pfad (Dockerfile: /data/fahrplan.db) |
FAHRPLAN_MCP_TRANSPORT | stdio | stdio oder http (Dockerfile setzt http) |
FAHRPLAN_MCP_HOST / FAHRPLAN_MCP_PORT | 0.0.0.0:8080 (Dockerfile) | nur http-Modus |
FAHRPLAN_FEED_CHECK_INTERVAL | 21600 (6 h) | CKAN-Prüfung; 0 deaktiviert Auto-Update |
Verifizierte EFA-Eigenheiten (Pitfalls)
outputFormat=rapidJSON: Response-Keys heißenstopEvents/journeys(nichtdepartureList/trips).- Freie Haltestellennamen können mehrdeutig sein → Antwort mit
locations[]-Vorschlägen und leeren Events. Deshalb: IMMER per DHID/ID auflösen. …_Parent-Suffix aus GTFSparent_stationwird von EFA nicht akzeptiert → DHID ohne Suffix.- Bei Ankünften (
itdTripDateTimeDepArr=arr) heißen die Zeitfelder trotzdemdepartureTimePlanned/-Estimated. - Der EFA liefert alle Zeiten mit
Z-Suffix (UTC) – der Client konvertiert sie nach Europe/Berlin, bevor er sie ausgibt (früher zeigten die Tools versehentlich UTC, was wie ein ignorierterdeparture_time-Parameter aussah; gefixt in v1.2.1). - Verspätungen werden als UTC-Differenz berechnet – zeitzonenunabhängig korrekt.
- MS_REQUEST (Meldungs-Endpoint) liefert HTTP 400 → Störungen aus den eingebetteten
infos[]der DM-Antworten extrahieren. calcNumberRequestsgreift in rapidJSON nicht zuverlässig →plan_connectionkann mehr Verbindungen liefern alsmax_results(Ergebnisse korrekt, nur Begrenzung weich).
GTFS-Feed-Details
- CKAN-Dataset:
496eea5d-d6ef-4dc2-aeb0-d15c4fbf3178(„Soll-Fahrplandaten VRR“), API:https://opendata.ruhr/api/3/action/package_show?id=… - Ressourcen-UUID wechselt monatlich → Import ermittelt sie immer frisch per CKAN-API.
- Filter:
agency_id IN (FAHRPLAN_AGENCY_IDS); transitiv referenzierende Zeilen bleiben erhalten. stop_times.txtdes Gesamtfeeds (~7 Mio. Zeilen) wird gestreamt (erste Listen-Version wurde OOM-killed).- Ungefilterter Gesamtfeed wäre ~500 MB Datenbank – deshalb bewusst kein Default-Import.
Entwicklung
git clone … && cd rhein-ruhr-fahrplan-mcp
uv venv && source .venv/bin/activate
uv pip install -e .
rhein-ruhr-fahrplan-mcp # stdio starten (Live-Only)
FAHRPLAN_AGENCY_IDS=nia-25 rhein-ruhr-fahrplan-mcp # mit GTFS-Sollplan
python3 tests/stdio_e2e.py $(command -v rhein-ruhr-fahrplan-mcp) # stdio-E2E
FAHRPLAN_AGENCY_IDS=nia-25 python3 tests/stdio_fullcycle.py $(command -v rhein-ruhr-fahrplan-mcp) # inkl. Autoimport
Releases: Version in pyproject.toml hochziehen → Commit → git tag vX.Y.Z && git push origin vX.Y.Z – die GitHub-Action published automatisch nach PyPI (Trusted Publishing).
Frequently asked questions
What is Rhein-Ruhr Fahrplan MCP?
Public transit data for the Rhein-Ruhr region: live departures, trips, disruptions, GTFS schedules.
How do I install Rhein-Ruhr Fahrplan MCP?
It runs on your machine. In Claude Code: claude mcp add rhein-ruhr-fahrplan-mcp -e 'FAHRPLAN_AGENCY_IDS=<FAHRPLAN_AGENCY_IDS>' -e 'FAHRPLAN_OPERATOR=<FAHRPLAN_OPERATOR>' -e 'FAHRPLAN_DEFAULT_START=<FAHRPLAN_DEFAULT_START>' -- uvx rhein-ruhr-fahrplan-mcp==1.2.2. For other clients, paste the JSON configuration from this page into their MCP settings.
Does Rhein-Ruhr Fahrplan MCP need an API key?
Its registry entry lists no required key or secret. Some features may still need an account with the service it connects to.
Is Rhein-Ruhr Fahrplan MCP open source?
Its code is public on GitHub, but the repository does not declare a standard license.
Who maintains Rhein-Ruhr Fahrplan MCP?
It is published by MarcProe. AI.tn lists it but does not maintain or endorse it.
From the official MCP Registry. Listing is not an endorsement: review a server's code and permissions before giving it access to your data.