sbb-mcp 0.4.2 → 0.5.0

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.
Files changed (74) hide show
  1. package/LICENSE +50 -57
  2. package/README.md +26 -296
  3. package/dist/index.js +47 -17
  4. package/package.json +10 -29
  5. package/dist/auth.d.ts +0 -2
  6. package/dist/auth.js +0 -44
  7. package/dist/auth.js.map +0 -1
  8. package/dist/cache.d.ts +0 -12
  9. package/dist/cache.js +0 -58
  10. package/dist/cache.js.map +0 -1
  11. package/dist/client.d.ts +0 -17
  12. package/dist/client.js +0 -70
  13. package/dist/client.js.map +0 -1
  14. package/dist/formatters.d.ts +0 -22
  15. package/dist/formatters.js +0 -210
  16. package/dist/formatters.js.map +0 -1
  17. package/dist/http.d.ts +0 -2
  18. package/dist/http.js +0 -61
  19. package/dist/http.js.map +0 -1
  20. package/dist/i18n.d.ts +0 -22
  21. package/dist/i18n.js +0 -36
  22. package/dist/i18n.js.map +0 -1
  23. package/dist/index.d.ts +0 -2
  24. package/dist/index.js.map +0 -1
  25. package/dist/journey.d.ts +0 -5
  26. package/dist/journey.js +0 -67
  27. package/dist/journey.js.map +0 -1
  28. package/dist/prices.d.ts +0 -3
  29. package/dist/prices.js +0 -51
  30. package/dist/prices.js.map +0 -1
  31. package/dist/profile.d.ts +0 -16
  32. package/dist/profile.js +0 -77
  33. package/dist/profile.js.map +0 -1
  34. package/dist/rate-limit.d.ts +0 -5
  35. package/dist/rate-limit.js +0 -44
  36. package/dist/rate-limit.js.map +0 -1
  37. package/dist/structured.d.ts +0 -119
  38. package/dist/structured.js +0 -133
  39. package/dist/structured.js.map +0 -1
  40. package/dist/swisstrip.d.ts +0 -41
  41. package/dist/swisstrip.js +0 -119
  42. package/dist/swisstrip.js.map +0 -1
  43. package/dist/tools.d.ts +0 -2
  44. package/dist/tools.js +0 -464
  45. package/dist/tools.js.map +0 -1
  46. package/dist/transport/index.d.ts +0 -9
  47. package/dist/transport/index.js +0 -9
  48. package/dist/transport/index.js.map +0 -1
  49. package/dist/transport/smapi-auth.d.ts +0 -2
  50. package/dist/transport/smapi-auth.js +0 -39
  51. package/dist/transport/smapi-auth.js.map +0 -1
  52. package/dist/transport/smapi-client.d.ts +0 -22
  53. package/dist/transport/smapi-client.js +0 -83
  54. package/dist/transport/smapi-client.js.map +0 -1
  55. package/dist/transport/smapi-journey.d.ts +0 -23
  56. package/dist/transport/smapi-journey.js +0 -82
  57. package/dist/transport/smapi-journey.js.map +0 -1
  58. package/dist/transport/smapi-mock.d.ts +0 -9
  59. package/dist/transport/smapi-mock.js +0 -151
  60. package/dist/transport/smapi-mock.js.map +0 -1
  61. package/dist/transport/smapi-prices.d.ts +0 -14
  62. package/dist/transport/smapi-prices.js +0 -73
  63. package/dist/transport/smapi-prices.js.map +0 -1
  64. package/dist/transport/smapi-types.d.ts +0 -153
  65. package/dist/transport/smapi-types.js +0 -2
  66. package/dist/transport/smapi-types.js.map +0 -1
  67. package/dist/types.d.ts +0 -139
  68. package/dist/types.js +0 -3
  69. package/dist/types.js.map +0 -1
  70. package/dist/widgets.d.ts +0 -33
  71. package/dist/widgets.js +0 -120
  72. package/dist/widgets.js.map +0 -1
  73. package/web/dist/widgets.css +0 -1
  74. package/web/dist/widgets.js +0 -1
