Skip to main content
Glama
gebab88

Busse Göttingen MCP-Server

by gebab88

Busse Göttingen – MCP-Server

Zweck

Dieser MCP-Server liefert Abfahrten, Tagesfahrpläne und Verbindungen im Göttinger Nahverkehr über die TRIAS-Schnittstelle (VDV 431-2, XML über HTTP POST).

Related MCP server: mcp-sbb-transport

Voraussetzungen und Installation

  • Node.js ≥ 22

npm install
cp .env.example .env

Trage in .env den von Connect Fahrplanauskunft GmbH erhaltenen Wert für RequestorRef ein.

Der RequestorRef ist eine Zugangskennung für die TRIAS-Schnittstelle und wird nicht mit diesem Repository verteilt. Du beantragst ihn selbst bei Connect Fahrplanauskunft GmbH (EFA Deutschland) und trägst ihn in deine eigene .env ein. Ohne gültigen RequestorRef startet der Server nicht.

Start

Für den Produktivbetrieb:

npm run build && npm start

Während der Entwicklung:

npm run dev

Die Tests sind hermetisch und laufen mit oder ohne lokale .env-Datei: Der RequestorRef wird in tests/setup.ts durch einen Platzhalter ersetzt, und alle Tests laufen gegen einen lokalen Fake-Server, nie gegen die echte Schnittstelle.

Bei jedem Push prüft die GitHub-Action in .github/workflows/ci.yml die Typen, die Tests und den Build (Node.js 22).

Der Server verwendet stdio; stdout ist ausschließlich der MCP-Protokollkanal.

MCP-Client-Konfiguration

Der Server liest seine .env aus dem Arbeitsverzeichnis, in dem er gestartet wird. Deshalb muss der Client ihn mit cwd auf das Projektverzeichnis setzen — sonst findet er die .env nicht und startet mit „RequestorRef fehlt.".

OpenCode (~/.config/opencode/opencode.json):

{
  "mcp": {
    "servers": {
      "busse-goettingen": {
        "type": "local",
        "command": ["node", "/PFAD/ZUM/PROJEKT/dist/index.js"],
        "cwd": "/PFAD/ZUM/PROJEKT"
      }
    }
  }
}

Claude Code (~/.claude.json):

{
  "mcpServers": {
    "busse-goettingen": {
      "command": "node",
      "args": ["/PFAD/ZUM/PROJEKT/dist/index.js"],
      "cwd": "/PFAD/ZUM/PROJEKT"
    }
  }
}

/PFAD/ZUM/PROJEKT steht für das Verzeichnis, in dem du das Projekt geklont hast.

So steht der RequestorRef nicht in der Client-Konfiguration, sondern bleibt in der .env des Projekts. Alternativ kann der Client den RequestorRef auch als Umgebungsvariable setzen; Umgebungsvariablen haben Vorrang vor der .env.

Werkzeuge

  • stop_search – query (erforderlich), optional type und maxResults. Sucht Haltestellen und liefert unter anderem stopPointRef; die Suche ist unscharf.

  • departures – stop (Name oder stopPointRef, erforderlich), optional when (UTC), maxResults und includeRealtime. Liefert Abfahrten in einem zweistündigen Zeitfenster mit UTC- und Ortszeit.

  • journey – from und to (Namen oder stopPointRef, erforderlich), optional when (UTC), maxResults und includeRealtime. Liefert Verbindungen, Fahrzeiten und Umstiege.

  • timetable – stop (Name oder stopPointRef, erforderlich), optional date im Format JJJJ-MM-TT. Liefert den Tagesfahrplan ohne Echtzeitabfrage.

Bei unscharfer Auflösung nennen data.resolved, data.resolvedFrom oder data.resolvedTo die tatsächlich verwendete Haltestelle. Abweichungen stehen in warnings.

Umgang mit dem RequestorRef

Der RequestorRef ist eine Zugangskennung und verlässt deinen Rechner nicht:

  • Er steht ausschließlich in .env, die in .gitignore liegt. .env.example enthält nur die Vorlage ohne Wert.

  • Er wird nie protokolliert. Der Server schreibt nichts auf stdout außer dem MCP-Protokoll, und Fehlermeldungen gehen auf stderr.

  • Er wird aus Fehlertexten entfernt, bevor sie das Werkzeug verlassen (<RequestorRef> als Platzhalter). Das betrifft auch den Antworttext der Schnittstelle, falls diese den eigenen Request-Body zurückgibt.

Was der Code und was der Zugang betrifft, steht unter Nutzungsbedingungen Connect.

Bekannte Einschränkungen

  • Die WAF blockiert GET-Anfragen; TRIAS wird deshalb ausschließlich per POST angesprochen.

  • Das Tageskontingent beträgt 10.000 Aufrufe pro Tag. Der Server zählt seine eigenen Aufrufe mit und weist ab 80 % Auslastung darauf hin.

  • RequestorRef wird von der API nicht validiert; ein falscher Wert kann erst durch eine API-Antwort auffallen.

  • Die Haltestellen-Auflösung ist unscharf. data.resolved nennt immer die verwendete Haltestelle.

  • Zeiten werden in UTC und in der Zeitzone Europe/Berlin ausgegeben.

  • Als lokal gekennzeichnet (isLocal) sind nur die Orte aus GÖTTINGEN_LOCALITIES; voreingestellt ist allein Göttingen. Gleichnamige Orte wie „Göttingen (Westf)" zählen nicht als lokal.

