mcpField
S
swiss-transport-mcp

swiss-transport-mcp

本地服务
github.com地图与出行82 周前更新

关于 swiss-transport-mcp

swiss-transport-mcp 为出行者和 AI 助手提供瑞士公共交通查询,涵盖行程、实时班次及多种交通数据。它将 OJP 2.0、SIRI-SX 和 REST 等接口转换为 JSON,并支持本地与云端传输。

主要功能

  1. 01行程规划与实时班次
  2. 02站点名称和坐标搜索
  3. 03实时延误与中断信息
  4. 04列车拥挤度和票价查询
  5. 05列车编组与开放数据查询

适用场景

  1. 01规划含换乘的瑞士铁路行程
  2. 02查询车站下一班车及站台
  3. 03确认线路中断和列车拥挤度
  4. 04查询票价、车厢设施或交通数据集

MCP 相关

该 MCP 服务向兼容客户端提供交通查询工具和资源,数据来自瑞士公共交通开放数据接口。支持 stdio 和 Streamable HTTP 传输,部分扩展工具需单独 API 密钥。

配置

本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。

mcp.json · 通用配置
{
"mcpServers": {
"malkreide-swiss-transport": {
"command": "uvx",
"args": [
"swiss-transport-mcp"
]
}
}
}
启动命令uvx swiss-transport-mcp

本地服务需要在你的电脑上安装运行环境(如 Node.js 18+)。各客户端的配置文件位置不同,请参考客户端文档。

安装包
pypiswiss-transport-mcp0.5.0

工具

11

收录的工具列表 · 更新于 2 周前

参数类型必填说明
paramsany是

详细介绍

🇨🇭 属于 瑞士公共数据 MCP 产品组合

🚆 swiss-transport-mcp

版本 许可证:MIT Python 3.11+ MCP 数据来源 CI

连接 AI 模型与瑞士公共交通系统的 MCP 服务——提供行程规划、实时发车信息、运营中断、拥挤程度、票价、列车编组和来自 opentransportdata.swiss 的开放数据。

🇩🇪 德语版

演示

演示:Claude 查询运营中断和发车信息


概览

swiss-transport-mcp 为 Claude 等 AI 助手提供完整的瑞士出行信息系统——不仅有时刻表,还有实时运营中断提醒、拥挤程度预测、票价和完整的列车编组视图。所有信息都可通过一个标准化的 MCP 接口访问。

opentransportdata.swiss 上的各类 API 使用不同的协议——OJP 2.0(XML/SOAP)、SIRI-SX(XML)、REST/JSON。此服务会将所有数据转换为简洁的 JSON,供 AI 模型使用,充当多语言协议解释器。

示例演示查询: “为 25 名学生规划从苏黎世前往温特图尔 Technorama 的学校旅行——检查是否有运营中断,并找到最佳发车班次。” → 按受众查看更多使用场景 →


功能

  • 🗺️ 行程规划(A → B,包含换乘、时长、交通方式),通过 OJP 2.0 提供
  • 🕐 实时发车信息,包含延误和站台信息
  • 🔍 站点搜索,可按名称或坐标搜索
  • 🚨 实时运营中断提醒(取消、封闭),通过 SIRI-SX 提供
  • 📊 列车拥挤程度预测(SBB、BLS、Thurbo、SOB)
  • 💰 票价,支持选择舱等
  • 🚃 列车编组——车厢、舱等、设施、无障碍信息
  • 📦 开放数据目录——约 90 个交通数据集,通过 CKAN 提供
  • 🔑 优雅降级——即使没有可选 API 密钥,服务也能通过核心工具启动
  • ☁️ 双传输方式——stdio 用于 Claude Desktop,Streamable HTTP/SSE 用于云端部署

前提条件

  • Python 3.11+
  • 从 api-manager.opentransportdata.swiss 获取免费的 API 密钥(至少订阅 OJP 2.0)
  • 可选:SIRI-SX、Occupancy、Formation、OJP Fare 的其他密钥

安装