package/LICENSE CHANGED
@@ -1,57 +1,50 @@
1
- # Functional Source License, Version 1.1, MIT Future License
2
-
3
- ## Abbreviation
4
- FSL-1.1-MIT
5
-
6
- ## Notice
7
- Copyright 2026 SwissTrip (F. Weinhappl)
8
-
9
- ## Terms and Conditions
10
-
11
- ### Licensor ("We")
12
- The party offering the Software under these Terms and Conditions.
13
-
14
- ### The Software
15
- The "Software" is each version of the software that we make available under these Terms and Conditions, as indicated by our inclusion of these Terms and Conditions with the Software.
16
-
17
- ### License Grant
18
- Subject to your compliance with this License Grant and the Patents, Redistribution and Trademark clauses below, we hereby grant you the right to use, copy, modify, create derivative works, publicly perform, publicly display and redistribute the Software for any Permitted Purpose identified below.
19
-
20
- ### Permitted Purpose
21
- A Permitted Purpose is any purpose other than a Competing Use. A Competing Use means making the Software available to others in a commercial product or service that:
22
-
23
- 1. substitutes for the Software;
24
- 2. substitutes for any other product or service we offer using the Software that exists as of the date we make the Software available; or
25
- 3. offers the same or substantially similar functionality as the Software.
26
-
27
- Permitted Purposes specifically include using the Software:
28
-
29
- 1. for your internal use and access;
30
- 2. for non-commercial education;
31
- 3. for non-commercial research; and
32
- 4. in connection with professional services that you provide to a licensee using the Software in accordance with these Terms and Conditions.
33
-
34
- ### Patents
35
- To the extent your use for a Permitted Purpose would necessarily infringe our patents, the license grant above includes a license under our patents. If you make a claim against any party that the Software infringes or contributes to the infringement of any patent, then your patent license to the Software ends immediately.
36
-
37
- ### Redistribution
38
- The Terms and Conditions apply to all copies, modifications and derivatives of the Software.
39
-
40
- If you redistribute any copies, modifications or derivatives of the Software, you must include a copy of or a link to these Terms and Conditions and not remove any copyright notices provided in or with the Software.
41
-
42
- ### Disclaimer
43
- THE SOFTWARE IS PROVIDED "AS IS" AND WITHOUT WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION WARRANTIES OF FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABILITY, TITLE OR NON-INFRINGEMENT.
44
-
45
- IN NO EVENT WILL WE HAVE ANY LIABILITY TO YOU ARISING OUT OF OR RELATED TO THE SOFTWARE, INCLUDING INDIRECT, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES, EVEN IF WE HAVE BEEN INFORMED OF THEIR POSSIBILITY IN ADVANCE.
46
-
47
- ### Trademarks
48
- Except for displaying the License Details and identifying us as the origin of the Software, you have no right under these Terms and Conditions to use our trademarks, trade names, service marks or product names.
49
-
50
- ## Grant of Future License
51
- We hereby irrevocably grant you an additional license to use the Software under the MIT license that is effective on the second anniversary of the date we make the Software available. On or after that date, you may use the Software under the MIT license, in which case the following will apply:
52
-
53
- Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
54
-
55
- The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
56
-
57
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
1
+ Copyright (c) 2026 F. Weinhappl / SwissTrip
2
+ All Rights Reserved.
3
+
4
+ This software and its source code are proprietary and confidential.
5
+
6
+ No license is granted, express or implied, to use, copy, modify, merge,
7
+ publish, distribute, sublicense, or sell copies of this software, in whole
8
+ or in part, except as explicitly permitted below.
9
+
10
+ PERMITTED USE
11
+ You may install and run unmodified copies of the published npm package
12
+ ("sbb-mcp") solely as a runtime client to connect AI assistants to the
13
+ SwissTrip SBB MCP service hosted at https://mcp.swisstrip.app for
14
+ personal, non-commercial use.
15
+
16
+ PROHIBITED USE
17
+ The following are not permitted without prior written agreement signed by
18
+ F. Weinhappl on behalf of SwissTrip:
19
+ - Redistribution, mirroring, or republication of the source code or
20
+ compiled output, in whole or in part.
21
+ - Use of the source code, in whole or in part, in any other software,
22
+ product, or service.
23
+ - Hosting, operating, or offering a service based on, derived from,
24
+ or substantially similar to this software.
25
+ - Reverse engineering, decompilation, or disassembly, except to the
26
+ extent expressly permitted by mandatory applicable law.
27
+ - Removal, alteration, or obscuring of this license notice or any
28
+ copyright, trademark, or attribution notices.
29
+
30
+ NO WARRANTY
31
+ This software is provided "as is", without warranty of any kind, express
32
+ or implied, including but not limited to the warranties of
33
+ merchantability, fitness for a particular purpose, and non-infringement.
34
+ In no event shall the author or copyright holder be liable for any claim,
35
+ damages, or other liability arising from, out of, or in connection with
36
+ this software or its use.
37
+
38
+ GOVERNING LAW
39
+ This License shall be governed by and construed in accordance with the
40
+ laws of Switzerland, without regard to its conflict of law provisions.
41
+ Any disputes arising under or in connection with this License shall be
42
+ subject to the exclusive jurisdiction of the courts of Zurich,
43
+ Switzerland.
44
+
45
+ COMMERCIAL LICENSING
46
+ For commercial licensing, redistribution rights, or any use not covered
47
+ by the permitted use above, contact:
48
+
49
+ F. Weinhappl
50
+ fabsforward2@gmail.com
package/README.md CHANGED
@@ -1,339 +1,69 @@
1
1
  # sbb-mcp
