sbb-mcp 0.4.0 → 0.4.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,314 +1,339 @@
1
- # sbb-mcp
2
-
3
- [![npm version](https://img.shields.io/npm/v/sbb-mcp.svg)](https://www.npmjs.com/package/sbb-mcp)
4
- [![License: FSL-1.1-MIT](https://img.shields.io/badge/License-FSL--1.1--MIT-blue.svg)](https://fsl.software/)
5
- [![smithery badge](https://smithery.ai/badge/fabsforward2-zhoi/sbb-mcp)](https://smithery.ai/servers/fabsforward2-zhoi/sbb-mcp)
6
-
7
- MCP server for **Swiss Federal Railways** (SBB/CFF/FFS) -- real-time train schedules, prices, and ticket purchase links for any AI assistant.
8
-
9
- Works with Claude Desktop, Claude Code, Cursor, Windsurf, VS Code Copilot, ChatGPT, and any MCP-compatible AI client.
10
-
11
- ## Features
12
-
13
- - **Search stations** -- find any Swiss train station by name
14
- - **Train connections** -- real-time schedules with departure/arrival times, platforms, transfers
15
- - **Ticket prices** -- 1st/2nd class with Half-Fare (Halbtax) and GA travelcard support
16
- - **Purchase links** -- direct deep links to buy tickets on SBB.ch
17
- - **Pagination** -- browse earlier/later connections
18
- - **Trip details** -- intermediate stops, occupancy, platform changes
19
- - **Journey planning** -- built-in prompt for end-to-end trip planning
20
- - **Destination weather** -- automatic weather forecast for your destination (powered by [swiss-weather-mcp](https://www.npmjs.com/package/swiss-weather-mcp))
21
- - **Multi-traveler** -- family trip pricing when connected to SwissTrip (partner, kids, each with their own reduction card)
22
- - **Multilingual** -- output in 9 languages: de, fr, it, en, es, pt, ru, ar, zh (v0.4.0+)
23
- - **Mock mode** -- works without credentials for testing and demos
24
-
25
- ## Quick Start
26
-
27
- ### Claude Desktop
28
-
29
- Add to your `claude_desktop_config.json`:
30
-
31
- ```json
32
- {
33
- "mcpServers": {
34
- "sbb": {
35
- "command": "npx",
36
- "args": ["-y", "sbb-mcp"],
37
- "env": {
38
- "SMAPI_CLIENT_ID": "your-client-id",
39
- "SMAPI_CLIENT_SECRET": "your-secret",
40
- "SMAPI_SCOPE": "your-scope",
41
- "SMAPI_CONTRACT_ID": "your-contract-id"
42
- }
43
- }
44
- }
45
- }
46
- ```
47
-
48
- ### Claude Code
49
-
50
- ```bash
51
- claude mcp add sbb -- npx -y sbb-mcp
52
- ```
53
-
54
- ### Cursor
55
-
56
- Add to `.cursor/mcp.json`:
57
-
58
- ```json
59
- {
60
- "mcpServers": {
61
- "sbb": {
62
- "command": "npx",
63
- "args": ["-y", "sbb-mcp"],
64
- "env": {
65
- "SMAPI_CLIENT_ID": "your-client-id",
66
- "SMAPI_CLIENT_SECRET": "your-secret",
67
- "SMAPI_SCOPE": "your-scope",
68
- "SMAPI_CONTRACT_ID": "your-contract-id"
69
- }
70
- }
71
- }
72
- }
73
- ```
74
-
75
- ### Windsurf
76
-
77
- Add to `~/.codeium/windsurf/mcp_config.json`:
78
-
79
- ```json
80
- {
81
- "mcpServers": {
82
- "sbb": {
83
- "command": "npx",
84
- "args": ["-y", "sbb-mcp"],
85
- "env": {
86
- "SMAPI_CLIENT_ID": "your-client-id",
87
- "SMAPI_CLIENT_SECRET": "your-secret",
88
- "SMAPI_SCOPE": "your-scope",
89
- "SMAPI_CONTRACT_ID": "your-contract-id"
90
- }
91
- }
92
- }
93
- }
94
- ```
95
-
96
- ### VS Code Copilot
97
-
98
- Add to `.vscode/mcp.json`:
99
-
100
- ```json
101
- {
102
- "servers": {
103
- "sbb": {
104
- "command": "npx",
105
- "args": ["-y", "sbb-mcp"],
106
- "env": {
107
- "SMAPI_CLIENT_ID": "your-client-id",
108
- "SMAPI_CLIENT_SECRET": "your-secret",
109
- "SMAPI_SCOPE": "your-scope",
110
- "SMAPI_CONTRACT_ID": "your-contract-id"
111
- }
112
- }
113
- }
114
- }
115
- ```
116
-
117
- ### Smithery
118
-
119
- Install via [Smithery](https://smithery.ai/servers/fabsforward2-zhoi/sbb-mcp):
120
-
121
- ```bash
122
- npx @smithery/cli mcp add fabsforward2-zhoi/sbb-mcp
123
- ```
124
-
125
- ### Demo Mode (No Credentials)
126
-
127
- Run without any environment variables to use mock data:
128
-
129
- ```bash
130
- npx sbb-mcp
131
- ```
132
-
133
- This lets you test the MCP server with realistic Swiss station data without SBB API credentials.
134
-
135
- ## Multilingual output (v0.4.0+)
136
-
137
- 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).
138
-
139
- Resolution order: `language` arg → saved profile language (`save_profile`) → English.
140
-
141
- ```jsonc
142
- // Example: French output
143
- { "from": "Zurich HB", "to": "Bern", "language": "fr" }
144
- ```
145
-
146
- 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).
147
-
148
- Save a default language once per user:
149
-
150
- ```jsonc
151
- { "tool": "save_profile", "language": "de" }
152
- ```
153
-
154
- ## Tools
155
-
156
- ### search_stations
157
-
158
- Search for Swiss train stations by name. Returns station IDs needed for other tools.
159
-
160
- **Input:**
161
- - `query` (string, required) -- Station name, e.g. "Zurich", "Bern", "Interlaken"
162
- - `limit` (number, optional) -- Max results (default: 10)
163
-
164
- **Example:** "Find stations matching Luzern"
165
-
166
- ### search_connections
167
-
168
- Find train connections between two stations. Automatically resolves station names to IDs.
169
-
170
- **Input:**
171
- - `from` (string, required) -- Origin station name or ID (e.g. "Zurich HB" or "8503000")
172
- - `to` (string, required) -- Destination station name or ID
173
- - `date` (string, optional) -- Travel date YYYY-MM-DD
174
- - `time` (string, optional) -- Departure time HH:MM
175
- - `arrival_time` (boolean, optional) -- Treat time as arrival time
176
-
177
- **Example:** "Show me trains from Zurich to Bern tomorrow at 9am"
178
-
179
- Results automatically include destination weather when coordinates are available (e.g. **Bern weather:** 6-18°C, mostly sunny, 10% rain).
180
-
181
- ### get_trip_details
182
-
183
- Get detailed stop-by-stop information for a connection including intermediate stops, platforms, and occupancy forecasts.
184
-
185
- **Input:**
186
- - `trip_id` (string, required) -- Trip ID from search_connections
187
-
188
- ### get_more_connections
189
-
190
- Load earlier or later trains for a previous search.
191
-
192
- **Input:**
193
- - `collection_id` (string, required) -- Collection ID from search_connections
194
- - `direction` ("next" | "previous") -- Later or earlier trains
195
-
196
- ### get_prices
197
-
198
- Get ticket prices with Swiss reduction card support. Supports multi-traveler family pricing when connected to SwissTrip.
199
-
200
- **Input:**
201
- - `trip_ids` (string[], required) -- Trip IDs from search_connections
202
- - `traveler_type` ("ADULT" | "CHILD", default: "ADULT") -- used when no traveler_names given
203
- - `reduction_card` ("HALF_FARE" | "GA" | "NONE", default: "HALF_FARE") -- used when no traveler_names given
204
- - `traveler_names` (string[], optional) -- SwissTrip traveler names for family pricing (requires `SWISSTRIP_TOKEN`)
205
-
206
- **Example:** "How much for Zurich to Zermatt for Fabian and Anna?" (with SwissTrip connected, each traveler's reduction card is applied automatically)
207
-
208
- ### get_ticket_link
209
-
210
- 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.
211
-
212
- **Input:**
213
- - `trip_id` (string, required) -- Trip ID to purchase
214
- - `from_name` (string, required) -- Origin station name
215
- - `from_id` (string, required) -- Origin station ID
216
- - `to_name` (string, required) -- Destination station name
217
- - `to_id` (string, required) -- Destination station ID
218
- - `date` (string, required) -- Travel date YYYY-MM-DD
219
- - `time` (string, required) -- Departure time HH:MM
220
- - `traveler_type` ("ADULT" | "CHILD", default: "ADULT") -- used when no traveler_names given
221
- - `reduction_card` ("HALF_FARE" | "GA" | "NONE", default: "HALF_FARE") -- used when no traveler_names given
222
- - `traveler_names` (string[], optional) -- SwissTrip traveler names for family tickets (requires `SWISSTRIP_TOKEN`)
223
-
224
- ### list_travelers
225
-
226
- List all travelers in the user's SwissTrip account (self, partner, kids). Each traveler has their own reduction card. Requires `SWISSTRIP_TOKEN`.
227
-
228
- **Example:** "Who are my travelers?" → shows all saved travelers with their reduction cards
229
-
230
- ## Prompts
231
-
232
- ### plan_journey
233
-
234
- End-to-end journey planning prompt. Searches connections, compares prices, and provides ticket links.
235
-
236
- **Input:**
237
- - `from` (string, required) -- Origin station
238
- - `to` (string, required) -- Destination station
239
- - `date` (string, optional) -- Travel date
240
-
241
- ## Environment Variables
242
-
243
- | Variable | Required | Description |
244
- |----------|----------|-------------|
245
- | `SMAPI_CLIENT_ID` | Yes* | OAuth 2.0 client ID from SBB Developer Portal |
246
- | `SMAPI_CLIENT_SECRET` | Yes* | OAuth 2.0 client secret |
247
- | `SMAPI_SCOPE` | Yes* | OAuth scope |
248
- | `SMAPI_CONTRACT_ID` | Yes* | SBB business contract ID |
249
- | `SMAPI_ENV` | No | `int` (default) or `prod` |
250
- | `SMAPI_TENANT_ID` | No | Azure AD tenant (defaults to SBB tenant) |
251
- | `SWISSTRIP_TOKEN` | No | SwissTrip auth token for cloud profiles and multi-traveler support |
252
- | `SWISSTRIP_URL` | No | SwissTrip API base URL (defaults to `https://swisstrip.ch`) |
253
-
254
- *Without SMAPI credentials, the server runs in mock mode with realistic demo data.
255
-
256
- ## SwissTrip Integration (Optional)
257
-
258
- Set `SWISSTRIP_TOKEN` to connect sbb-mcp to your [SwissTrip](https://swisstrip.ch) account. This enables:
259
-
260
- - **Cloud-synced profiles** -- your travel profile (name, DOB, reduction card) syncs from SwissTrip instead of local `~/.sbb-mcp/profile.json`
261
- - **Multi-traveler pricing** -- add your partner, kids, or travel companions on SwissTrip and get per-person pricing with correct reduction cards
262
- - **Family tickets** -- pass `traveler_names` to `get_prices` and `get_ticket_link` for group pricing
263
-
264
- ```json
265
- {
266
- "mcpServers": {
267
- "sbb": {
268
- "command": "npx",
269
- "args": ["-y", "sbb-mcp"],
270
- "env": {
271
- "SMAPI_CLIENT_ID": "your-client-id",
272
- "SMAPI_CLIENT_SECRET": "your-secret",
273
- "SMAPI_SCOPE": "your-scope",
274
- "SWISSTRIP_TOKEN": "your-swisstrip-auth-token"
275
- }
276
- }
277
- }
278
- }
279
- ```
280
-
281
- Without `SWISSTRIP_TOKEN`, sbb-mcp uses local file-based profiles as before -- no SwissTrip account required.
282
-
283
- ## Available on
284
-
285
- - [npm](https://www.npmjs.com/package/sbb-mcp)
286
- - [Official MCP Registry](https://registry.modelcontextprotocol.io)
287
- - [Smithery](https://smithery.ai/servers/fabsforward2-zhoi/sbb-mcp)
288
-
289
- Also available as: [sbb-mcp-official](https://www.npmjs.com/package/sbb-mcp-official) | [swiss-rail-mcp](https://www.npmjs.com/package/swiss-rail-mcp) | [sbb-cff-ffs-mcp](https://www.npmjs.com/package/sbb-cff-ffs-mcp) | [swiss-train-mcp](https://www.npmjs.com/package/swiss-train-mcp) | [swiss-railways-mcp](https://www.npmjs.com/package/swiss-railways-mcp)
290
-
291
- ## About
292
-
293
- 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](https://www.npmjs.com/package/swiss-weather-mcp) (MeteoSwiss + Open-Meteo).
294
-
295
- **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.
296
-
297
- ## Changelog
298
-
299
- ### v0.4.0 — Multilingual
300
-
301
- - Every tool now accepts an optional `language` parameter (`de | fr | it | en | es | pt | ru | ar | zh`).
302
- - Labels, date/time formatting, and the SBB ticket-buy button text are translated.
303
- - `Accept-Language` is passed to SBB SMAPI so station names come back in the requested language where supported (de/fr/it/en).
304
- - `save_profile` stores a preferred language; later tool calls default to it when `language` is omitted.
305
- - **Breaking:** default output locale with no profile and no tool arg is now `en` (was implicitly `de-CH`). Set a profile or pass `language: 'de'` to restore the old behavior.
306
- - Translations shared with the WhatsApp/Telegram bots via the new [`sbb-i18n`](https://www.npmjs.com/package/sbb-i18n) package.
307
-
308
- ### v0.3.0 Destination weather
309
-
310
- - Automatic weather forecast appended to `search_connections` results via [`swiss-weather-mcp`](https://www.npmjs.com/package/swiss-weather-mcp).
311
-
312
- ## License
313
-
314
- [FSL-1.1-MIT](https://fsl.software/) -- Functional Source License. Free to use for any non-competing purpose. Converts to MIT after 2 years. See [LICENSE](LICENSE) for details.
1
+ # sbb-mcp
2
+
3
+ [![npm version](https://img.shields.io/npm/v/sbb-mcp.svg)](https://www.npmjs.com/package/sbb-mcp)
4
+ [![License: FSL-1.1-MIT](https://img.shields.io/badge/License-FSL--1.1--MIT-blue.svg)](https://fsl.software/)
5
+ [![smithery badge](https://smithery.ai/badge/fabsforward2-zhoi/sbb-mcp)](https://smithery.ai/servers/fabsforward2-zhoi/sbb-mcp)
6
+
7
+ MCP server for **Swiss Federal Railways** (SBB/CFF/FFS) -- real-time train schedules, prices, and ticket purchase links for any AI assistant.
8
+
9
+ Works with Claude Desktop, Claude Code, Cursor, Windsurf, VS Code Copilot, ChatGPT, and any MCP-compatible AI client.
10
+
11
+ ## Features
12
+
13
+ - **Search stations** -- find any Swiss train station by name
14
+ - **Train connections** -- real-time schedules with departure/arrival times, platforms, transfers
15
+ - **Ticket prices** -- 1st/2nd class with Half-Fare (Halbtax) and GA travelcard support
16
+ - **Purchase links** -- direct deep links to buy tickets on SBB.ch
17
+ - **Pagination** -- browse earlier/later connections
18
+ - **Trip details** -- intermediate stops, occupancy, platform changes
19
+ - **Journey planning** -- built-in prompt for end-to-end trip planning
20
+ - **Destination weather** -- automatic weather forecast for your destination (powered by [swiss-weather-mcp](https://www.npmjs.com/package/swiss-weather-mcp))
21
+ - **Multi-traveler** -- family trip pricing when connected to SwissTrip (partner, kids, each with their own reduction card)
22
+ - **Multilingual** -- output in 9 languages: de, fr, it, en, es, pt, ru, ar, zh (v0.4.0+)
23
+ - **Rich widgets in ChatGPT** -- connection cards, trip timelines, price tables, and ticket cards via the OpenAI Apps SDK (v0.4.1+)
24
+ - **Mock mode** -- works without credentials for testing and demos
25
+
26
+ ## Quick Start
27
+
28
+ ### Claude Desktop
29
+
30
+ Add to your `claude_desktop_config.json`:
31
+
32
+ ```json
33
+ {
34
+ "mcpServers": {
35
+ "sbb": {
36
+ "command": "npx",
37
+ "args": ["-y", "sbb-mcp"],
38
+ "env": {
39
+ "SMAPI_CLIENT_ID": "your-client-id",
40
+ "SMAPI_CLIENT_SECRET": "your-secret",
41
+ "SMAPI_SCOPE": "your-scope",
42
+ "SMAPI_CONTRACT_ID": "your-contract-id"
43
+ }
44
+ }
45
+ }
46
+ }
47
+ ```
48
+
49
+ ### Claude Code
50
+
51
+ ```bash
52
+ claude mcp add sbb -- npx -y sbb-mcp
53
+ ```
54
+
55
+ ### Cursor
56
+
57
+ Add to `.cursor/mcp.json`:
58
+
59
+ ```json
60
+ {
61
+ "mcpServers": {
62
+ "sbb": {
63
+ "command": "npx",
64
+ "args": ["-y", "sbb-mcp"],
65
+ "env": {
66
+ "SMAPI_CLIENT_ID": "your-client-id",
67
+ "SMAPI_CLIENT_SECRET": "your-secret",
68
+ "SMAPI_SCOPE": "your-scope",
69
+ "SMAPI_CONTRACT_ID": "your-contract-id"
70
+ }
71
+ }
72
+ }
73
+ }
74
+ ```
75
+
76
+ ### Windsurf
77
+
78
+ Add to `~/.codeium/windsurf/mcp_config.json`:
79
+
80
+ ```json
81
+ {
82
+ "mcpServers": {
83
+ "sbb": {
84
+ "command": "npx",
85
+ "args": ["-y", "sbb-mcp"],
86
+ "env": {
87
+ "SMAPI_CLIENT_ID": "your-client-id",
88
+ "SMAPI_CLIENT_SECRET": "your-secret",
89
+ "SMAPI_SCOPE": "your-scope",
90
+ "SMAPI_CONTRACT_ID": "your-contract-id"
91
+ }
92
+ }
93
+ }
94
+ }
95
+ ```
96
+
97
+ ### VS Code Copilot
98
+
99
+ Add to `.vscode/mcp.json`:
100
+
101
+ ```json
102
+ {
103
+ "servers": {
104
+ "sbb": {
105
+ "command": "npx",
106
+ "args": ["-y", "sbb-mcp"],
107
+ "env": {
108
+ "SMAPI_CLIENT_ID": "your-client-id",
109
+ "SMAPI_CLIENT_SECRET": "your-secret",
110
+ "SMAPI_SCOPE": "your-scope",
111
+ "SMAPI_CONTRACT_ID": "your-contract-id"
112
+ }
113
+ }
114
+ }
115
+ }
116
+ ```
117
+
118
+ ### Smithery
119
+
120
+ Install via [Smithery](https://smithery.ai/servers/fabsforward2-zhoi/sbb-mcp):
121
+
122
+ ```bash
123
+ npx @smithery/cli mcp add fabsforward2-zhoi/sbb-mcp
124
+ ```
125
+
126
+ ### Demo Mode (No Credentials)
127
+
128
+ Run without any environment variables to use mock data:
129
+
130
+ ```bash
131
+ npx sbb-mcp
132
+ ```
133
+
134
+ This lets you test the MCP server with realistic Swiss station data without SBB API credentials.
135
+
136
+ ## Multilingual output (v0.4.0+)
137
+
138
+ 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).
139
+
140
+ Resolution order: `language` arg → saved profile language (`save_profile`) → English.
141
+
142
+ ```jsonc
143
+ // Example: French output
144
+ { "from": "Zurich HB", "to": "Bern", "language": "fr" }
145
+ ```
146
+
147
+ 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).
148
+
149
+ Save a default language once per user:
150
+
151
+ ```jsonc
152
+ { "tool": "save_profile", "language": "de" }
153
+ ```
154
+
155
+ ## Tools
156
+
157
+ ### search_stations
158
+
159
+ Search for Swiss train stations by name. Returns station IDs needed for other tools.
160
+
161
+ **Input:**
162
+ - `query` (string, required) -- Station name, e.g. "Zurich", "Bern", "Interlaken"
163
+ - `limit` (number, optional) -- Max results (default: 10)
164
+
165
+ **Example:** "Find stations matching Luzern"
166
+
167
+ ### search_connections
168
+
169
+ Find train connections between two stations. Automatically resolves station names to IDs.
170
+
171
+ **Input:**
172
+ - `from` (string, required) -- Origin station name or ID (e.g. "Zurich HB" or "8503000")
173
+ - `to` (string, required) -- Destination station name or ID
174
+ - `date` (string, optional) -- Travel date YYYY-MM-DD
175
+ - `time` (string, optional) -- Departure time HH:MM
176
+ - `arrival_time` (boolean, optional) -- Treat time as arrival time
177
+
178
+ **Example:** "Show me trains from Zurich to Bern tomorrow at 9am"
179
+
180
+ Results automatically include destination weather when coordinates are available (e.g. **Bern weather:** 6-18°C, mostly sunny, 10% rain).
181
+
182
+ ### get_trip_details
183
+
184
+ Get detailed stop-by-stop information for a connection including intermediate stops, platforms, and occupancy forecasts.
185
+
186
+ **Input:**
187
+ - `trip_id` (string, required) -- Trip ID from search_connections
188
+
189
+ ### get_more_connections
190
+
191
+ Load earlier or later trains for a previous search.
192
+
193
+ **Input:**
194
+ - `collection_id` (string, required) -- Collection ID from search_connections
195
+ - `direction` ("next" | "previous") -- Later or earlier trains
196
+
197
+ ### get_prices
198
+
199
+ Get ticket prices with Swiss reduction card support. Supports multi-traveler family pricing when connected to SwissTrip.
200
+
201
+ **Input:**
202
+ - `trip_ids` (string[], required) -- Trip IDs from search_connections
203
+ - `traveler_type` ("ADULT" | "CHILD", default: "ADULT") -- used when no traveler_names given
204
+ - `reduction_card` ("HALF_FARE" | "GA" | "NONE", default: "HALF_FARE") -- used when no traveler_names given
205
+ - `traveler_names` (string[], optional) -- SwissTrip traveler names for family pricing (requires `SWISSTRIP_TOKEN`)
206
+
207
+ **Example:** "How much for Zurich to Zermatt for Fabian and Anna?" (with SwissTrip connected, each traveler's reduction card is applied automatically)
208
+
209
+ ### get_ticket_link
210
+
211
+ 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.
212
+
213
+ **Input:**
214
+ - `trip_id` (string, required) -- Trip ID to purchase
215
+ - `from_name` (string, required) -- Origin station name
216
+ - `from_id` (string, required) -- Origin station ID
217
+ - `to_name` (string, required) -- Destination station name
218
+ - `to_id` (string, required) -- Destination station ID
219
+ - `date` (string, required) -- Travel date YYYY-MM-DD
220
+ - `time` (string, required) -- Departure time HH:MM
221
+ - `traveler_type` ("ADULT" | "CHILD", default: "ADULT") -- used when no traveler_names given
222
+ - `reduction_card` ("HALF_FARE" | "GA" | "NONE", default: "HALF_FARE") -- used when no traveler_names given
223
+ - `traveler_names` (string[], optional) -- SwissTrip traveler names for family tickets (requires `SWISSTRIP_TOKEN`)
224
+
225
+ ### list_travelers
226
+
227
+ List all travelers in the user's SwissTrip account (self, partner, kids). Each traveler has their own reduction card. Requires `SWISSTRIP_TOKEN`.
228
+
229
+ **Example:** "Who are my travelers?" → shows all saved travelers with their reduction cards
230
+
231
+ ## Prompts
232
+
233
+ ### plan_journey
234
+
235
+ End-to-end journey planning prompt. Searches connections, compares prices, and provides ticket links.
236
+
237
+ **Input:**
238
+ - `from` (string, required) -- Origin station
239
+ - `to` (string, required) -- Destination station
240
+ - `date` (string, optional) -- Travel date
241
+
242
+ ## Environment Variables
243
+
244
+ | Variable | Required | Description |
245
+ |----------|----------|-------------|
246
+ | `SMAPI_CLIENT_ID` | Yes* | OAuth 2.0 client ID from SBB Developer Portal |
247
+ | `SMAPI_CLIENT_SECRET` | Yes* | OAuth 2.0 client secret |
248
+ | `SMAPI_SCOPE` | Yes* | OAuth scope |
249
+ | `SMAPI_CONTRACT_ID` | Yes* | SBB business contract ID |
250
+ | `SMAPI_ENV` | No | `int` (default) or `prod` |
251
+ | `SMAPI_TENANT_ID` | No | Azure AD tenant (defaults to SBB tenant) |
252
+ | `SWISSTRIP_TOKEN` | No | SwissTrip auth token for cloud profiles and multi-traveler support |
253
+ | `SWISSTRIP_URL` | No | SwissTrip API base URL (defaults to `https://swisstrip.ch`) |
254
+
255
+ *Without SMAPI credentials, the server runs in mock mode with realistic demo data.
256
+
257
+ ## SwissTrip Integration (Optional)
258
+
259
+ Set `SWISSTRIP_TOKEN` to connect sbb-mcp to your [SwissTrip](https://swisstrip.ch) account. This enables:
260
+
261
+ - **Cloud-synced profiles** -- your travel profile (name, DOB, reduction card) syncs from SwissTrip instead of local `~/.sbb-mcp/profile.json`
262
+ - **Multi-traveler pricing** -- add your partner, kids, or travel companions on SwissTrip and get per-person pricing with correct reduction cards
263
+ - **Family tickets** -- pass `traveler_names` to `get_prices` and `get_ticket_link` for group pricing
264
+
265
+ ```json
266
+ {
267
+ "mcpServers": {
268
+ "sbb": {
269
+ "command": "npx",
270
+ "args": ["-y", "sbb-mcp"],
271
+ "env": {
272
+ "SMAPI_CLIENT_ID": "your-client-id",
273
+ "SMAPI_CLIENT_SECRET": "your-secret",
274
+ "SMAPI_SCOPE": "your-scope",
275
+ "SWISSTRIP_TOKEN": "your-swisstrip-auth-token"
276
+ }
277
+ }
278
+ }
279
+ }
280
+ ```
281
+
282
+ Without `SWISSTRIP_TOKEN`, sbb-mcp uses local file-based profiles as before -- no SwissTrip account required.
283
+
284
+ ## Available on
285
+
286
+ - [npm](https://www.npmjs.com/package/sbb-mcp)
287
+ - [Official MCP Registry](https://registry.modelcontextprotocol.io)
288
+ - [Smithery](https://smithery.ai/servers/fabsforward2-zhoi/sbb-mcp)
289
+
290
+ Also available as: [sbb-mcp-official](https://www.npmjs.com/package/sbb-mcp-official) | [swiss-rail-mcp](https://www.npmjs.com/package/swiss-rail-mcp) | [sbb-cff-ffs-mcp](https://www.npmjs.com/package/sbb-cff-ffs-mcp) | [swiss-train-mcp](https://www.npmjs.com/package/swiss-train-mcp) | [swiss-railways-mcp](https://www.npmjs.com/package/swiss-railways-mcp)
291
+
292
+ ## About
293
+
294
+ 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](https://www.npmjs.com/package/swiss-weather-mcp) (MeteoSwiss + Open-Meteo).
295
+
296
+ **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.
297
+
298
+ ## ChatGPT (custom connector)
299
+
300
+ A hosted HTTPS endpoint is available at `https://mcp.swisstrip.app/mcp` for use as a custom connector in ChatGPT (requires Plus/Pro/Business/Enterprise with Developer Mode enabled).
301
+
302
+ 1. ChatGPT **Settings Connectors** enable **Developer Mode**
303
+ 2. Click **Add custom connector**
304
+ 3. **MCP Server URL:** `https://mcp.swisstrip.app/mcp`
305
+ 4. **Authentication:** None
306
+ 5. Save, then enable the connector via the **+** button in the composer
307
+
308
+ Tool responses render as interactive widgets (connection cards, trip details, price tables, ticket cards) using the OpenAI Apps SDK.
309
+
310
+ ## Changelog
311
+
312
+ ### v0.4.2 — Repository metadata
313
+
314
+ - Point `repository`, `homepage`, and `bugs` fields at the monorepo source of truth (`Fabsbags/swisstrip-web`, directory `packages/sbb-mcp`) so npm and MCP registries link to the active code. No runtime or API changes.
315
+
316
+ ### v0.4.1 — Apps SDK widgets
317
+
318
+ - Five Preact widgets registered as `ui://widget/*.html` resources: stations list, connection list, trip details, prices table, ticket card.
319
+ - Tool responses now include `structuredContent` + `_meta["openai/outputTemplate"]` so ChatGPT renders rich UI instead of plain markdown.
320
+ - Hosted endpoint live at `https://mcp.swisstrip.app/mcp` for use as a ChatGPT custom connector.
321
+ - Widget bundle built separately via Vite under `web/` (single IIFE, inlined CSS, ~25 KB total).
322
+ - Server rendering is unchanged for non-Apps-SDK clients (Claude Desktop, Cursor, etc.) — they see the same markdown output as before.
323
+
324
+ ### v0.4.0 — Multilingual
325
+
326
+ - Every tool now accepts an optional `language` parameter (`de | fr | it | en | es | pt | ru | ar | zh`).
327
+ - Labels, date/time formatting, and the SBB ticket-buy button text are translated.
328
+ - `Accept-Language` is passed to SBB SMAPI so station names come back in the requested language where supported (de/fr/it/en).
329
+ - `save_profile` stores a preferred language; later tool calls default to it when `language` is omitted.
330
+ - **Breaking:** default output locale with no profile and no tool arg is now `en` (was implicitly `de-CH`). Set a profile or pass `language: 'de'` to restore the old behavior.
331
+ - Translations shared with the WhatsApp/Telegram bots via the new [`sbb-i18n`](https://www.npmjs.com/package/sbb-i18n) package.
332
+
333
+ ### v0.3.0 — Destination weather
334
+
335
+ - Automatic weather forecast appended to `search_connections` results via [`swiss-weather-mcp`](https://www.npmjs.com/package/swiss-weather-mcp).
336
+
337
+ ## License
338
+
339
+ [FSL-1.1-MIT](https://fsl.software/) -- Functional Source License. Free to use for any non-competing purpose. Converts to MIT after 2 years. See [LICENSE](LICENSE) for details.