# Clone the repository
git clone https://github.com/malkreide/swiss-transport-mcp.git
cd swiss-transport-mcp

# Install
pip install -e .

或者使用 uvx(无需永久安装):

uvx swiss-transport-mcp

快速开始

# 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

立即在 Claude Desktop 中试用:

“苏黎世 Stadelhofen 接下来有哪些发车班次?” “我怎么从 Wädenswil 坐火车去伯尔尼?”


配置

环境变量
变量API必填
TRANSPORT_API_KEYOJP + CKAN 的统一密钥✅(或使用单独的密钥)
TRANSPORT_OJP_API_KEYOJP 2.0 行程规划器可选(覆盖)
TRANSPORT_CKAN_API_KEYCKAN 数据目录可选(单独订阅)
SIRI_SX_API_KEY中断提醒(SIRI-SX)可选
OCCUPANCY_API_KEY客流量预测可选
FORMATION_API_KEY列车编组可选
OJP_FARE_API_KEY票价(OJP Fare)可选

未配置密钥的 API 会静默禁用——仅使用 6 个核心工具,服务也能正常启动。

运行 / 安全变量:

变量作用默认值
MCP_ENV / ENV进程环境。仅当值为 dev/development/local/test 时,才允许禁用 TLS 验证。(未设置 → 生产环境)
TRANSPORT_SSL_VERIFY设置为 false 可禁用 TLS 证书验证。仅当 MCP_ENV 指定为开发环境时才会生效——否则会忽略此设置并继续启用验证。true
TRANSPORT_CKAN_URL覆盖 CKAN 基础 URL。必须在出站允许列表内(*.opentransportdata.swiss);拒绝站外地址。https://api.opentransportdata.swiss/ckan-api
MCP_CORS_ORIGINS允许调用 HTTP 传输的浏览器来源列表,以逗号分隔。使用 * 可允许任意来源(不推荐)。这些来源可读取 Mcp-Session-Id 标头。https://claude.ai
LOG_FORMAT设置为 json 可输出结构化日志(RFC 5424 严重性级别);其他值则输出易读文本。日志始终写入 stderr。text
OTEL_TRACES_ENABLED设置为 1 可启用 OpenTelemetry 跟踪(需要 otel 扩展:pip install 'swiss-transport-mcp[otel]')。否则不执行任何操作。(关闭)
MCP_STATELESS设置为 1 可使 Streamable HTTP 传输以无状态方式运行——不保留服务端会话状态,因此实例无需会话粘性负载均衡。建议用于水平扩展。(关闭 → 有状态)
MCP_ALLOWED_HOSTS此服务可通过其访问的主机名列表,以逗号分隔;必要时包含端口(例如 fahrplan.example.ch:8080)。通过任何其他 Host 发来的请求都会被拒绝,并返回 421;仍允许回环地址,以便容器健康检查正常运行。在非回环地址上监听但未设置此变量时,将关闭检查并记录警告。(未设置 → 关闭)

🔒 **出站允许列表:**所有出站请求都限制为发往 opentransportdata.swiss 主机的 https:// 请求。发送请求前会拒绝任何其他主机(SSRF / 出站流量加固)。

Claude Desktop 配置

最简配置(仅核心工具):

{
  "mcpServers": {
    "swiss-transport": {
      "command": "swiss-transport-mcp",
      "env": {
        "TRANSPORT_API_KEY": "your_key_here"
      }
    }
  }
}

完整配置(全部 11 个工具):

{
  "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"
      }
    }
  }
}

配置文件位置:

  • macOS:~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows:%APPDATA%\Claude\claude_desktop_config.json
云端部署(Streamable HTTP)

适用于通过浏览器中的 claude.ai 使用(例如,在没有本地软件的受管工作站上)。云端传输方式为 Streamable HTTP(MCP_TRANSPORT=streamable-http,端点为 /mcp)。仍支持 SSE(/sse),但已弃用。

MCP_TRANSPORT用途端点
stdio(默认)本地 Claude Desktop 子进程–
streamable-http(或 http)云端/容器(推荐)/mcp
sse旧版浏览器传输方式(已弃用)/sse