2
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)
3
+ MCP client for the SwissTrip SBB MCP service. Connects AI assistants to live Swiss Federal Railways (SBB / CFF / FFS) data: train schedules, station search, ticket prices, and direct ticket purchase links.
6
4
 
7
- MCP server for **Swiss Federal Railways** (SBB/CFF/FFS) -- real-time train schedules, prices, and ticket purchase links for any AI assistant.
5
+ The package is a thin client. All SBB API access, ticketing, and profile sync run on the hosted SwissTrip server at `https://mcp.swisstrip.app/mcp`.
8
6
 
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
7
+ ## Install
27
8
 
28
9
  ### Claude Desktop
29
10
 
30
- Add to your `claude_desktop_config.json`:
11
+ Add to `claude_desktop_config.json`:
31
12
 
32
13
  ```json
33
14
  {
34
15
  "mcpServers": {
35
16
  "sbb": {
36
17
  "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
- }
18
+ "args": ["-y", "sbb-mcp"]
44
19
  }
45
20
  }
46
21
  }
47
22
  ```
48
23
 
49
- ### Claude Code
50
-
51
- ```bash
52
- claude mcp add sbb -- npx -y sbb-mcp
53
- ```
54
-
55
24
  ### Cursor
56
25
 
57
- Add to `.cursor/mcp.json`:
26
+ Add to `~/.cursor/mcp.json`:
58
27
 
59
28
  ```json
60
29
  {
61
30
  "mcpServers": {
62
31
  "sbb": {
63
32
  "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
- }
33
+ "args": ["-y", "sbb-mcp"]
71
34
  }
72
35
  }
73
36
  }
74
37
  ```
75
38
 
76
- ### Windsurf
39
+ ### ChatGPT (Plus / Pro / Business / Enterprise with Developer Mode)
77
40
 
78
- Add to `~/.codeium/windsurf/mcp_config.json`:
41
+ No install required. Add a custom connector pointing at:
79
42
 
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
43
  ```
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" }
44
+ https://mcp.swisstrip.app/mcp
153
45
  ```
154
46
 
155
47
  ## Tools
156
48
 
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
49
+ - `search_stations` — find Swiss stations, addresses, and points of interest
50
+ - `search_connections` — train schedules between two stations
51
+ - `get_trip_details` detailed trip with all intermediate stops
52
+ - `get_more_connections` — earlier or later trains for a previous search
53
+ - `get_prices` — ticket prices with Halbtax / GA discounts
54
+ - `get_ticket_link` direct purchase link to SBB.ch
55
+ - `save_profile` / `get_profile` save your travel profile locally
56
+ - `list_travelers` — multi-traveler family pricing (requires `SWISSTRIP_TOKEN`)
188
57
 
189
- ### get_more_connections
58
+ ## Optional configuration
190
59
 
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).
60
+ | Environment variable | Purpose |
61
+ |---|---|
62
+ | `SWISSTRIP_TOKEN` | Sync your traveler profile from your SwissTrip account. Mint at https://swisstrip.app/settings/developer. |
63
+ | `SBB_MCP_URL` | Override the hosted server URL. Default: `https://mcp.swisstrip.app/mcp`. |
336
64
 
337
65
  ## License
338
66
 
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.
67
+ Proprietary. See [LICENSE](./LICENSE). © 2026 SwissTrip.
68
+
69
+ For commercial licensing inquiries: fabsforward2@gmail.com.
package/dist/index.js CHANGED
@@ -1,25 +1,55 @@
1
1
  #!/usr/bin/env node
