Skip to main content

MCP Server for Swiss public transport – OJP journey planner, real-time departures, disruptions, occupancy, ticket prices, train formations and open data from opentransportdata.swiss

Project description

🇨🇭 Part of the Swiss Public Data MCP Portfolio

🚆 swiss-transport-mcp

Version License: MIT Python 3.11+ MCP Data Source CI

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.

🇩🇪 Deutsche Version


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


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


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

Quickstart

# 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-mcp

Try 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
TRANSPORT_API_KEY Unified key for OJP + CKAN ✅ (or individual keys)
TRANSPORT_OJP_API_KEY OJP 2.0 Journey Planner Optional (override)
TRANSPORT_CKAN_API_KEY CKAN data catalogue Optional (separate subscription)
SIRI_SX_API_KEY Disruption alerts (SIRI-SX) Optional
OCCUPANCY_API_KEY Occupancy forecast Optional
FORMATION_API_KEY Train formation Optional
OJP_FARE_API_KEY Ticket prices (OJP Fare) Optional

APIs without a key are silently disabled – the server starts fine with just the 6 core tools.

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.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

Cloud Deployment (SSE for browser access)

For use via claude.ai in the browser (e.g. on managed workstations without local software):

Render.com (recommended):

  1. Push/fork the repository to GitHub
  2. On render.com: New Web Service → connect GitHub repo
  3. Render detects render.yaml automatically
  4. Set environment variables in the Render dashboard
  5. In claude.ai under Settings → MCP Servers, add: https://your-app.onrender.com/sse

Docker:

docker build -t swiss-transport-mcp .
docker run -p 8000:8000 \
  -e TRANSPORT_API_KEY=xxx \
  -e SIRI_SX_API_KEY=xxx \
  swiss-transport-mcp

💡 "stdio for the developer laptop, SSE for the browser."


Available Tools

Core Tools (OJP 2.0 / CKAN)

Tool Description Data Source
transport_search_stop Search stops/stations by name OJP 2.0
transport_nearby_stops Find nearby stops by coordinates OJP 2.0
transport_departures Real-time departure board with delays & platforms OJP 2.0
transport_trip_plan Plan journey A → B with transfers, duration, mode OJP 2.0
transport_search_datasets Search open data catalogue (~90 datasets) CKAN¹
transport_get_dataset 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
get_transport_disruptions 🚨 Live disruptions, cancellations, line closures SIRI-SX
get_train_occupancy 📊 Occupancy forecast for specific trains Occupancy JSON
get_ticket_price 💰 Ticket prices for connections OJP Fare
get_train_composition 🚃 Train formation, classes, accessibility Formation REST
check_transport_api_status 🔍 Health check for all configured APIs All

Example Use Cases

Query Tool
"Next trains from Zurich Stadelhofen?" transport_departures
"Plan a trip for 25 students from Zurich to Winterthur Technorama" transport_trip_plan
"Any disruptions between Zurich and Bern?" get_transport_disruptions
"How full is IC 1009 today?" get_train_occupancy
"What does a ticket from Wädenswil to Bern cost?" get_ticket_price
"Does IC 708 have a dining car?" get_train_composition
"Which stops are near Langstrasse 100?" transport_nearby_stops

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 suite
├── Dockerfile                 # Container for cloud deployment
├── render.yaml                # One-click Render.com deployment
├── pyproject.toml             # Build configuration (hatchling)
├── CHANGELOG.md
├── CONTRIBUTING.md
├── LICENSE
├── README.md                  # This file (English)
└── README.de.md               # German version

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_text parameter
  • CKAN: Requires a separate subscription in the API Manager

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"

Changelog

See CHANGELOG.md


License

MIT License — see LICENSE


Author

Hayal Oezkan · github.com/malkreide


Credits & Related Projects

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

swiss_transport_mcp-0.2.0.tar.gz (48.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

swiss_transport_mcp-0.2.0-py3-none-any.whl (46.8 kB view details)

Uploaded Python 3

File details

Details for the file swiss_transport_mcp-0.2.0.tar.gz.

File metadata

  • Download URL: swiss_transport_mcp-0.2.0.tar.gz
  • Upload date:
  • Size: 48.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.7

File hashes

Hashes for swiss_transport_mcp-0.2.0.tar.gz
Algorithm Hash digest
SHA256 254e66e808495d3e179343a521b0f8a1ac175f170cced9a615b727211d09fe0a
MD5 f0113cd47cc5339e7cc01dbdfb1e5db3
BLAKE2b-256 440b456a378a946919f65af52cd12974ca5726002f636059cf0dd7a333b864b2

See more details on using hashes here.

Provenance

The following attestation bundles were made for swiss_transport_mcp-0.2.0.tar.gz:

Publisher: publish.yml on malkreide/swiss-transport-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file swiss_transport_mcp-0.2.0-py3-none-any.whl.

File metadata

File hashes

Hashes for swiss_transport_mcp-0.2.0-py3-none-any.whl
Algorithm Hash digest
SHA256 63868b69006175a265d5d24c1900dade77d021f1ec278c8ffaf3a645d32c76f0
MD5 742646e6186f13c36469c11971ef245e
BLAKE2b-256 1c670bb471de75a84596fca342fddac8fb2bb866c78862f81d6e249ecf48c49e

See more details on using hashes here.

Provenance

The following attestation bundles were made for swiss_transport_mcp-0.2.0-py3-none-any.whl:

Publisher: publish.yml on malkreide/swiss-transport-mcp

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page