Docker(推荐):

# Build + run with explicit resource limits (see docker-compose.yml)
TRANSPORT_API_KEY=xxx docker compose up --build
# → http://127.0.0.1:8000/mcp

该镜像采用多阶段构建,并以非 root 用户身份运行;docker-compose.yml 添加了 read_only、no-new-privileges 以及内存/CPU/PID 限制。

Render.com:

  1. 将仓库推送到 GitHub 或从中派生仓库
  2. 在 render.com 上:新建 Web 服务 → 连接 GitHub 仓库(Docker 运行时)
  3. 设置环境变量 MCP_TRANSPORT=streamable-http 和 MCP_HOST=0.0.0.0
  4. 在 claude.ai 的“Settings → MCP Servers”下添加:https://your-app.onrender.com/mcp

💡 “开发者笔记本使用 stdio,云端使用 Streamable HTTP。”

**水平扩展:**使用 MCP_STATELESS=1 运行。在无状态模式下,服务不会保留任何会话状态,因此任一实例都可以处理任一请求,使用普通的轮询负载均衡器即可——无需粘性会话/Mcp-Session-Id 亲和性。如果需要有状态流式传输,则在边缘负载均衡器处按 Mcp-Session-Id 路由(例如使用 HAProxy stick-tables),确保每个会话固定到同一个实例。

⚠️ 绑定:在网络传输模式下,服务默认绑定到 127.0.0.1,因此本地启动的服务不会暴露给整个网络(例如公共 Wi-Fi)。仅在预期绑定所有接口的容器/云端环境中设置 MCP_HOST=0.0.0.0(Docker 镜像已为你完成此设置)。


可用工具

核心工具(OJP 2.0 / CKAN)
工具描述数据来源
transport_search_stop按名称搜索车站/站点OJP 2.0
transport_nearby_stops按坐标查找附近站点OJP 2.0
transport_departures实时出发信息,包含延误和站台OJP 2.0
transport_trip_plan规划从 A 到 B 的行程,包含换乘、时长和交通方式OJP 2.0
transport_search_datasets搜索开放数据目录(约 90 个数据集)CKAN¹
transport_get_dataset获取特定数据集的完整详情CKAN¹

¹ CKAN 工具需要在 API Manager 中单独订阅。

扩展工具(可选 API 密钥)
工具描述数据来源
get_transport_disruptions🚨 实时交通中断、取消和线路关闭信息SIRI-SX
get_train_occupancy📊 特定列车的拥挤度预测Occupancy JSON
get_ticket_price💰 区间票价OJP Fare
get_train_composition🚃 列车编组、车厢等级和无障碍信息Formation REST
check_transport_api_status🔍 检查所有已配置 API 的运行状况全部
示例用例
查询工具
“从 Zurich Stadelhofen 出发的下一班列车是什么时候?”transport_departures
“为 25 名学生规划从 Zurich 前往 Winterthur Technorama 的行程”transport_trip_plan
“Zurich 和 Bern 之间有交通中断吗?”get_transport_disruptions
“IC 1009 今天有多拥挤?”get_train_occupancy
“从 Wädenswil 到 Bern 的车票多少钱?”get_ticket_price
“IC 708 有餐车吗?”get_train_composition
“Langstrasse 100 附近有哪些站点?”transport_nearby_stops

架构

┌─────────────────┐     ┌───────────────────────────┐     ┌──────────────────────────┐
│   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     │
                        └───────────────────────────┘
基础设施组件
组件比喻功能
RateLimiter门卫限制每个时间窗口内的 API 调用次数
SimpleCache白板缓存响应,以供重复查询使用
APIClient总机集中处理身份验证、重定向和错误
APIConfig名片每个 API 的密钥、URL 和限额
缓存策略
API缓存 TTL原因
SIRI-SX120s运营中断不会每秒都发生变化
Occupancy300s预测以天为单位
Formation600s列车编组当天保持稳定
OJP Fare1800s票价在一天内很少变化

项目结构

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 version

