sbb-mcp
MCP server for Swiss Federal Railways (SBB/CFF/FFS) — train schedules, prices, and ticket links for any AI assistant.
sbb-mcp
MCP server for Swiss Federal Railways (SBB/CFF/FFS) -- real-time train schedules, prices, and ticket purchase links for any AI assistant.
Works with Claude Desktop, Claude Code, Cursor, Windsurf, VS Code Copilot, ChatGPT, and any MCP-compatible AI client.
Features
- Search stations -- find any Swiss train station by name
- Train connections -- real-time schedules with departure/arrival times, platforms, transfers
- Ticket prices -- 1st/2nd class with Half-Fare (Halbtax) and GA travelcard support
- Purchase links -- direct deep links to buy tickets on SBB.ch
- Pagination -- browse earlier/later connections
- Trip details -- intermediate stops, occupancy, platform changes
- Journey planning -- built-in prompt for end-to-end trip planning
- Destination weather -- automatic weather forecast for your destination (powered by swiss-weather-mcp)
- Multi-traveler -- family trip pricing when connected to SwissTrip (partner, kids, each with their own reduction card)
- Multilingual -- output in 9 languages: de, fr, it, en, es, pt, ru, ar, zh (v0.4.0+)
- Rich widgets in ChatGPT -- connection cards, trip timelines, price tables, and ticket cards via the OpenAI Apps SDK (v0.4.1+)
- Mock mode -- works without credentials for testing and demos
Quick Start
Claude Desktop
Add to your claude_desktop_config.json:
{
"mcpServers": {
"sbb": {
"command": "npx",
"args": ["-y", "sbb-mcp"],
"env": {
"SMAPI_CLIENT_ID": "your-client-id",
"SMAPI_CLIENT_SECRET": "your-secret",
"SMAPI_SCOPE": "your-scope",
"SMAPI_CONTRACT_ID": "your-contract-id"
}
}
}
}
Claude Code
claude mcp add sbb -- npx -y sbb-mcp
Cursor
Add to .cursor/mcp.json:
{
"mcpServers": {
"sbb": {
"command": "npx",
"args": ["-y", "sbb-mcp"],
"env": {
"SMAPI_CLIENT_ID": "your-client-id",
"SMAPI_CLIENT_SECRET": "your-secret",
"SMAPI_SCOPE": "your-scope",
"SMAPI_CONTRACT_ID": "your-contract-id"
}
}
}
}
Windsurf
Add to ~/.codeium/windsurf/mcp_config.json:
{
"mcpServers": {
"sbb": {
"command": "npx",
"args": ["-y", "sbb-mcp"],
"env": {
"SMAPI_CLIENT_ID": "your-client-id",
"SMAPI_CLIENT_SECRET": "your-secret",
"SMAPI_SCOPE": "your-scope",
"SMAPI_CONTRACT_ID": "your-contract-id"
}
}
}
}
VS Code Copilot
Add to .vscode/mcp.json:
{
"servers": {
"sbb": {
"command": "npx",
"args": ["-y", "sbb-mcp"],
"env": {
"SMAPI_CLIENT_ID": "your-client-id",
"SMAPI_CLIENT_SECRET": "your-secret",
"SMAPI_SCOPE": "your-scope",
"SMAPI_CONTRACT_ID": "your-contract-id"
}
}
}
}
ChatGPT (custom connector)
A hosted HTTPS endpoint is live at https://mcp.swisstrip.app/mcp — no install needed. Requires ChatGPT Plus/Pro/Business/Enterprise with Developer Mode enabled.
- ChatGPT → Settings → Connectors → enable Developer Mode
- Click Add custom connector
- MCP Server URL:
https://mcp.swisstrip.app/mcp - Authentication: None
- Save, then enable the connector via the + button in the composer
Tool responses render as interactive widgets (connection cards, trip details, price tables, ticket cards) via the OpenAI Apps SDK.
Smithery
Install via Smithery:
npx @smithery/cli mcp add fabsforward2-zhoi/sbb-mcp
Demo Mode (No Credentials)
Run without any environment variables to use mock data:
npx sbb-mcp
This lets you test the MCP server with realistic Swiss station data without SBB API credentials.
Multilingual output (v0.4.0+)
Every tool accepts an optional language argument — one of de, fr, it, en, es, pt, ru, ar, zh. This controls the output language for labels, date/time formatting, and the ticket-buy button text. It also sets the Accept-Language header on SBB API calls so station names come back in the requested language where the SBB API supports it (de/fr/it/en).
Resolution order: language arg → saved profile language (save_profile) → English.
// Example: French output
{ "from": "Zurich HB", "to": "Bern", "language": "fr" }
The SBB deep link path uses de/fr/it/en where supported and falls back to en for other languages (SBB.ch serves those four).
Save a default language once per user:
{ "tool": "save_profile", "language": "de" }
Tools
search_stations
Search for Swiss train stations by name. Returns station IDs needed for other tools.
Input:
query(string, required) -- Station name, e.g. "Zurich", "Bern", "Interlaken"limit(number, optional) -- Max results (default: 10)
Example: "Find stations matching Luzern"
search_connections
Find train connections between two stations. Automatically resolves station names to IDs.
Input:
from(string, required) -- Origin station name or ID (e.g. "Zurich HB" or "8503000")to(string, required) -- Destination station name or IDdate(string, optional) -- Travel date YYYY-MM-DDtime(string, optional) -- Departure time HH:MMarrival_time(boolean, optional) -- Treat time as arrival time
Example: "Show me trains from Zurich to Bern tomorrow at 9am"
Results automatically include destination weather when coordinates are available (e.g. Bern weather: 6-18°C, mostly sunny, 10% rain).
get_trip_details
Get detailed stop-by-stop information for a connection including intermediate stops, platforms, and occupancy forecasts.
Input:
trip_id(string, required) -- Trip ID from search_connections
get_more_connections
Load earlier or later trains for a previous search.
Input:
collection_id(string, required) -- Collection ID from search_connectionsdirection("next" | "previous") -- Later or earlier trains
get_prices
Get ticket prices with Swiss reduction card support. Supports multi-traveler family pricing when connected to SwissTrip.
Input:
trip_ids(string[], required) -- Trip IDs from search_connectionstraveler_type("ADULT" | "CHILD", default: "ADULT") -- used when no traveler_names givenreduction_card("HALF_FARE" | "GA" | "NONE", default: "HALF_FARE") -- used when no traveler_names giventraveler_names(string[], optional) -- SwissTrip traveler names for family pricing (requiresSWISSTRIP_TOKEN)
Example: "How much for Zurich to Zermatt for Fabian and Anna?" (with SwissTrip connected, each traveler's reduction card is applied automatically)
get_ticket_link
Get a direct purchase link to buy the ticket on SBB.ch. On mobile with the SBB app installed, opens directly in the app with Halbtax/GA applied automatically. Supports multi-traveler tickets when connected to SwissTrip.
Input:
trip_id(string, required) -- Trip ID to purchasefrom_name(string, required) -- Origin station namefrom_id(string, required) -- Origin station IDto_name(string, required) -- Destination station nameto_id(string, required) -- Destination station IDdate(string, required) -- Travel date YYYY-MM-DDtime(string, required) -- Departure time HH:MMtraveler_type("ADULT" | "CHILD", default: "ADULT") -- used when no traveler_names givenreduction_card("HALF_FARE" | "GA" | "NONE", default: "HALF_FARE") -- used when no traveler_names giventraveler_names(string[], optional) -- SwissTrip traveler names for family tickets (requiresSWISSTRIP_TOKEN)
save_profile
Save the user's travel profile locally so future sessions can apply the correct reduction card and age-based pricing automatically. Stored at ~/.sbb-mcp/profile.json (or synced from SwissTrip when SWISSTRIP_TOKEN is set).
Input (all optional — supply what the user provides):
first_name(string) -- First name (for ticket booking)last_name(string) -- Last name (for ticket booking)date_of_birth(string) -- YYYY-MM-DD (for age-based pricing)reduction_card("HALF_FARE" | "GA" | "NONE") -- Halbtax, GA, or nonereduction_card_valid_until(string) -- YYYY-MM-DD card expiry
Example: "I'm Fabian Weinhappl, born 1989-06-14, I have a Halbtax until 2027-03-01" → profile saved for future price calls.
get_profile
Read the saved travel profile. Useful to call before get_prices / get_ticket_link so the right reduction card is applied without re-asking the user. Returns guidance to call save_profile when no profile exists.
Example: "What's my reduction card on file?"
list_travelers
List all travelers in the user's SwissTrip account (self, partner, kids). Each traveler has their own reduction card. Requires SWISSTRIP_TOKEN.
Example: "Who are my travelers?" → shows all saved travelers with their reduction cards
Prompts
plan_journey
End-to-end journey planning prompt. Searches connections, compares prices, and provides ticket links.
Input:
from(string, required) -- Origin stationto(string, required) -- Destination stationdate(string, optional) -- Travel date
Environment Variables
| Variable | Required | Description |
|---|---|---|
SMAPI_CLIENT_ID | Yes* | OAuth 2.0 client ID from SBB Developer Portal |
SMAPI_CLIENT_SECRET | Yes* | OAuth 2.0 client secret |
SMAPI_SCOPE | Yes* | OAuth scope |
SMAPI_CONTRACT_ID | Yes* | SBB business contract ID |
SMAPI_ENV | No | int (default) or prod |
SMAPI_TENANT_ID | No | Azure AD tenant (defaults to SBB tenant) |
SWISSTRIP_TOKEN | No | SwissTrip auth token for cloud profiles and multi-traveler support |
SWISSTRIP_URL | No | SwissTrip API base URL (defaults to https://swisstrip.ch) |
*Without SMAPI credentials, the server runs in mock mode with realistic demo data.
SwissTrip Integration (Optional)
Set SWISSTRIP_TOKEN to connect sbb-mcp to your SwissTrip account. This enables:
- Cloud-synced profiles -- your travel profile (name, DOB, reduction card) syncs from SwissTrip instead of local
~/.sbb-mcp/profile.json - Multi-traveler pricing -- add your partner, kids, or travel companions on SwissTrip and get per-person pricing with correct reduction cards
- Family tickets -- pass
traveler_namestoget_pricesandget_ticket_linkfor group pricing
{
"mcpServers": {
"sbb": {
"command": "npx",
"args": ["-y", "sbb-mcp"],
"env": {
"SMAPI_CLIENT_ID": "your-client-id",
"SMAPI_CLIENT_SECRET": "your-secret",
"SMAPI_SCOPE": "your-scope",
"SWISSTRIP_TOKEN": "your-swisstrip-auth-token"
}
}
}
}
Without SWISSTRIP_TOKEN, sbb-mcp uses local file-based profiles as before -- no SwissTrip account required.
Available on
- npm
- Official MCP Registry
- Smithery
- ChatGPT custom connector at
https://mcp.swisstrip.app/mcp(Plus/Pro/Business/Enterprise — rich widgets)
Also available under these alias names on npm (all forward to sbb-mcp): swiss-rail-mcp | sbb-cff-ffs-mcp | swiss-train-mcp | swiss-railways-mcp
Not affiliated with SBB.
sbb-mcpis an independent, community-maintained MCP server built on SBB's public Swiss Mobility API (SMAPI). It is not affiliated with or endorsed by SBB (Schweizerische Bundesbahnen).
About
Built on the official SBB Swiss Mobility API (SMAPI) with OSDM-compliant journey planning and pricing. Covers the entire Swiss public transport network including SBB, BLS, SOB, and regional operators. Weather data powered by swiss-weather-mcp (MeteoSwiss + Open-Meteo).
SBB (Schweizerische Bundesbahnen) / CFF (Chemins de fer federaux suisses) / FFS (Ferrovie federali svizzere) -- Swiss Federal Railways operates one of the densest rail networks in the world with over 10,000 daily connections.
Changelog
v0.4.2 — Repository metadata
- Point
repository,homepage, andbugsfields at the monorepo source of truth (Fabsbags/swisstrip-web, directorypackages/sbb-mcp) so npm and MCP registries link to the active code. No runtime or API changes.
v0.4.1 — Apps SDK widgets
- Five Preact widgets registered as
ui://widget/*.htmlresources: stations list, connection list, trip details, prices table, ticket card. - Tool responses now include
structuredContent+_meta["openai/outputTemplate"]so ChatGPT renders rich UI instead of plain markdown. - Hosted endpoint live at
https://mcp.swisstrip.app/mcpfor use as a ChatGPT custom connector. - Widget bundle built separately via Vite under
web/(single IIFE, inlined CSS, ~25 KB total). - Server rendering is unchanged for non-Apps-SDK clients (Claude Desktop, Cursor, etc.) — they see the same markdown output as before.
v0.4.0 — Multilingual
- Every tool now accepts an optional
languageparameter (de | fr | it | en | es | pt | ru | ar | zh). - Labels, date/time formatting, and the SBB ticket-buy button text are translated.
Accept-Languageis passed to SBB SMAPI so station names come back in the requested language where supported (de/fr/it/en).save_profilestores a preferred language; later tool calls default to it whenlanguageis omitted.- Breaking: default output locale with no profile and no tool arg is now
en(was implicitlyde-CH). Set a profile or passlanguage: 'de'to restore the old behavior. - Translations shared with the WhatsApp/Telegram bots via the new
sbb-i18npackage.
v0.3.0 — Destination weather
- Automatic weather forecast appended to
search_connectionsresults viaswiss-weather-mcp.
License
FSL-1.1-MIT -- Functional Source License. Free to use for any non-competing purpose. Converts to MIT after 2 years. See LICENSE for details.
संबंधित सर्वर
Holvi MCP Server
MCP server for Holvi — Finnish business banking for entrepreneurs. View balances, transactions, create and send invoices via AI agents.
Poke-MCP
Fetches Pokémon data from the PokeAPI and exposes it through a standardized MCP interface.
MCP Cookie Server
Provides positive reinforcement to LLMs by awarding 'cookies' as treats.
ClawPay MCP
Non-custodial x402 payment layer for AI agents. Agents sign transactions locally on Base — no custodial infrastructure, no API keys, no KYC.
MCP Marvel Rivals
Provides access to Marvel Rivals game data through a standardized interface.
Nexus Dashboard
A comprehensive Model Context Protocol (MCP) server for Cisco Nexus Dashboard, enabling AI agents like Claude to interact with Nexus Dashboard APIs for intelligent network automation and management.
MCP Minecraft Remote
Remotely control a Minecraft Java Edition server using the Model Context Protocol (MCP).
Haiguitang (Turtle Soup) Game
An MCP server for '海龟汤' (Turtle Soup), a scenario-based reasoning puzzle game.
N.I.N.A. Advanced API
Control the N.I.N.A. (Nighttime Imaging 'N' Astronomy) software through its Advanced API.
xmcp.dev
The TypeScript framework for building & shipping MCP servers