swiss-transport-mcp
This server gives AI models access to Swiss public transport data through MCP tools: plan journeys, check live departures and disruptions, search stops, get occupancy forecasts, ticket prices, train compositions, and browse open transport datasets.
Search stops by name or find nearby stops by coordinates
Plan journeys from A to B with transfers, duration, and transport modes
Get real-time departures/arrivals with delays and platform info
Retrieve live disruption alerts (cancellations, closures, line changes)
Check train occupancy forecasts for SBB, BLS, Thurbo, and SOB
Get ticket prices including class selection (first/second class)
View train formations — carriages, classes, amenities, accessibility
Search and inspect open data catalogues (~90 transport datasets via CKAN)
Check API status to verify configured keys and service availability
Runs on stdio or HTTP for local Claude Desktop or cloud deployment
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@swiss-transport-mcp What are the next departures from Zurich HB?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
🇨🇭 Part of the Swiss Public Data MCP Portfolio
🚆 swiss-transport-mcp
MCP server connecting AI models to the Swiss public transport system – journey planning, real-time departures, disruptions, occupancy, ticket prices, train formations and open data from opentransportdata.swiss.
Demo
Overview
swiss-transport-mcp gives AI assistants like Claude a complete Swiss travel information system – not just timetables, but also real-time disruption alerts, occupancy forecasts, ticket prices, and a full train formation view. All accessible through a single, standardised MCP interface.
The various APIs at opentransportdata.swiss speak different protocols – OJP 2.0 (XML/SOAP), SIRI-SX (XML), REST/JSON. This server translates everything into clean JSON for the AI model, acting as a multilingual protocol interpreter.
Anchor demo query: "Plan a school trip for 25 students from Zurich to the Technorama in Winterthur – check for disruptions and find the best departure." → More use cases by audience →
Related MCP server: swiss-public-transport-mcp
Features
🗺️ Journey planning (A → B with transfers, duration, transport mode) via OJP 2.0
🕐 Real-time departures with delays and platform information
🔍 Stop search by name or coordinates
🚨 Live disruption alerts (cancellations, closures) via SIRI-SX
📊 Occupancy forecasts for trains (SBB, BLS, Thurbo, SOB)
💰 Ticket prices including class selection
🚃 Train formation – coaches, classes, amenities, accessibility
📦 Open data catalogue – ~90 transport datasets via CKAN
🔑 Graceful degradation – server starts with core tools even without optional API keys
☁️ Dual transport – stdio for Claude Desktop, Streamable HTTP/SSE for cloud deployment
Prerequisites
Python 3.11+
A free API key from api-manager.opentransportdata.swiss (subscribe to OJP 2.0 as minimum)
Optional: additional keys for SIRI-SX, Occupancy, Formation, OJP Fare
Installation
# Clone the repository
git clone https://github.com/malkreide/swiss-transport-mcp.git
cd swiss-transport-mcp
# Install
pip install -e .Or with uvx (no permanent installation):
uvx swiss-transport-mcpQuickstart
# Set the minimum required key (OJP core tools)
export TRANSPORT_API_KEY=your_key_here
# Start the server (stdio mode for Claude Desktop)
swiss-transport-mcpTry it immediately in Claude Desktop:
"What are the next departures from Zurich Stadelhofen?" "How do I get from Wädenswil to Bern by train?"
Configuration
Environment Variables
Variable | API | Required |
| Unified key for OJP + CKAN | ✅ (or individual keys) |
| OJP 2.0 Journey Planner | Optional (override) |
| CKAN data catalogue | Optional (separate subscription) |
| Disruption alerts (SIRI-SX) | Optional |
| Occupancy forecast | Optional |
| Train formation | Optional |
| Ticket prices (OJP Fare) | Optional |
APIs without a key are silently disabled – the server starts fine with just the 6 core tools.
Operational / security variables:
Variable | Effect | Default |
| Process environment. Must be | (unset → production) |
| Set to |
|
| Override the CKAN base URL. Must stay on the egress allow-list ( |
|
| Comma-separated list of browser origins allowed to call the HTTP transport. Use |
|
|
|
|
|
| (off) |
|
| (off → stateful) |
| Comma-separated list of the names this server is reachable under, port included where it matters (e.g. | (unset → off) |
🔒 Egress allow-list: all outbound requests are restricted to
https://onopentransportdata.swisshosts. Any other host is refused before a request is sent (SSRF / egress hardening).
Claude Desktop Configuration
Minimal (core tools only):
{
"mcpServers": {
"swiss-transport": {
"command": "swiss-transport-mcp",
"env": {
"TRANSPORT_API_KEY": "your_key_here"
}
}
}
}Full (all 11 tools):
{
"mcpServers": {
"swiss-transport": {
"command": "swiss-transport-mcp",
"env": {
"TRANSPORT_API_KEY": "your_ojp_key_here",
"SIRI_SX_API_KEY": "your_siri_key_here",
"OCCUPANCY_API_KEY": "your_occupancy_key_here",
"FORMATION_API_KEY": "your_formation_key_here",
"OJP_FARE_API_KEY": "your_fare_key_here"
}
}
}
}Config file locations:
macOS:
~/Library/Application Support/Claude/claude_desktop_config.jsonWindows:
%APPDATA%\Claude\claude_desktop_config.json
Cloud Deployment (Streamable HTTP)
For use via claude.ai in the browser (e.g. on managed workstations without local software). The cloud transport is Streamable HTTP (MCP_TRANSPORT=streamable-http, endpoint /mcp). SSE (/sse) is still supported but deprecated.
| Use | Endpoint |
| Local Claude Desktop subprocess | – |
| Cloud / container (recommended) |
|
| Legacy browser transport (deprecated) |
|
Docker (recommended):
# Build + run with explicit resource limits (see docker-compose.yml)
TRANSPORT_API_KEY=xxx docker compose up --build
# → http://127.0.0.1:8000/mcpThe image is a multi-stage build running as a non-root user; docker-compose.yml adds read_only, no-new-privileges and memory/CPU/PID limits.
Render.com:
Push/fork the repository to GitHub
On render.com: New Web Service → connect GitHub repo (Docker runtime)
Set env
MCP_TRANSPORT=streamable-httpandMCP_HOST=0.0.0.0In claude.ai under Settings → MCP Servers, add:
https://your-app.onrender.com/mcp
💡 "stdio for the developer laptop, Streamable HTTP for the cloud."
Scaling horizontally: run with MCP_STATELESS=1. In stateless mode the
server keeps no per-session state, so any instance can serve any request and a
plain round-robin load balancer suffices — no sticky sessions / Mcp-Session-Id
affinity required. If you need stateful streaming instead, route by
Mcp-Session-Id at the edge LB (e.g. HAProxy stick-tables) so each session
stays pinned to one instance.
⚠️ Binding: In a network transport the server binds to
127.0.0.1by default so a locally started server is not exposed to your whole network (e.g. public Wi-Fi). SetMCP_HOST=0.0.0.0only in a container/cloud environment where binding to all interfaces is intended (the Docker image does this for you).
Available Tools
Core Tools (OJP 2.0 / CKAN)
Tool | Description | Data Source |
| Search stops/stations by name | OJP 2.0 |
| Find nearby stops by coordinates | OJP 2.0 |
| Real-time departure board with delays & platforms | OJP 2.0 |
| Plan journey A → B with transfers, duration, mode | OJP 2.0 |
| Search open data catalogue (~90 datasets) | CKAN¹ |
| Get full details of a specific dataset | CKAN¹ |
¹ CKAN tools require a separate subscription in the API Manager.
Extension Tools (optional API keys)
Tool | Description | Data Source |
| 🚨 Live disruptions, cancellations, line closures | SIRI-SX |
| 📊 Occupancy forecast for specific trains | Occupancy JSON |
| 💰 Ticket prices for connections | OJP Fare |
| 🚃 Train formation, classes, accessibility | Formation REST |
| 🔍 Health check for all configured APIs | All |
Example Use Cases
Query | Tool |
"Next trains from Zurich Stadelhofen?" |
|
"Plan a trip for 25 students from Zurich to Winterthur Technorama" |
|
"Any disruptions between Zurich and Bern?" |
|
"How full is IC 1009 today?" |
|
"What does a ticket from Wädenswil to Bern cost?" |
|
"Does IC 708 have a dining car?" |
|
"Which stops are near Langstrasse 100?" |
|
Architecture
┌─────────────────┐ ┌───────────────────────────┐ ┌──────────────────────────┐
│ Claude / AI │────▶│ Swiss Transport MCP │────▶│ opentransportdata.swiss │
│ (MCP Host) │◀────│ (MCP Server) │◀────│ │
└─────────────────┘ │ │ │ OJP 2.0 (XML/SOAP) │
│ 11 Tools · 2 Resources │ │ SIRI-SX (XML) │
│ Stdio | SSE │ │ CKAN (REST/JSON) │
│ │ │ Occupancy(REST/JSON) │
│ Core: │ │ Formation(REST/JSON) │
│ api_client + ojp_client │ │ OJP Fare (XML/SOAP) │
│ Extensions: │ └──────────────────────────┘
│ siri_sx, occupancy, │
│ ojp_fare, formation │
└───────────────────────────┘Infrastructure Components
Component | Metaphor | Function |
RateLimiter | Bouncer | Limits API calls per time window |
SimpleCache | Whiteboard | Caches responses for repeated queries |
APIClient | Switchboard | Handles auth, redirects, errors centrally |
APIConfig | Business card | Key, URL, limits per API |
Caching Strategy
API | Cache TTL | Rationale |
SIRI-SX | 120s | Disruptions don't change every second |
Occupancy | 300s | Forecasts are day-based |
Formation | 600s | Train composition is stable for the day |
OJP Fare | 1800s | Prices rarely change intraday |
Project Structure
swiss-transport-mcp/
├── src/swiss_transport_mcp/ # Main package
│ ├── server.py # FastMCP server, tool definitions
│ ├── api_client.py # Core OJP + CKAN client
│ ├── ojp_client.py # OJP 2.0 XML/SOAP parser
│ ├── api_infrastructure.py # RateLimiter, SimpleCache, APIClient
│ ├── siri_sx.py # Disruption alerts
│ ├── occupancy.py # Occupancy forecasts
│ ├── ojp_fare.py # Ticket prices
│ └── formation.py # Train formation
├── tests/
│ └── test_server.py # Unit + integration tests
├── .github/workflows/ci.yml # GitHub Actions (Python 3.11/3.12/3.13)
├── claude_desktop_config.json # Example Claude Desktop config
├── pyproject.toml
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md # This file (English)
└── README.de.md # German versionSafety & Limits
Read-only: All tools perform read-only requests (HTTP GET / OJP XML POST for queries only) — no data is written, modified, or deleted on any upstream system.
No personal data: Journey queries are transient and not stored by this server. The APIs return scheduled timetable and real-time operational data. No personally identifiable information (PII) is processed or retained.
Rate limits: opentransportdata.swiss enforces per-key rate limits (documented in the API Manager). The server's built-in
RateLimiter(SIRI-SX: 2 req/min, Formation/OJP Fare: 5 req/min) stays within these bounds automatically. Use thelimitparameters conservatively for bulk queries.API key required: A free key from api-manager.opentransportdata.swiss is mandatory. Keys are bound to your account's subscription — only subscribe to APIs you intend to use.
Data freshness: Real-time tools (departures, disruptions, occupancy) reflect the upstream source at query time. The server caches responses for short TTLs (120s–1800s) to reduce API load — see the Caching Strategy table above.
Terms of service: Data is subject to the ToS of opentransportdata.swiss. OJP, SIRI-SX, and the CKAN catalogue are published under open licences (ODbL / CC BY 4.0) for non-commercial and research use.
No guarantees: This server is a community project, not affiliated with the Federal Office of Transport (BAV/OFT) or SBB. Availability depends on upstream APIs.
Before you install (consent)
Adding this server to your MCP client lets the connected AI model issue Swiss
public-transport queries on your behalf, using your opentransportdata.swiss
API key, and make outbound HTTPS requests to opentransportdata.swiss. Nothing
is written upstream and no PII is stored, but you should review the tool list
above and confirm you are comfortable granting that access before configuring
the server.
Running the HTTP transport safely (no built-in auth)
The server has no authentication of its own. When you run the Streamable
HTTP transport (MCP_TRANSPORT=streamable-http), the MCP SDK issues a
cryptographically random Mcp-Session-Id per session, but there is no user
identity bound to it. Therefore:
Do not expose a no-auth instance directly to the public internet. Put it behind an authenticating reverse proxy (OAuth2 proxy, mTLS, or your platform's access control), or restrict it to a trusted network.
Keep the default
MCP_HOST=127.0.0.1for local use; only bind0.0.0.0inside a controlled container/cloud environment (see Deployment).Scope
MCP_CORS_ORIGINSto the origins you actually trust.Set
MCP_ALLOWED_HOSTSwhenever you bind beyond loopback. It guards against DNS rebinding: a page on your network resolves its own hostname to this server's address and then talks to it from the browser. CORS does not stop that — from the browser's point of view the request is same-origin — and neither would a token, since the attacking page runs in a context that holds one. Only theHostcheck does. Left unset the check stays off, which is the right default only when something in front of the server validatesHost.
See SECURITY.md for the full security posture and the
accepted-risk decisions (gateway-level controls).
Known Limitations
OJP Fare: Discounts (Halbtax, GA, regional passes) are not always reflected
Formation: Stop-based data is only available for TODAY (real-time dependency)
Occupancy: SBB, BLS, Thurbo and SOB only – no private railways
SIRI-SX: Returns ALL Swiss disruptions → use the
filter_textparameterCKAN: Requires a separate subscription in the API Manager
MCP Protocol Version
This server speaks two protocol eras over the same endpoint. The client's first request on a connection decides which one applies; a later claim from the other era is refused.
Era | Revision | Who reaches it |
|
| What today's clients speak. The server answers with the revision asked for, or with the |
Per-request envelope |
| A request carrying the |
Both revisions are pinned in
tests/test_protocol_version.py and asserted
against the installed SDK, so a Dependabot bump of mcp cannot move either one
silently. That pin says which revisions the SDK offers.
That the server actually serves them is measured in
tests/test_modern_wire.py, against the very app
main() hands to uvicorn: real 2026-07-28 single-exchange POSTs — no
initialize, no Mcp-Session-Id — for server/discover, tools/list and a
tools/call, the three rejection rungs (missing envelope, routing header
disagreeing with the body, unserved revision), and a legacy initialize on the
same endpoint to show both eras coexist.
An earlier version of this section claimed the repo built no ASGI app to send a request through, and offered that as the reason the gate could only assert constants. It did build one.
Server identity. 2026-07-28 has no initialize, and so no single place
where a client reads serverInfo. The revision puts the Implementation
(name, title, version, website) into server/discover and into the _meta
of every result instead. This server fills those from its own distribution
metadata, so the version on the wire is the version that was installed — it
cannot drift from pyproject.toml.
Note that the SDK's LATEST_PROTOCOL_VERSION is an alias for the modern
era, not for the handshake era — pinning against it alone would leave the era
that current clients actually negotiate free to drift.
Update policy. When the gate fails, do not edit the constant blindly: read
the spec changelog between the two revisions, verify the server still behaves,
then move the constant, this section, README.de.md and
CHANGELOG.md together.
Testing
# Unit tests (no API key required)
PYTHONPATH=src pytest tests/ -m "not live"
# Integration tests (API key required)
TRANSPORT_API_KEY=xxx pytest tests/ -m "live"Where the test data comes from
All four upstream APIs need a Bearer token from the opentransportdata.swiss
API-Manager, so CI cannot record a real response — measured and kept in
tests/fixtures/upstream_auth_probe.json. The XML payloads in the test modules
are therefore hand-written, not recorded, and cannot refute the production
code: both come from the same reading of the docs, and where both are wrong
they are wrong together.
What can be recorded is the contract. OJP 2.0 is a CEN standard
(CEN/TS 17118) with a public XML schema, and tests/fixtures/ojp_2_0_contract.json
is a dated index derived from it — element names, the structures this server
builds on, the enumerations it sends as values, plus the SHA-256 of every
schema file read. tests/test_ojp_contract.py holds the requests and parsers
against it. The schema itself is deliberately not vendored: the source
repository carries no licence file.
python scripts/record_fixtures.py # re-record
python scripts/record_fixtures.py --check # recompute against the pinned tagSource, date, selection rule and hashes: tests/fixtures/PROVENANCE.md.
Changelog
See CHANGELOG.md
Contributing
See CONTRIBUTING.md
Security
See SECURITY.md (Deutsch) for the security posture and how to report a vulnerability.
License
MIT License — see LICENSE
Author
Hayal Oezkan · github.com/malkreide
Credits & Related Projects
Data: opentransportdata.swiss – Federal Office of Transport (FOT/BAV)
Protocol: Model Context Protocol – Anthropic / Linux Foundation
Related: zurich-opendata-mcp – MCP server for Zurich city open data
Portfolio: Swiss Public Data MCP Portfolio
Installation
Run via uv's uvx — no clone or manual install needed. Add to your MCP client config (mcpServers for Claude Desktop, Cursor and Windsurf; use a top-level servers key for VS Code in .vscode/mcp.json):
{
"mcpServers": {
"swiss-transport-mcp": {
"command": "uvx",
"args": [
"swiss-transport-mcp"
]
}
}
}Available Tools
11 toolscheck_transport_api_statusARead-only
Prüft den Verbindungsstatus aller konfigurierten Transport-APIs.
Zeigt an, welche APIs verfügbar sind, ob die API-Keys gültig sind und ob die Dienste erreichbar sind.
Inputs: no named parameters. Returns: result
get_ticket_priceARead-onlyIdempotent
Ticketpreise für eine ÖV-Verbindung in der Schweiz abfragen.
Berechnet den Fahrpreis für eine Verbindung inklusive Routeninformation. Zeigt reguläre Tarife an. Rabatte (Halbtax, GA) sind möglicherweise nicht vollständig berücksichtigt.
Args: origin: Abfahrtsort (z.B. "Zürich HB", "Wädenswil", "Bern") destination: Ankunftsort (z.B. "Bern", "Luzern", "Basel SBB") departure_time: Abfahrtszeit im Format YYYY-MM-DDTHH:MM (z.B. "2026-03-01T08:00"). Standard: jetzt. travel_class: Reiseklasse. "first" = 1. Klasse, "second" = 2. Klasse.
Beispiele: - Einfache Preisabfrage: get_ticket_price(origin="Zürich HB", destination="Bern") - Mit Zeitangabe: get_ticket_price(origin="Wädenswil", destination="Luzern", departure_time="2026-03-01T08:00") - 1. Klasse: get_ticket_price(origin="Basel SBB", destination="Genf", travel_class="first")
Hinweis: Für verbindliche Preise immer sbb.ch oder den Schalter konsultieren.
Inputs: origin (required), destination (required), travel_class, departure_time. Returns: result
get_train_compositionARead-onlyIdempotent
Zugzusammensetzung und Wagenreihung für einen Schweizer Zug abrufen.
Zeigt die Wagenreihung, Klassen, Sektoren, Ausstattung (Rollstuhlplatz, Velohaken, Speisewagen, Familienzone) und Gleisbelegung an.
Args: train_number: Zugnummer (z.B. "2806", "1009", "708"). Nur die Nummer, ohne Zugtyp-Präfix. railway_company: Eisenbahnunternehmen (EVU). Erlaubt: SBBP (SBB), BLSP (BLS), RhB (Rhätische Bahn), SOB (Südostbahn), THURBO, TPF, TRN, MBC, OeBB, VDBB, ZB. operation_date: Betriebstag YYYY-MM-DD. Standard: heute. Wichtig: Stop-based nur für HEUTE verfügbar. show_details: Detailgrad. "stop_based" = kompakt (empfohlen), "vehicle_based" = pro Fahrzeug, "full" = alles.
Beispiele: - SBB-Zug: get_train_composition(train_number="1009") - BLS-Zug: get_train_composition(train_number="2806", railway_company="BLSP") - Detailliert: get_train_composition(train_number="708", show_details="vehicle_based")
Typische Fragen, die damit beantwortet werden können: - "Hat der IC nach Bern einen Speisewagen?" - "Wo kann ich mit dem Rollstuhl einsteigen?" - "In welchem Sektor hält die 1. Klasse?" - "Gibt es Veloplätze im Zug?"
Inputs: train_number (required), show_details, operation_date, railway_company. Returns: result
get_train_occupancyARead-only
Auslastungsprognose für Schweizer Züge abrufen.
Zeigt, wie voll ein bestimmter Zug voraussichtlich sein wird, aufgeteilt nach 1. und 2. Klasse pro Streckenabschnitt. Auslastungsstufen: wenig belegt, mässig belegt, nur Stehplätze.
Zwei Abfragemodi:
Nach Zugnummer: train_number + operator angeben
Nach Strecke: departure_station + arrival_station angeben
Args: train_number: Zugnummer (z.B. "1009", "IC 708"). Zugtyp-Präfixe werden automatisch entfernt. departure_station: Abfahrtsort für Streckensuche (z.B. "Zürich HB") arrival_station: Ankunftsort für Streckensuche (z.B. "Bern") operation_date: Betriebstag YYYY-MM-DD (Standard: heute). Prognosen sind bis 3 Monate voraus verfügbar. operator: Betreiber-Code. "11"=SBB, "33"=BLS, "65"=Thurbo, "82"=SOB.
Beispiele: - Bestimmter Zug: get_train_occupancy(train_number="1009") - BLS-Zug: get_train_occupancy(train_number="2806", operator="33") - Strecke: get_train_occupancy(departure_station="Zürich HB", arrival_station="Bern")
Inputs: operator, train_number, operation_date, arrival_station, +1 more. Returns: result
get_transport_disruptionsARead-only
Aktuelle Störungsmeldungen im Schweizer öffentlichen Verkehr abrufen.
Liefert Informationen zu Zugausfällen, Verspätungen, Gleisänderungen, Streckensperrungen und anderen Betriebsstörungen.
Args: filter_text: Suchbegriff zum Filtern (z.B. "Zürich", "S-Bahn", "IC 1", "Bern-Thun"). Leer = alle Störungen. language: Sprache der Meldungen. DE (Deutsch), FR (Französisch), IT (Italienisch), EN (Englisch). max_results: Maximale Anzahl Ergebnisse (1-50). Standard: 15.
Beispiele: - Alle aktuellen Störungen: get_transport_disruptions() - Störungen in Zürich: get_transport_disruptions(filter_text="Zürich") - S-Bahn Störungen: get_transport_disruptions(filter_text="S-Bahn") - Strecke prüfen: get_transport_disruptions(filter_text="Bern")
Inputs: language, filter_text, max_results. Returns: result
transport_departuresARead-only
Get upcoming departures or arrivals at a Swiss public transport stop.
Shows real-time information including delays when available. Like a digital departure board at a train station.
Use transport_search_stop first to get the stop_id.
Returns: Departures with line, destination, scheduled time, real-time time, delay, and platform.
Inputs: params (required). Returns: Result of transport_departures.
transport_get_datasetARead-onlyIdempotent
Get full details of a specific transport dataset.
Returns metadata, description, all available resources (files/APIs) with download URLs and formats.
Use transport_search_datasets first to find the dataset ID.
Returns: Full dataset metadata, resources with URLs, and format info.
Inputs: params (required). Returns: Result of transport_get_dataset.
transport_nearby_stopsARead-onlyIdempotent
Find public transport stops near a geographic location.
Useful for finding stops near a school, address, or point of interest. Swiss coordinates only (lat 45–48.5, lon 5.5–10.8).
Returns: Nearby stops with id, name, coordinates, and distance info.
Inputs: params (required). Returns: Result of transport_nearby_stops.
transport_search_datasetsARead-onlyIdempotent
Search the Swiss transport open data catalog (~90 datasets).
Find datasets about timetables, real-time data, GTFS feeds, accessibility info, traffic counters, and more from opentransportdata.swiss.
Returns: Matching datasets with name, description, formats, and download URLs.
Inputs: params (required). Returns: Result of transport_search_datasets.
transport_search_stopARead-onlyIdempotent
Search for Swiss public transport stops and stations by name.
Searches across all Swiss public transport stops (train stations, tram/bus stops, boat stations). Returns stop IDs needed for transport_departures and transport_trip_plan.
Returns: Matching stops with id, name, coordinates, and transport modes.
Inputs: params (required). Returns: Result of transport_search_stop.
transport_trip_planARead-only
Plan a journey between two locations in Switzerland.
Works like the SBB app: enter origin and destination (stop IDs or place names), get multiple trip options with transfers, durations, and transport modes.
For best results, use stop IDs from transport_search_stop. Place names (addresses) also work but may be slower.
Returns: Trip options, each with legs (individual journey segments), total duration, number of transfers, and transport modes used.
Inputs: params (required). Returns: Result of transport_trip_plan.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 11 tools
Each tool has a clearly distinct purpose. Even closely related tools like transport_search_stop and transport_nearby_stops are differentiated by search method (by name vs. by location). No overlapping or ambiguous tools.
Naming is inconsistent: six tools use the 'transport_' prefix, four use 'get_', and one uses 'check_'. The verb-noun pattern is not consistently applied, mixing prefixes and different verb styles.
11 tools is well-scoped for a Swiss transport server. Each tool serves a clear need without being redundant or excessive, covering stops, departures, trips, disruptions, occupancy, prices, composition, and data catalog access.
The tool surface covers all major use cases for Swiss public transport: stop search, nearby stops, departures, trip planning, disruptions, occupancy forecasts, ticket pricing, train composition, and even access to the open data catalog. No obvious gaps for an assistant helping with transport queries.
Maintenance
Related MCP Connectors
Swiss Transport MCP — wraps Transport Open Data API (free, no auth)
Canonical SwissTrip MCP — independent SBB/CFF/FFS schedules, prices, and ticket links by SwissTrip.
Swiss trains and public transport: live connections and departures. Official data, free, no key.
The Ferryhopper MCP server is a connector for LLMs and AI Agents in maritime travel that exposes ferry routes, schedules, and booking options. It enables AI assistants to search ports and connections across 33 countries and 190+ ferry operators, provide real-time ferry itineraries with indicative prices, and assist users with planning island-hopping or multi-leg journeys by processing natural language queries about ferry times, passenger counts, and travel durations.
Related MCP Servers
- AlicenseAqualityDmaintenanceA zero-authentication MCP server for Swiss public transport, enabling users to query train connections, disruptions, station facilities, and plan journeys using natural language.121MIT
- AlicenseAqualityCmaintenanceMCP server for Swiss public transport — connections, stationboards, real-time delays, and direct booking links for SBB.426 PyPI1MIT
- AlicenseAqualityBmaintenanceAn MCP server for Swiss Federal Railways (SBB) open data, enabling AI models to query real-time disruptions, passenger frequencies, station details, and more without an API key.933 PyPI2MIT
- AlicenseNot gradedqualityDmaintenanceProvides real-time Swiss railway information including departures, connections, train composition, occupancy forecasts, disruptions, and pricing, accessible via natural language in over 100 languages.MIT