安全与限制

  • 只读: 所有工具都执行只读请求(仅用于查询的 HTTP GET / OJP XML POST)——不会在任何上游系统中写入、修改或删除数据。
  • 不处理个人数据: 行程查询是临时的,本服务不会存储这些查询。API 返回的是计划时刻表和实时运营数据。不会处理或保留任何个人身份信息(PII)。
  • 速率限制: opentransportdata.swiss 会对每个密钥实施速率限制(详见 API Manager 文档)。服务内置的 RateLimiter(SIRI-SX:2 req/min,Formation/OJP Fare:5 req/min)会自动遵守这些限制。进行批量查询时,请谨慎使用 limit 参数。
  • 需要 API 密钥: 必须使用从 api-manager.opentransportdata.swiss 获取的免费密钥。密钥与您的账户订阅绑定——请仅订阅您打算使用的 API。
  • 数据时效性: 实时工具(出发、运营中断、载客率)反映查询时的上游数据源。本服务会以较短的 TTL(120s–1800s)缓存响应,以减少 API 负载——请参阅上方的缓存策略表。
  • 服务条款: 数据受 opentransportdata.swiss 的 ToS 约束。OJP、SIRI-SX 和 CKAN 目录以开放许可证(ODbL / CC BY 4.0)发布,可用于非商业用途和研究。
  • 不作保证: 本服务是社区项目,与联邦交通局(BAV/OFT)或 SBB 无关。服务可用性取决于上游 API。
安装前须知(同意事项)

将此服务添加到您的 MCP 客户端后,连接的 AI 模型便可代表您查询瑞士 公共交通信息,使用的是您的 opentransportdata.swiss API 密钥,并向 opentransportdata.swiss 发出 HTTPS 外连请求。不会向上游写入任何内容, 也不会存储 PII,但在配置服务前,请查看上方的工具列表,并确认您愿意授予 此类访问权限。

安全运行 HTTP 传输(无内置身份验证)

此服务本身不提供身份验证。运行 Streamable HTTP 传输(MCP_TRANSPORT=streamable-http)时,MCP SDK 会为每个会话生成一个 加密随机的 Mcp-Session-Id,但不会将其绑定到任何用户身份。因此:

  • 不要将未启用身份验证的实例直接暴露到公共互联网。 请将其置于支持身份验证的反向代理(OAuth2 代理、mTLS 或平台的访问控制)之后,或限制其仅供可信网络访问。
  • 本地使用时保留默认值 MCP_HOST=127.0.0.1;只有在受控的容器/云环境中才绑定到 0.0.0.0(参见 Deployment)。
  • 将 MCP_CORS_ORIGINS 限定为你实际信任的源。
  • 只要绑定地址超出回环范围,就设置 MCP_ALLOWED_HOSTS。它用于防范DNS 重绑定:网络上的某个页面将自己的主机名解析到此服务的地址,然后从浏览器与其通信。CORS 无法阻止这种情况——从浏览器的角度看,该请求属于同源请求;令牌也无法阻止,因为攻击页面运行在持有令牌的上下文中。只有 Host 检查能够阻止它。未设置该选项时,检查会保持关闭;只有在服务前方的组件会验证 Host 时,这才是合适的默认设置。

完整的安全状况和已接受风险的决策(网关级控制)请参阅 SECURITY.md。


已知限制

  • OJP 票价: 折扣(Halbtax、GA、区域通票)不一定会反映在票价中
  • Formation: 基于站点的数据仅在今天可用(依赖实时数据)
  • Occupancy: 仅支持 SBB、BLS、Thurbo 和 SOB,不支持私营铁路
  • SIRI-SX: 返回瑞士的所有交通中断信息 → 请使用 filter_text 参数
  • CKAN: 需要在 API Manager 中单独订阅

MCP 协议版本

此服务通过同一个端点支持两个协议时代。客户端在连接上的第一个请求决定适用哪个时代;如果之后声明属于另一个时代,则会被拒绝。