Verifizierte Beispiele

Live gegen https://v4-api.efa.de/efa/trias geprüft am 20.10.2026 mit npx tsx scripts/smoke.ts (5 API-Aufrufe):

stop_search
  de:03152:33817  Bahnhof, Göttingen (probability 0.25, high)
  de:03152:5382    Göttingen Bahnhof (probability 0.25, high)
  de:03152:33982   Göttingen Landgericht/Bahnhof (probability 0.239999995)

departures
  de:03159:33817::7 | RB86 | Göttingen → Einbeck Mitte
  timetabledTime: 2026-10-20T13:25:00Z
  timetabledTimeLocal: 2026-10-20T15:25:00+02:00 | realtime: true
  warning: Es wurden 20 von mehr Abfahrten zurückgegeben.

timetable
  resolved: de:03152:33817, Bahnhof, Göttingen
  date: 2026-10-20
  RB86 | Göttingen → Einbeck Mitte
  timetabledTime: 2026-10-20T13:25:00Z
  timetabledTimeLocal: 2026-10-20T15:25:00+02:00
  ICE 771 InterCityExpress | Kiel Hbf → Göttingen
  timetabledTime: 2026-10-20T13:31:00Z
  timetabledTimeLocal: 2026-10-20T15:31:00+02:00

journey
  resolvedFrom: de:03152:33817, Bahnhof, Göttingen
  resolvedTo: de:03152:33924
  departureTime: 2026-10-20T11:10:00Z | departureTimeLocal: 2026-10-20T13:10:00+02:00
  arrivalTime: 2026-10-20T11:58:00Z | arrivalTimeLocal: 2026-10-20T13:58:00+02:00
  durationMinutes: 48 | interchanges: 2
  leg: RB85 | Göttingen → Lenglern Bahnhof

API-Aufrufe: 5

Der separate Live-Test der unbekannten ID de:09999:33924 war fehlerfrei und lieferte confidence: low sowie den Hinweis, dass die ID nicht existiert. Die aktuelle API-Antwort verwendete dabei Geretsried, Feuerwehrschule; „Geretsried, Keplerweg“ war ebenfalls in der Antwort enthalten, aber nicht der zuerst gelieferte Halt. Das ist eine Abweichung von der erwarteten Fixture-Ausgabe und wird deshalb nicht verschwiegen.

Nutzungsbedingungen Connect

Die Daten dürfen nur für eigene Zwecke verwendet und nicht weiterverkauft werden. Alle Angaben ohne Gewähr.

Code und Zugang

Der Code dieses Servers darf weitergegeben werden. Der Zugang (der RequestorRef) darf es nicht: Die Nutzungsbedingungen von Connect erlauben die Weitergabe der Zugangsdaten nur mit schriftlicher Zustimmung, und Connect behält sich vor, den Zugang bei Verstößen zu sperren.

Ein git clone dieses Projekts enthält kein Credential — die .env ist nicht versioniert. Wer den Code erhält, kann sich mit einem eigenen, bei Connect beantragten RequestorRef Zugang verschaffen. Das ist die beabsichtigte Grenze: Der Code ist offen, der Zugang bleibt bei dem, der ihn beantragt hat.

Wer den Server öffentlich betreiben will (etwa als Dienst für andere), muss das vorher mit Connect klären.

Available Tools

4 tools
departuresAbfahrtenA

Liefert Abfahrten einer Haltestelle für ein Zeitfenster von zwei Stunden. stop kann ein Haltestellenname oder eine stopPointRef sein und wird unscharf aufgelöst; when ist ein UTC-Zeitpunkt. includeRealtime steuert Echtzeitdaten, maxResults die Anzahl.

NameRequiredDescriptionDefault
stopYes
whenNo
maxResultsNo
includeRealtimeNo

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden, and it does disclose useful behavior: fuzzy resolution of stop identifiers, UTC semantics for when, a fixed two-hour window, and that includeRealtime toggles realtime data. It omits error behavior for unresolvable stops, defaults, and any rate or data-source caveats.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A single dense paragraph that front-loads the core purpose and the two-hour window before moving to parameter behavior. Every clause carries information, though the parameter notes are run together rather than separated, slightly reducing scanability.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 4-parameter tool with no annotations and no output schema, the description covers purpose and all parameters adequately. It does not describe the shape of returned departures or the meaning of realtime vs scheduled entries, which an agent may need to interpret results.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does explain all four parameters: stop accepts a name or stopPointRef and is fuzzily resolved, when is a UTC timestamp, includeRealtime controls realtime data, maxResults controls count. It still leaves types, defaults, and maxResults bounds unstated, so it is not fully self-sufficient.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Liefert Abfahrten einer Haltestelle') plus the fixed scope of a two-hour window, which is more precise than the bare title 'Abfahrten'. It does not name or contrast any sibling (stop_search, journey, timetable), so an agent must infer differentiation from the resource alone.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is implied by the resource: an agent can tell this returns a departure board for a stop within a two-hour window. There is no explicit when-to-use/when-not guidance and no reference to the sibling timetable or journey tools, which is a real gap for a transit domain with overlapping tools.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