2
+ /**
3
+ * sbb-mcp — stdio→HTTPS proxy.
4
+ *
5
+ * Forwards every MCP request from a local stdio transport (Claude Desktop,
6
+ * Cursor, etc.) to the hosted SwissTrip SBB MCP server. All SBB API access,
7
+ * ticketing, profile sync, and rendering happen on the server. This client
8
+ * holds no credentials and no business logic.
9
+ *
10
+ * Override the server URL with SBB_MCP_URL.
11
+ * Pass an optional SwissTrip account token via SWISSTRIP_TOKEN to enable
12
+ * cloud-synced profiles and multi-traveler pricing.
13
+ */
14
+ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
15
+ import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
16
+ import { Server } from '@modelcontextprotocol/sdk/server/index.js';
2
17
  import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
3
- import { isSmapiConfigured } from './transport/index.js';
4
- import { isSwissTripConfigured } from './swisstrip.js';
5
- import { createSbbMcpServer } from './tools.js';
18
+ import { CallToolRequestSchema, GetPromptRequestSchema, ListPromptsRequestSchema, ListResourcesRequestSchema, ListResourceTemplatesRequestSchema, ListToolsRequestSchema, ReadResourceRequestSchema, SubscribeRequestSchema, UnsubscribeRequestSchema, } from '@modelcontextprotocol/sdk/types.js';
19
+ const REMOTE_URL = process.env.SBB_MCP_URL ?? 'https://mcp.swisstrip.app/mcp';
20
+ const NAME = 'sbb-mcp';
21
+ const VERSION = '0.5.0';
6
22
  async function main() {
7
- const server = createSbbMcpServer();
8
- const transport = new StdioServerTransport();
9
- await server.connect(transport);
10
- if (!isSmapiConfigured()) {
11
- console.error('[sbb-mcp] Running in MOCK mode (no SMAPI credentials configured)');
12
- console.error('[sbb-mcp] Set SMAPI_CLIENT_ID, SMAPI_CLIENT_SECRET, SMAPI_SCOPE for live data');
13
- }
14
- else {
15
- console.error('[sbb-mcp] Connected to SBB SMAPI');
16
- }
17
- if (isSwissTripConfigured()) {
18
- console.error('[sbb-mcp] SwissTrip cloud profiles enabled (SWISSTRIP_TOKEN set)');
23
+ const headers = {};
24
+ if (process.env.SWISSTRIP_TOKEN) {
25
+ headers.Authorization = `Bearer ${process.env.SWISSTRIP_TOKEN}`;
19
26
  }
27
+ // Upstream client — connects to the hosted MCP server over HTTPS.
28
+ // Client capabilities advertise what THIS side supports; we don't expose
29
+ // sampling or roots, so an empty bag is correct.
30
+ const upstream = new Client({ name: `${NAME}-proxy`, version: VERSION }, { capabilities: {} });
31
+ await upstream.connect(new StreamableHTTPClientTransport(new URL(REMOTE_URL), {
32
+ requestInit: { headers },
33
+ }));
34
+ // Local stdio server — what Claude Desktop / Cursor talk to.
35
+ const server = new Server({ name: NAME, version: VERSION }, { capabilities: { tools: {}, resources: { subscribe: true }, prompts: {} } });
36
+ // Forward every MCP request type to the upstream server.
37
+ server.setRequestHandler(ListToolsRequestSchema, () => upstream.listTools());
38
+ server.setRequestHandler(CallToolRequestSchema, (req) => upstream.callTool(req.params));
39
+ server.setRequestHandler(ListResourcesRequestSchema, () => upstream.listResources());
40
+ server.setRequestHandler(ListResourceTemplatesRequestSchema, () => upstream.listResourceTemplates());
41
+ server.setRequestHandler(ReadResourceRequestSchema, (req) => upstream.readResource(req.params));
42
+ server.setRequestHandler(SubscribeRequestSchema, (req) => upstream.subscribeResource(req.params));
43
+ server.setRequestHandler(UnsubscribeRequestSchema, (req) => upstream.unsubscribeResource(req.params));
44
+ server.setRequestHandler(ListPromptsRequestSchema, () => upstream.listPrompts());
45
+ server.setRequestHandler(GetPromptRequestSchema, (req) => upstream.getPrompt(req.params));
46
+ // Forward upstream notifications (progress, list_changed, etc.) back to the agent.
47
+ upstream.fallbackNotificationHandler = async (n) => {
48
+ await server.notification(n);
49
+ };
50
+ await server.connect(new StdioServerTransport());
20
51
  }
21
52
  main().catch((err) => {
22
- console.error('[sbb-mcp] Fatal error:', err);
53
+ console.error('[sbb-mcp]', err instanceof Error ? err.message : err);
23
54
  process.exit(1);
24
55
  });
25
- //# sourceMappingURL=index.js.map
package/package.json CHANGED
@@ -1,31 +1,19 @@
1
1
  {
2
2
  "name": "sbb-mcp",
3
- "version": "0.4.2",
4
- "mcpName": "io.github.Fabsbags/sbb-mcp",
5
- "description": "MCP server for Swiss Federal Railways (SBB/CFF/FFS) — real-time train schedules, prices, and ticket purchase links for any AI assistant",
3
+ "version": "0.5.0",
4
+ "description": "MCP client for the SwissTrip SBB MCP service — connect AI assistants to live Swiss Federal Railways (SBB/CFF/FFS) data: schedules, prices, and ticket links.",
6
5
  "type": "module",
7
6
  "main": "dist/index.js",
8
- "exports": {
9
- ".": "./dist/index.js",
10
- "./transport": "./dist/transport/index.js"
11
- },
12
7
  "bin": {
13
8
  "sbb-mcp": "dist/index.js"
14
9
  },
15
10
  "files": [
16
11
  "dist",
17
- "web/dist",
18
12
  "README.md",
19
13
  "LICENSE"
20
14
  ],
21
15
  "scripts": {
22
- "ensure:i18n": "node scripts/ensure-i18n.cjs",
23
- "build:widgets": "npm --prefix web install --no-audit --no-fund && npm --prefix web run build",
24
- "build:server": "tsc -p tsconfig.build.json",
25
- "build": "npm run ensure:i18n && npm run build:widgets && npm run build:server",
26
- "dev": "tsc -w -p tsconfig.build.json",
27
- "start:http": "node dist/http.js",
28
- "test": "vitest run",
16
+ "build": "tsc",
29
17
  "prepublishOnly": "npm run build"
30
18
  },
31
19
  "keywords": [
@@ -45,31 +33,24 @@
45
33
  "cursor",
46
34
  "model-context-protocol"
47
35
  ],
48
- "author": "SwissTrip <fabsforward2@gmail.com>",
49
- "license": "FSL-1.1-MIT",
36
+ "author": "F. Weinhappl <fabsforward2@gmail.com>",
37
+ "license": "SEE LICENSE IN LICENSE",
50
38
  "repository": {
51
39
  "type": "git",
52
- "url": "https://github.com/Fabsbags/swisstrip-web",
53
- "directory": "packages/sbb-mcp"
40
+ "url": "git+https://github.com/Fabsbags/sbb-mcp.git"
54
41
  },
55
- "homepage": "https://github.com/Fabsbags/swisstrip-web/tree/main/packages/sbb-mcp#readme",
42
+ "homepage": "https://swisstrip.app",
56
43
  "bugs": {
57
- "url": "https://github.com/Fabsbags/swisstrip-web/issues"
44
+ "url": "https://github.com/Fabsbags/sbb-mcp/issues"
58
45
  },
59
46
  "engines": {
60
47
  "node": ">=18"
61
48
  },
62
49
  "dependencies": {
63
- "@modelcontextprotocol/sdk": "^1.12.1",
64
- "express": "^5.1.0",
65
- "sbb-i18n": "^0.1.0",
66
- "swiss-weather-mcp": "^0.1.1",
67
- "zod": "^3.24.4"
50
+ "@modelcontextprotocol/sdk": "^1.12.1"
68
51
  },
69
52
  "devDependencies": {
70
- "@types/express": "^5.0.2",
71
53
  "@types/node": "^22.15.3",
72
- "typescript": "^5.8.3",
73
- "vitest": "^4.1.0"
54
+ "typescript": "^5.8.3"
74
55
  }
75
56
  }
package/dist/auth.d.ts DELETED
@@ -1,2 +0,0 @@
1
- export declare function isSmapiConfigured(): boolean;
2
- export declare function getAccessToken(): Promise<string>;