时代修订版本适用客户端
initialize 握手2024-11-05 … 2025-11-25当前客户端使用的协议。服务会使用请求中指定的修订版本作答;如果请求要求更新的版本,则使用 2025-11-25 这一上限。
逐请求封套2026-07-28携带 2026-07-28 _meta 封套的请求会建立现代连接。

这两个修订版本都固定在 tests/test_protocol_version.py 中,并与已安装的 SDK 进行断言,因此 Dependabot 升级 mcp 时,任一版本都不会悄然变动。此固定项说明了 SDK 提供哪些修订版本。

服务实际支持这些版本的情况,则通过 tests/test_modern_wire.py 进行测量,测试对象正是 main() 交给 uvicorn 的应用:针对 server/discover、tools/list 和一次 tools/call 发送真实的 2026-07-28 单次交互 POST 请求——不发送 initialize,也不使用 Mcp-Session-Id;测试三种拒绝情形(缺少封套、路由标头与请求正文不一致、未提供的修订版本),并在同一端点发送传统的 initialize,以证明两个时代可以共存。

本节的早期版本曾声称仓库没有可供发送请求的 ASGI 应用,并以此解释为何门禁只能断言常量。实际上,仓库确实构建了一个应用。

服务身份。 2026-07-28 没有 initialize,因此也没有客户端读取 serverInfo 的单一位置。该修订版本会将 Implementation(名称、标题、版本、网站)放入 server/discover,并放入每个结果的 _meta。此服务会从自身的发行版元数据中填入这些信息,因此网络传输中的版本就是已安装的版本,不会与 pyproject.toml 不一致。

请注意,SDK 的 LATEST_PROTOCOL_VERSION 是现代时代的别名,而不是握手时代的别名——只针对它设置固定版本,会让当前客户端实际协商使用的时代有机会发生变动。

更新政策。 门禁失败时,不要盲目编辑常量:请阅读两个修订版本之间的规范变更日志,确认服务仍按预期运行,然后一并更新常量、本节、README.de.md 和 CHANGELOG.md。


测试

# 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"
测试数据来源

所有四个上游 API 都需要 opentransportdata.swiss API-Manager 提供的 Bearer 令牌,因此 CI 无法记录真实响应——相关信息已测量并保存在 tests/fixtures/upstream_auth_probe.json 中。因此,测试模块中的 XML 载荷都是手工编写的,并非记录所得,无法反驳生产代码:两者都基于对文档的同一解读,如果两者都错,就会错在同一个地方。

可以记录的是契约。OJP 2.0 是 CEN 标准(CEN/TS 17118),并提供公开的 XML 架构;tests/fixtures/ojp_2_0_contract.json 是据此整理的、带日期的索引,包含元素名称、此服务依赖的结构、以值发送的枚举,以及读取的每个架构文件的 SHA-256。tests/test_ojp_contract.py 中包含针对该索引的请求和解析器。架构本身有意不随仓库附带:源代码仓库没有许可文件。

python scripts/record_fixtures.py          # re-record
python scripts/record_fixtures.py --check  # recompute against the pinned tag

来源、日期、选择规则和哈希值:tests/fixtures/PROVENANCE.md。


更新日志

请参阅 CHANGELOG.md


贡献

请参阅 CONTRIBUTING.md


安全

请参阅 SECURITY.md(德语),了解安全状况以及如何报告漏洞。


许可证

MIT 许可证 — 请参阅 LICENSE


作者

Hayal Oezkan · github.com/malkreide


致谢与相关项目

安装

通过 uv 的 uvx 运行,无需克隆或手动安装。将其添加到 MCP 客户端配置中(Claude Desktop、Cursor 和 Windsurf 使用 mcpServers;VS Code 在 .vscode/mcp.json 中使用顶层 servers 键):

{
  "mcpServers": {
    "swiss-transport-mcp": {
      "command": "uvx",
      "args": [
        "swiss-transport-mcp"
      ]
    }
  }
}

评论

支持 Markdown

第一次接触 MCP?

从协议是什么,到在客户端里装上第一个服务,这几条回答覆盖了大多数入门问题。

一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。