Rhein-Ruhr Fahrplan MCP

io.github.MarcProev1.2.2更新于 Oct 6, 2026

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

概览

AI 生成的概览

提供德国莱茵-鲁尔地区的实时公共交通发车、到达、换乘与故障信息,并可选支持 GTFS 时刻表数据。

功能
封装 VRR EFA 接口,返回带实时预测的发车与到达信息、站点之间的换乘方案,以及当前的故障、施工和改道提示。配置 GTFS 后可增加所选运营商的计划时刻表、用于解析站点 ID 的站点索引、数据源状态和幂等的数据源更新。还可保存并解析默认出发站点。
适用场景
当助手需要回答莱茵-鲁尔地区的公共交通问题时适用,例如下一班发车、行程规划、延误和故障。仅实时模式即可直接使用;只有需要特定运营商的计划时刻表时才需配置 GTFS。
运行要求
以 Python 包在本地运行(uvx 或 uv tool install),也可用 Docker 以 HTTP 传输运行。无需账号或 API 密钥。可选环境变量:FAHRPLAN_AGENCY_IDS(GTFS 导入)、FAHRPLAN_DEFAULT_START、FAHRPLAN_OPERATOR、FAHRPLAN_DB_PATH、FAHRPLAN_MCP_TRANSPORT、FAHRPLAN_MCP_HOST、FAHRPLAN_MCP_PORT、FAHRPLAN_FEED_CHECK_INTERVAL。需要访问 VRR EFA 服务和 VRR 开放数据 CKAN API 的网络连接。
安装前请注意
GTFS 导入会下载数据源并写入本地 SQLite 数据库;不过滤的导入约 500 MB,因此应设置 FAHRPLAN_AGENCY_IDS。配置运营商后,后台线程每六小时检查一次数据源并自动导入新资源。查询会发送到外部 VRR EFA 与开放数据服务。README 指出长期公开使用需向运营方发送邮件。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Rhein-Ruhr Fahrplan MCP,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

rhein-ruhr-fahrplan-mcp

[PyPI] [Python] [wheel] [Downloads] [MCP] [GTFS + EFA] [uv]

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)

bash
uvx rhein-ruhr-fahrplan-mcp

Oder dauerhaft installiert:

bash
uv tool install rhein-ruhr-fahrplan-mcprhein-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):

json
{  "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)

bash
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:

bash
# 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:

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:

bash
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:

yaml
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

bash
git clone … && cd rhein-ruhr-fahrplan-mcpuv venv && source .venv/bin/activateuv pip install -e .rhein-ruhr-fahrplan-mcp                   # stdio starten (Live-Only)FAHRPLAN_AGENCY_IDS=nia-25 rhein-ruhr-fahrplan-mcp   # mit GTFS-Sollplanpython3 tests/stdio_e2e.py $(command -v rhein-ruhr-fahrplan-mcp)      # stdio-E2EFAHRPLAN_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).

来源:README.md,提交 4342c43

工具

0
工具元数据尚未被收录。

版本历史

1
  1. v1.2.2最新Oct 6, 2026