MobilityMCP
Hosted MCP server for public transport in Germany (ÖPNV).
Что умеет
- Search Place: Löst den NAMEN einer Stadt, Region oder eines Bezirks in Koordinaten und OSM-Ids auf — der erste Schritt, wenn ein GEBIET verortet werden muss („was kann ich in <REGION> unternehmen", „w
- Resolve Location: Löst Freitext in die Id auf, mit der gefahren wird — die Haltestelle, die Adresse oder den POI hinter „von <X> nach <Y>", „erzähl mir was über <POI>". Wo Routing, Abfahrtstafel oder
- Nearby: Findet Haltestellen, POIs und Adressen im Radius um eine KOORDINATE (Schwerpunkt Hannover/Niedersachsen) — „was ist in der Nähe von <lat,lon>", „welche Haltestellen liegen um diesen Punkt". Li
Какие данные видит
Нужен ли аккаунт
Не нужен: сервер работает без входа
Hosted MCP server for public transport in Germany (ÖPNV). It answers timetable questions: journeys from any address, stop or place, departure boards with real-time data, the course of a line, and sharing vehicles nearby with the stock their operators currently report. Journeys and departures cover all of Germany; disruption reports are currently available for Lower Saxony, Bremen and Hamburg. In clients that draw, journeys and departure boards also come as an interactive view. Read-only: it books and sells nothing. Open data under their licences (DELFI, OpenStreetMap, MobiData BW and the sharing operators), passed through with attribution. For sights, events and weather, add its sibling TourismMCP; one account covers both.
Как подключить
Как подключить MobilityMCP к Claude
Адрес сервера, который нужно вставить в настройках Claude:
https://mobilitymcp--kaufmann.run.tools
- Откройте Claude (сайт claude.ai или приложение для компьютера).
- Перейдите в Настройки → Коннекторы (в английском интерфейсе: Settings → Connectors).
- Нажмите Добавить пользовательский коннектор (Add custom connector).
- Вставьте адрес сервера, скопированный ниже, в поле URL удалённого MCP-сервера и нажмите Добавить.
- В чате нажмите + → Коннекторы и включите новый коннектор.
Пользовательские коннекторы доступны на тарифах Free, Pro, Max, Team и Enterprise. На Free можно добавить только один. В Team и Enterprise коннектор сначала добавляет владелец организации в Настройки организации → Коннекторы.
Авторизация
После нажатия Добавить откроется окно входа в сервис. Войдите под своим аккаунтом и подтвердите доступ. Пароль Claude не видит.
Как подключить MobilityMCP к ChatGPT
Адрес сервера, который нужно вставить в настройках ChatGPT:
https://mobilitymcp--kaufmann.run.tools
- Откройте ChatGPT в браузере (chatgpt.com). Нужен тариф Plus, Pro, Business, Enterprise или Edu.
- Один раз включите режим разработчика: Настройки → Приложения → Дополнительные настройки → Режим разработчика (Settings → Apps → Advanced settings → Developer mode).
- Откройте Настройки → Коннекторы и нажмите Создать (Create).
- Заполните форму: Название (любое), Описание (одна фраза, что делает сервис), URL MCP-сервера (скопируйте ниже).
- В поле Аутентификация выберите OAuth, если сервис требует вход, иначе Нет. Нажмите Создать.
- В новом чате откройте + → Приложения/Коннекторы и включите коннектор.
Название раздела у OpenAI менялось (Connectors → Apps/Plugins). Если пункт называется иначе, ищите «режим разработчика» в настройках. В рабочих пространствах Business/Enterprise администратор должен разрешить пользовательские коннекторы.
Авторизация
При первом использовании ChatGPT откроет окно входа в сервис. Войдите и подтвердите доступ.
Как подключить MobilityMCP к Cursor
Адрес сервера, который нужно вставить в настройках Cursor:
https://mobilitymcp--kaufmann.run.tools
Быстрый способ: нажмите кнопку Открыть в Cursor ниже, Cursor сам предложит добавить сервер.
Вручную:
- В Cursor откройте Settings → Cursor Settings → MCP и нажмите Add new global MCP server.
- Вставьте JSON, скопированный ниже, в открывшийся файл
~/.cursor/mcp.json(для одного проекта:.cursor/mcp.jsonв корне проекта). - Сохраните файл. Сервер появится в списке MCP; при необходимости пройдите авторизацию по кнопке рядом с ним.
Авторизация
Если сервис требует вход, рядом с сервером в списке MCP появится кнопка авторизации.
Список инструментов сервера (13)
Технические названия из tools/list. Нужны только разработчикам.
| search_place | Löst den NAMEN einer Stadt, Region oder eines Bezirks in Koordinaten und OSM-Ids auf — der erste Schritt, wenn ein GEBIET verortet werden muss („was kann ich in <REGION> unternehmen", „wie ist das Wetter in <CITY>"). **Für eine HALTESTELLE ist dieses Werkzeug fast immer falsch**: es kennt Gebiete, keine Bahnsteige — auf einen Bahnhofs-Namen antwortet es mit dem Stadtteil, und die Id, die es liefert, ist eine OSM-Id und keine fahrbare Halte-Id. **Trägt die Anfrage `Bahnhof`, `Hauptbahnhof`, `Hbf` oder `Bf`, gehört sie an die Ortsauflösung** — „Köln Hauptbahnhof" und „Hannover Bahnhof" also dorthin, nicht hierher: auf das erste antwortet dieses Werkzeug mit einem gleichnamigen Ortsteil (einem in Potsdam), auf das zweite mit der Stadt Hannover. Dasselbe für Adresse und POI — alles, was Start, Ziel oder Abfahrtsort einer Fahrt sein kann; eine Stadt als Fahrt-Endpunkt („von Hannover nach Celle") ebenfalls. Von einer Koordinate zurück zum Namen geht `reverse_geocode`, die Umgebung einer Koordinate listet `nearby`. **Pflicht**: `name`. **Optional**: `lang` — wird für Symmetrie mit den übrigen Geo-Werkzeugen angenommen, derzeit aber nicht ans Backend durchgereicht und ändert das Ergebnis nicht. **Anleitung**: `get_usage_guide` mit `tool='search_place'` — die Abgrenzung im Detail, die typischen Ketten und der Umgang mit einem mehrdeutigen Namen. **Anti-Fab**: nur die zurückgegebenen Namen und Ids nutzen, keine Bauch-Geographie. |
| resolve_location | Löst Freitext in die Id auf, mit der gefahren wird — die Haltestelle, die Adresse oder den POI hinter „von <X> nach <Y>", „erzähl mir was über <POI>". Wo Routing, Abfahrtstafel oder POI-Steckbrief eine Id brauchen, steht es davor — auch wenn der Nutzer die Stadt dazu nennt („Hauptbahnhof Hannover"). Ein GEBIET (Stadt/Region) verortet `search_place`. **Pflicht**: `query` — nur der Name: `'Kelsterbach Bahnhof'`, NICHT `'für Kelsterbach Bahnhof'`. Wegzulassen sind `für`, `vom`, `von`, `nach`, `bis`; ein führendes `am`/`an`/`in`/`zur`/`auf` bleibt stehen — so heißen echte Halte („Am Wehrhahn"). **Optional**: `lat`/`lon` (Ranking-Bias), `limit`, `node_types` (`'stop'`/`'address'`/`'poi'`/`'any'`, mehrere mit Komma in EINEM String; eine andere Art ist ein Argument-Fehler), `city_station` (Query = ganze Stadt → deren (Haupt-)Bahnhof). **Art-Wort in `node_types`, nicht in den Namen**: „Haltestelle X" → `'stop'`, „Adresse X" → `'address'`, „POI X"/„Sehenswürdigkeit X" → `'poi'`, `query` je ohne das Wort. **A→B: zweimal rufen** — Start, Ziel. Jeder Treffer trägt `type` und `location`; NUR ein `stop` hat eine fahrbare DH-Id, nie eine erfinden. **Anleitung**: `get_usage_guide` — Abgrenzung, Argumente, Rangfolge. **Anti-Fab**: nur die Treffer aus dem Output dieses Aufrufs verwenden. |
| nearby | Findet Haltestellen, POIs und Adressen im Radius um eine KOORDINATE (Schwerpunkt Hannover/Niedersachsen) — „was ist in der Nähe von <lat,lon>", „welche Haltestellen liegen um diesen Punkt". Liegt nur ein Name vor, kommt erst eine Auflösung: `search_place` für eine Stadt oder Region, sonst die Ortsauflösung. **Pflicht**: `latitude`, `longitude`, `radius_m`. **Optional**: `limit` (Default 10); `node_types` — EIN String, mehrere Arten mit Komma: `'stop'`, `'address'`, `'poi'`, die Sharing-Angebote `'bike_rental'`, `'scooter_rental'`, `'car_sharing'`, `'taxi_stand'`, die Abstellanlagen `'park_and_ride'`, `'bike_and_ride'`, oder `'any'` (`'stop,bike_rental'`); `include_mots` (legt die bedienenden Linien über die Haltestellen-Treffer); `only_available` (nur Sharing-Treffer mit gemeldetem freiem Fahrzeug — UNBEKANNTE Verfügbarkeit gilt nicht als frei). **Format**: kompakter Einrück-Text (TOON), kein JSON. **Anleitung**: `get_usage_guide` mit `tool='nearby'` — die Werte im Einzelnen, was `'any'` nicht abdeckt, und was ein Treffer trägt (`category`, `modality`, `parking`, `contactInfo`). **Anti-Fab**: nur die zurückgegebenen Namen, Typen, Distanzen und Verfügbarkeiten nennen; fehlt ein Feld, war es in der Quelle nicht getaggt — Öffnungszeiten und Preise stehen hier NICHT. |
| reverse_geocode | Benennt, was an einer KOORDINATE liegt — der Ort („was liegt bei <lat,lon>"), mit `level` eine bestimmte Ebene davon, mit `level='street'` die Straße samt nächster Hausnummer (der Lookup für eine GPS-Startposition). **Abgrenzung**: den Weg zurück (Name → Koordinate und OSM-Ids) geht `search_place`, die fahrbare Halte-Id liefert die Ortsauflösung, und `nearby` listet auf, was UM eine Koordinate liegt, statt den Punkt selbst zu benennen. **Pflicht**: `lat` und `lon` — geschrieben auch `latitude`/`longitude`, so wie `nearby` die Koordinate nimmt; je Aufruf nur eine der beiden Schreibweisen. **Optional**: `radius_m` (Suchradius in METERN; ein Ort, IN dem die Koordinate liegt, hat Abstand 0 und ist in jedem noch so engen Radius dabei — ohne `radius_m` die nächstgelegenen Treffer), `limit` (Höchstzahl Treffer, Default 10, Maximum 50) und `level` — `'place'` (Default: die ganze Ortshierarchie, feinste Ebene zuerst), `'city'` (die Stadt/Gemeinde), `'suburb'` (der Stadtteil) oder `'street'`. Kennt der Datensatz die gewünschte Ebene hier nicht, antwortet die nächst-gröbere, erkennbar am `place_type`; ein unbekannter Wert wirkt wie `'place'`. **Anleitung**: `get_usage_guide` mit `tool='reverse_geocode'`. **Anti-Fab**: nur die zurückgegebenen Orts- und Straßen-Namen verwenden, einschließlich der Hausnummer aus dem Datensatz — nie eine erfinden. |
| connections | Plant ÖPNV-Verbindungen von A nach B, deutschlandweit, Fernrouten eingeschlossen — **als Daten, für Ergebnisse, die du weiterverarbeitest**. Steht `show_connections` in deinem Werkzeug-Satz, ist das der Vordereingang für die Frage eines Menschen. Für „wie komme ich von X nach Y" kommt die Auskunft aus diesen Werkzeugen, nicht aus dem Allgemeinwissen. **Pflicht sind BEIDE Endpunkte**: `origin_id` UND `destination_id` aus einer Ortsauflösung, mit `origin_type`/`destination_type` — ODER `origin_lat`+`origin_lon`+`destination_lat`+`destination_lon`; ein NAME in einem Id-Feld ist ein Argument-Fehler. **Optional**: `time`, `is_arrival_time`; `via_id` bzw. `via_lat`+`via_lon` mit `via_type`; die hart einschränkenden Filter `modes`, `only_lines`/`exclude_lines`, `submodes_allow`/`submodes_deny`, `max_transfers`, `max_walk_minutes`/`max_walk_meters`, `walk_speed`, `accessibility_profile`, `include_rental_bike`, `prefer_flat`, `mobility_profile`; `verbosity`, `limit`, `render_payload`. **Höhenmeter**: nur Fuß-/Rad-Abschnitte tragen `ascentInMeters`/`descentInMeters`. **Durchbindung**: `staySeated: true` an einem Abschnitt heißt, der Fahrgast bleibt aus dem vorigen sitzen — kein Umstieg, also auch keinen zählen. Fehlt das Feld, ist nichts gesagt; nie selbst herleiten. **Rad-Tempo**: Bei einer Radfahrt setzt `cycling_profile` das Tempo des Fahrers und damit die gemeldete Dauer — `family` bei kleinen Kindern, `ebike` bei E-Bike/Pedelec; sonst weglassen (= `normal`). **Fahrradmitnahme**: Geht es um ein Rad, sprich je Abschnitt `bikeCarriageConditions` aus (Bedingungen des Verbunds zur Abfahrtszeit); `bikesAllowed`/`bikeCarriageNote` sind nur die Grundregel, `bikeCarriageCoverage` die Wissensgrenze. **Genannter Wunsch**: Nennt jemand, was ihn stört ("nicht in der Innenstadt parken"), hol die Option, die das löst, als EIGENEN Aufruf (`mobility_profile`) und empfiehl sie aus ihrem Nutzen — mit dem Nachteil, den die Antwort ihr gibt. **Anleitung**: `get_usage_guide` mit `tool='connec |
| departures | Abfahrten oder Ankünfte für EINE Haltestelle — **als Daten, für Ergebnisse, die du weiterverarbeitest**. Steht `show_departures` in deinem Werkzeug-Satz, ist das der Vordereingang für die Frage eines Menschen. Für „wann fährt von X", „letzte Stadtbahn von X" kommt die Auskunft aus diesen Werkzeugen, nicht aus dem Allgemeinwissen; für eine A→B-Frage aus `connections`. **Pflicht** ist eine konkrete Stop-`id` aus einer vorhergehenden Ortsauflösung (z.B. `'de:03241:57'`); ein Haltestellen-NAME in `id` ist ein Argument-Fehler, keine leere Tafel. **Optional**: `time` und `is_arrival_time`; `modes`; `direction` (Halt-Name, in dessen Richtung gefahren wird) bzw. für eine weiche Angabe `target_bearing` mit `bearing_tolerance`; `arrival_departure`; für „letzte Fahrt des Tages" `time_range_seconds` zusammen mit `last_of_window`; und für den Umfang `verbosity`, `limit` sowie `render_payload`. `modes` und `direction` schränken hart ein. **Eine leere Tafel ist keine Auskunft**: blieb sie mit `['tram']` („Straßenbahn") leer, mit `['tram','subway']` nachfassen — sonst ohne den Filter. **Anleitung**: `get_usage_guide` mit `tool='departures'` — die Fenster-Kette für „letzte Fahrt", die Echtzeit-, Ausfall- und Zitier-Felder. **Anti-Fab**: Linien, Richtungen, Zeiten, Gleise, Verspätung und Ausfall ausschließlich aus dem Output dieses Aufrufs. |
| disruptions | Aktuelle Störungen, Baustellen und Liniensperrungen im ÖPNV. Für „gibt es Störungen", „Ausfälle in X" ist dieses Werkzeug die Auskunft, nicht das Allgemeinwissen. **Datenlage — wichtig**: Störungsmeldungen liegen derzeit für Niedersachsen, Bremen und Hamburg vor; außerhalb gibt es dafür KEINE Datengrundlage. (Verbindungen und Abfahrten sind davon nicht betroffen — die sind deutschlandweit.) Eine leere Antwort ist deshalb nur dann eine Entwarnung, wenn das Feld `coverage` sie als solche ausweist; außerhalb der abgedeckten Gebiete heißt sie, dass du es nicht weißt. **Keine Pflicht-Args** — ohne Filter kommen die aktiven Meldungen, gekappt auf `limit`. Optional: `line` (Liniennummer/-token, z.B. `'6'`, `'U3'`) und `stop` (Haltestellen-Name) verknüpfen UND; `area` (Stadt/Gemeinde) bestimmt das `coverage` und sortiert die unverorteten Meldungen — es unterdrückt sie nicht: die kommen getrennt in `unplaced` zurück, auch ohne `area`. Nenne nur Filter, die der Nutzer wirklich nannte. **Format**: kompakter Einrück-Text (TOON), kein JSON; die Schreibweise steht in der Anleitung. **Anleitung**: `get_usage_guide` mit `tool='disruptions'` — die sechs `coverage`-Werte, die beiden Listen, die Felder einer Meldung und woran eine gekappte Antwort zu erkennen ist. **Anti-Fab**: nur zurückgegebene Meldungen nennen; eine Meldung ohne betroffene Linie und ohne betroffenen Halt ist eine allgemeine Störung und wird keiner Linie zugeschrieben, eine Meldung aus `unplaced` keinem Ort. |
| line_course | Linienverlauf: die Halte-Folge einer ÖPNV-LINIE und ihre gezeichnete Strecke für die Karte — „wo fährt die Y entlang", „welche X-Linien gibt es". Für Linien-Fragen: diese Auskunft, nicht das Allgemeinwissen. **Pflicht ist EINES**: `query` — Name/Nummer, wie ein Mensch sie schreibt (`'Heide-Shuttle'`, `'HS 2'`); ODER `id` aus einer früheren Antwort = GENAU EINE Linie. Sonst frag nach. **Optional**: `area` — der Ort, in dem die Linie fährt (`'Hannover'`; Dutzende Linien heißen `'100'`), `limit` (Default 8), `render_payload`, `format`. **Die Antwort**: je Fahrtrichtung ein Verlauf mit `headsign`, den `halts` als Namen und `pathOnMap` — der Strecke im Text, auf max. ~50 m vereinfacht; volle Auflösung: `render_payload: true`. **Mehrdeutig**: meint die Frage mehr Linien als eine Antwort ganz liest, kommt statt `lines` die Liste `candidates` (Nummer, Betreiber, Id) — ungezeichnet; dann den Ort erfragen oder mit `id` nachfassen. **Grenzen**: `geometryDegraded: true` heißt Luftlinien-Kette statt Straßenverlauf, `note` sagt es. Je Richtung EIN Fahrtmuster; ist `patternsTotal` größer, fährt sie üblicherweise so. `matchedTotal` über der Zahl der Linien heißt Ausschnitt. Unbekannter Ort: `note` sagt es, nichts wurde eingegrenzt. **Nicht dafür**: A→B (`connections`), Abfahrten (`departures`), Störungen (`disruptions`). **Anleitung**: `get_usage_guide` mit `tool='line_course'`. **Anti-Fab**: Linien, Halte, Reihenfolge, Strecke nur aus diesem Aufruf; findet sich keine, sag das. |
| link_datetime | Löst eine Zeit-Nennung in einen absoluten ISO-8601-Zeitpunkt auf — „morgen früh", „heute Abend um 18 Uhr", „in zwei Stunden", „um 8:30". Auch „jetzt"/„now"/„aktuell" wird aufgelöst: nutze das als kanonische Quelle für die aktuelle Zeit, statt dir selbst ein Datum auszudenken. Das Ergebnis (`candidates[].datetime_range.start`) geht direkt als `connections.time` bzw. `departures.time` weiter. Nennt der Nutzer bereits eine vollständige ISO-8601-Zeit mit Offset, ist kein Aufruf nötig. **Pflicht**: `text` — die Nennung, so wie der Nutzer sie schrieb. **Optional**: `lang` (`'de'` Default, `'en'`, `'fr'`) und `tz` (IANA-Name; ohne ihn wird die Lokalzeit als `Europe/Berlin` gelesen und als korrekter UTC-Instant zurückgegeben). **Was zurückkommt**: EIN Zeitpunkt, kein Fenster — `start` und `end` sind derselbe Instant. Eine nicht auflösbare Phrase liefert `candidates: []`; dann nachfragen, statt selbst zu rechnen. **Anleitung**: `get_usage_guide` mit `tool='link_datetime'` — insbesondere, auf welche Stunde eine vage Tageszeit fällt und was dann zu tun ist. **Anti-Fab**: Datum und Uhrzeit sind Fakten wie eine Liniennummer und stammen aus diesem Werkzeug — kein selbst-erfundenes Datum, keine eigene Datums-Arithmetik. Returns `candidates[].datetime_range:{start,end}`. |
| get_usage_guide | Die ausführliche Anleitung zu den Werkzeugen dieses Katalogs: wofür ein Werkzeug da ist, wogegen es abzugrenzen ist, was seine Argumente bewirken, was zurückkommt und was daraus zitiert werden darf. Die `description` eines Werkzeugs ist die Kurzform, dieser Text die vollständige. **Optional** `tool` — der Name genau eines Werkzeugs, dessen Abschnitt du lesen willst; weggelassen kommt die ganze Anleitung. Lies den Abschnitt eines Werkzeugs, bevor du dessen Filter setzt oder ein leeres Ergebnis als Antwort weitergibst. **Der Abruf ohne `tool` ist teuer**: er bringt die Abschnitte ALLER Werkzeuge dieses Katalogs auf einmal, ein Vielfaches eines einzelnen. Setze `tool`, sobald feststeht, um welches Werkzeug es geht; ohne Argument nur für den Überblick über den ganzen Katalog. |
| show_connections | **Der Vordereingang für jede Verbindungsfrage eines Menschen**, auch wenn er nur nach Zeiten fragt: plant die Fahrt wie `connections` und liefert sie zusätzlich als Ansicht aus, die ein Wirt mit Ansichten dem Nutzer zeigt — je Verbindung eine Karte mit Zeiten, Dauer, Umstiegen und Echtzeit-Lage. **Beantwortest du einem Menschen eine Verbindungsfrage, ruf dies statt `connections`**, das für Ergebnisse ist, die du weiterverarbeitest. **Pflicht sind BEIDE Endpunkte**, wie dort: `origin_id` UND `destination_id` — oder die vier Koordinaten-Felder; `render_payload` entfällt. Der Antwort-Text ist der von `connections`; die Rohdaten daneben tragen nur die Felder, die die Ansicht zeichnet, ihr Kartenverlauf davon im `_meta`. **Anleitung**: `get_usage_guide` mit `tool='connections'`. **Anti-Fab**: Linien, Zeiten, Halte und Gleise ausschließlich aus dem Output dieses Aufrufs. |
| show_departures | **Der Vordereingang für jede Abfahrtsfrage eines Menschen**: liest die Tafel einer Haltestelle wie `departures` und liefert sie zusätzlich als Ansicht aus, die ein Wirt mit Ansichten dem Nutzer zeigt — je Abfahrt Linie, Ziel, Gleis/Steig, Zeit und Echtzeit-Lage. **Beantwortest du einem Menschen eine Abfahrtsfrage, ruf dies statt `departures`**, das für Ergebnisse ist, die du weiterverarbeitest. **Pflicht ist die Halte-Id**, wie dort: `id` — eine Id aus `resolve_location`, kein Haltestellen-Name; `render_payload` entfällt. Der Antwort-Text ist der von `departures`; die Rohdaten daneben tragen nur die Felder, die die Ansicht zeichnet. **Anleitung**: `get_usage_guide` mit `tool='departures'`. **Anti-Fab**: Linien, Ziele, Zeiten und Gleise ausschließlich aus dem Output dieses Aufrufs. |
| show_connections_slim | **Dieselbe Verbindungs-Ansicht wie `show_connections`, nur schlank ausgeliefert**: das Kartenwerk lädt die Ansicht als Skript, statt es mitzubringen. **Nimm dies nur, wenn ausdrücklich nach der schlanken Auslieferung gefragt wird** — sonst `show_connections`. Sonst unverändert: plant die Fahrt wie `connections` und liefert sie zusätzlich als Ansicht aus. **Pflicht sind BEIDE Endpunkte**, wie dort: `origin_id` UND `destination_id` — oder die vier Koordinaten-Felder; `render_payload` entfällt. Der Antwort-Text ist der von `connections`; die Rohdaten daneben tragen nur die Felder, die die Ansicht zeichnet, ihr Kartenverlauf davon im `_meta`. **Anleitung**: `get_usage_guide` mit `tool='connections'`. **Anti-Fab**: Linien, Zeiten, Halte und Gleise ausschließlich aus dem Output dieses Aufrufs. |