swiss-transport-mcp
Click on "Install 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-mcpWhat 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) |
π 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.
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
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
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"
]
}
}
}This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/malkreide/swiss-transport-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server