mcpField
R
Rhein-Ruhr Fahrplan MCP

Rhein-Ruhr Fahrplan MCP

Local
github.com/MarcProeMaps & Travel0Updated 1w ago

About Rhein-Ruhr Fahrplan MCP

Rhein-Ruhr Fahrplan MCP is an MCP server for public transit data in the Rhein-Ruhr region, using VRR data. It provides live departures, arrivals, trips, and disruption information by default, with GTFS schedules available when configured.

Key features

  1. 01Query live departures and arrivals
  2. 02Plan journeys across the network
  3. 03Check disruptions, construction, and diversions
  4. 04Load GTFS schedules when configured
  5. 05Find stops and inspect their schedules

Use cases

  1. 01Check live times at a stop
  2. 02Plan a journey between two locations
  3. 03Review route disruptions and construction

MCP support

It exposes VRR regional transit data to MCP clients through tools. It supports stdio and Streamable HTTP, and adds scheduled GTFS data when configured.

Configuration

Local server config is the same for every client. Copy it into your client’s MCP config file.

mcp.json · Universal config
{
"mcpServers": {
"marcproe-rhein-ruhr-fahrplan": {
"command": "uvx",
"args": [
"rhein-ruhr-fahrplan-mcp"
],
"env": {
"FAHRPLAN_AGENCY_IDS": "<FAHRPLAN_AGENCY_IDS>",
"FAHRPLAN_OPERATOR": "<FAHRPLAN_OPERATOR>",
"FAHRPLAN_DEFAULT_START": "<FAHRPLAN_DEFAULT_START>"
}
}
}
}
Run commanduvx rhein-ruhr-fahrplan-mcp
Environment variables to set
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.

Local servers need a runtime on your machine (e.g. Node.js 18+). Config file locations differ by client; see your client’s docs.

Packages
pypirhein-ruhr-fahrplan-mcp1.2.2

Tools

9

Saved tool list · updated 2w ago

ParameterTypeRequiredDescription
limitintegerNo
querystringYes

Details

From the project README

rhein-ruhr-fahrplan-mcp

PyPI Python wheel Downloads MCP GTFS + EFA uv Listed on mcpservers.org

Rhein-Ruhr Fahrplan MCP server

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:

PfeilerQuelleInhalt
Sollfahrplan (optional)VRR-GTFS (Open Data ÖPNV, CKAN-API) → SQLiteNur die konfigurierten Verkehrsunternehmen (FAHRPLAN_AGENCY_IDS); z. B. NIAG: 123 Routen, 6.975 Fahrten, 3.869 Haltestellen
Echtzeit (immer aktiv)VRR-EFA efa.vrr.deLive-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)

ToolQuelleZweck
next_departuresEFA (live)Live-Abfahrten mit Echtzeitprognose
next_arrivalsEFA (live)Live-Ankünfte mit Echtzeitprognose
plan_connectionEFA (live)Verbindungen von A nach B im Gesamtnetz
line_disruptionsEFA (live)Aktuelle Störungen/Baustellen/Umleitungen
find_stopGTFS → EFA-FallbackHaltestelle finden (DHID auflösen)
stop_scheduleGTFSSollfahrplan (auch morgen/übermorgen)
sync_statusGTFSFeed-Status: Version, Gültigkeit, Zeilenzahlen
update_feedGTFSFeed aktualisieren (nur bei neuer Ressource – idempotent)
get_default_startGTFS → EFAKonfigurierte 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_feed aufrufen 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; via FAHRPLAN_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_idUnternehmenGebiet/Angebot
nia-25Niederrheinische VerkehrsbetriebeBus, Kreise Kleve & Wesel
dvg-20Duisburger VerkehrsgesellschaftBus/Tram Duisburg
swk-02SWK MOBILKrefeld
new-80NEW mobil und aktiv M'gladbachMönchengladbach
vvg-65NEW mobil und aktiv ViersenViersen
btm-70, rbg-70RheinbahnDüsseldorf
bgs-00, bgs-30–bgs-34BOGESTRABochum/Gelsenkirchen
btm-13, eva-10–eva-12RuhrbahnEssen/Mülheim
dsw-36–dsw-39DSW21Dortmund
sto-15, btm-15, eva-15STOAGOberhausen
wsw-16, wsw-66WSW mobilWuppertal
hst-00, hst-50Hagener StraßenbahnHagen
sws-18Stadtwerke SolingenSolingen
swr-16Stadtwerke RemscheidRemscheid
ver-45VEREnnepe-Ruhr-Kreis
ves-40VestischeRecklinghausen/Marl
bvr-88BVR Busverkehr RheinlandRheinland-Bus
bsm-76Bahnen der Stadt MonheimMonheim
hcr-35Straßenbahn Herne-CastropHerne/Castrop
swn-60Stadtwerke NeussNeuss
ddb-8003DB Regio NRWRegionalzug NRW
ddb-NXNational ExpressRegionalzug Ruhrgebiet
ddb-RRRheinRuhrBahnRegionalzug
ddb-R2eurobahnRegionalzug
ddb-W3WestfalenBahnRegionalzug
ddb-N2NordWestBahnRegionalzug
ddb-M2REGIOBAHNRegionalzug

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_IDS dazu.
  • Selbst-aktualisierend (mit Agencies): Daemon-Thread prüft alle FAHRPLAN_FEED_CHECK_INTERVAL Sekunden (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 [email protected].

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)
VariableDefaultBedeutung
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.dbSQLite-DB-Pfad (Dockerfile: /data/fahrplan.db)
FAHRPLAN_MCP_TRANSPORTstdiostdio oder http (Dockerfile setzt http)
FAHRPLAN_MCP_HOST / FAHRPLAN_MCP_PORT0.0.0.0:8080 (Dockerfile)nur http-Modus
FAHRPLAN_FEED_CHECK_INTERVAL21600 (6 h)CKAN-Prüfung; 0 deaktiviert Auto-Update

Verifizierte EFA-Eigenheiten (Pitfalls)

  • outputFormat=rapidJSON: Response-Keys heißen stopEvents/journeys (nicht departureList/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 GTFS parent_station wird von EFA nicht akzeptiert → DHID ohne Suffix.
  • Bei Ankünften (itdTripDateTimeDepArr=arr) heißen die Zeitfelder trotzdem departureTimePlanned/-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 ignorierter departure_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.
  • calcNumberRequests greift in rapidJSON nicht zuverlässig → plan_connection kann mehr Verbindungen liefern als max_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.txt des 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).

Comments

Markdown supported

New to MCP?

From what the protocol is to installing your first server, these answers cover most first questions.

An open protocol that defines how AI applications connect to external tools and data in a uniform way. Clients talk to the model; MCP servers provide tools, resources and prompt templates. They exchange standard messages, so one server can be reused by many clients.