journeyFahrten suchenA

Liefert mögliche Verbindungen zwischen zwei Haltestellen mit Strecke, Umstiegen und Zeiten. from und to sind Namen oder stopPointRefs und werden unscharf aufgelöst; when ist UTC. includeRealtime aktiviert Echtzeitdaten, maxResults begrenzt die Verbindungen.

NameRequiredDescriptionDefault
toYes
fromYes
whenNo
maxResultsNo
includeRealtimeNo

TDQS

A3.5/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It does add real behavioral context: from/to are fuzzy-resolved names or stopPointRefs, when is UTC, includeRealtime toggles live data, maxResults caps the result set. However it is silent on failure behavior (no connection found), defaults, limits, or whether results are cached/scheduled-only.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

A tight, front-loaded block: the core purpose comes first, then the parameter semantics. Nearly every clause carries information, with only mild redundancy in re-stating the result contents.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 5-parameter tool with no annotations and no output schema, the description covers the input contract reasonably well and sketches the return shape (route, transfers, times). It still leaves gaps around error/empty-result behavior, defaults, and depth of realtime semantics.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 0%, so the description must compensate, and it does: all five parameters are addressed, with the crucial fuzzy-resolution and stopPointRef semantics for from/to and the UTC convention for when. It stops short of giving a concrete format for when, a default for maxResults, or the default for includeRealtime.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description gives a specific verb+resource: it returns possible connections between two stops, and it enumerates what those results contain (route, transfers, times). It is clearly distinguishable from siblings like departures or timetable, though it never names them explicitly to reinforce the contrast.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines3/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Usage is only implied: an agent can infer this is the point-to-point routing tool rather than a stop lookup or departure board. There is no explicit statement of when to prefer journey over departures or timetable, and no prerequisites or exclusions are given.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

timetableTagesfahrplanA

Liefert den Tagesfahrplan einer Haltestelle für ein Datum. stop kann ein Name oder eine stopPointRef sein und wird unscharf aufgelöst; date ist JJJJ-MM-TT in Europe/Berlin. Echtzeit wird hier nicht abgefragt.

NameRequiredDescriptionDefault
dateNo
stopYes

TDQS

A3.9/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

With no annotations, the description carries the full burden. It usefully discloses that stop names are fuzzy-resolved, that the date is interpreted in Europe/Berlin, and that no realtime data is involved, but it says nothing about ambiguous-stop handling, error behavior, or result volume/cap.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three short sentences, each earning its place: purpose first, then the two parameters with their formats, then the scoping exclusion. No filler or redundancy.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness4/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a simple two-parameter read tool with no output schema and no annotations, the description covers the essentials: what is returned in principle, parameter formats, timezone, and fuzzy matching. It stops just short of describing output shape or the omitted-date default.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 0%, so the description must compensate, and it largely does: 'stop' is documented as accepting either a name or a stopPointRef with fuzzy resolution, and 'date' as YYYY-MM-DD in Europe/Berlin. The only gap is that 'date' is optional yet no default behavior (e.g. today) is stated.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb+resource: it returns the daily timetable for a stop on a given date. The clause 'Echtzeit wird hier nicht abgefragt' implicitly separates it from the sibling 'departures', but no sibling is named, so differentiation requires inference.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives a clear exclusions signal — realtime is not fetched here — which tells the agent when to look elsewhere. However, it never names the alternative tool (departures) nor states prerequisites, so the routing is implied rather than explicit.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 4 tool updatesv0.1.0
    • First observeddepartures
    • First observedjourney
    • First observedstop_search
    • First observedtimetable

TDQS

A3.6/5.0

Scored across 4 tools

Disambiguation4/5

Each tool targets a distinct operation: stop_search returns stop references, departures gives a two-hour departure window, journey computes connections between stops, and timetable returns a full-day schedule. departures and timetable both relate to a stop but differ by time horizon and real-time inclusion, so confusion is limited.

Naming Consistency3/5

stop_search uses a verb_noun snake_case pattern, while departures, journey, and timetable are bare nouns. The set is readable but lacks a single predictable naming convention.

Tool Count5/5

Four tools cover the core read-only transit queries without redundancy. Each earns its place and the count is well within a healthy range.

Completeness4/5

The surface covers stop lookup, departures, journey planning, and timetable, which are the main transit information needs. Minor gaps remain, such as nearby-stop search or line/disruption details, but agents can work around them.

Maintenance

ActivityMaintained
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers