Back to Browse

Rhein Ruhr Fahrplan MCP Server

Developer ToolsLow Risk10.0MCP RegistryLocal
Free

Server data from the Official MCP Registry

Public transit data for the Rhein-Ruhr region: live departures, trips, disruptions, GTFS schedules.

About

Public transit data for the Rhein-Ruhr region: live departures, trips, disruptions, GTFS schedules.

Security Report

10.0
Low Risk10.0Low Risk

Valid MCP server (0 strong, 2 medium validity signals). No known CVEs in dependencies. Imported from the Official MCP Registry. 1 finding(s) downgraded by scanner intelligence.

4 files analyzed · 1 issue found

Security scores are indicators to help you make informed decisions, not guarantees. Always review permissions before connecting any MCP server.

Permissions Required

This plugin requests these system permissions. Most are normal for its category.

file_system

Check that this permission is expected for this type of plugin.

env_vars

Check that this permission is expected for this type of plugin.

database

Check that this permission is expected for this type of plugin.

What You'll Need

Set these up before or after installing:

Comma-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.Optional

Environment variable: FAHRPLAN_AGENCY_IDS

Optional: filter live departures/arrivals by operator code (e.g. 'NIAG'). Empty = all operators.Optional

Environment variable: FAHRPLAN_OPERATOR

Optional: default start stop (DHID like 'de:05154:35739', EFA ID or unique name), available via the get_default_start tool.Optional

Environment variable: FAHRPLAN_DEFAULT_START

How to Install

Add this to your MCP configuration file:

{
  "mcpServers": {
    "io-github-marcproe-rhein-ruhr-fahrplan-mcp": {
      "env": {
        "FAHRPLAN_OPERATOR": "your-fahrplan-operator-here",
        "FAHRPLAN_AGENCY_IDS": "your-fahrplan-agency-ids-here",
        "FAHRPLAN_DEFAULT_START": "your-fahrplan-default-start-here"
      },
      "args": [
        "rhein-ruhr-fahrplan-mcp"
      ],
      "command": "uvx"
    }
  }
}

Documentation

View on GitHub

From the project's GitHub README.

rhein-ruhr-fahrplan-mcp

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

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 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)

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).

Reviews

No reviews yet

Be the first to review this server!