mcpField
R
rihla

rihla

本地服务
github.com/leojg地图与出行017 周前更新

关于 rihla

Rihla 是面向多段行程的航班搜索命令行工具和 MCP 服务,支持灵活日期与机场选择。它为各航段的日期和机场选项报价,再按停留时长约束排列有效组合,并提供离线模拟数据。

主要功能

  1. 01搜索多段航班行程
  2. 02灵活选择机场和日期
  3. 03跨航段应用停留时长约束
  4. 04按价格排列有效组合
  5. 05标明票价来源及参考性质
  6. 06对未报价航段返回部分结果

适用场景

  1. 01比较多站行程的机场组合
  2. 02在灵活出发日期内寻找低价路线
  3. 03使用模拟票价离线探索行程
  4. 04检查票价覆盖不完整的路线

MCP 相关

stdio MCP 服务提供两个只读工具:`resolve_airports` 用于验证和补充建议的机场代码,`search_trip` 用于搜索有报价的行程。工具说明要求 Agent 在使用有配额限制的搜索前确认机场。

配置

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

mcp.json · 通用配置
{
"mcpServers": {
"leojg-rihla": {
"command": "uvx",
"args": [
"rihla-mcp"
],
"env": {
"TRAVELPAYOUTS_TOKEN": "<TRAVELPAYOUTS_TOKEN>",
"SERPAPI_KEY": "<SERPAPI_KEY>",
"RIHLA_PROFILE": "<RIHLA_PROFILE>"
}
}
}
}
启动命令uvx rihla-mcp
需要配置的环境变量
TRAVELPAYOUTS_TOKEN密钥Travelpayouts Data API token (free) - the primary price source. Without any keys the server runs on offline mock data.
SERPAPI_KEY密钥SerpApi key (optional, 250 free searches/mo) - fills routes Travelpayouts misses with bookable Google Flights fares.
RIHLA_PROFILESource profile: 'local' (all configured sources), 'hosted' (redistribution-licensed only), or 'mock' (offline).

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

安装包
pypirihla-mcp0.1.0

工具

还没有获取到工具列表

本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。

详细介绍

Rihla

Rihla(رحلة),意为 “旅程”。 名称取自 Ibn Battuta 在 14 世纪撰写的游记 — 这位走遍最远之地的探险家留下了历史记录。他从 Tangier 出发前往 Mecca, 一路远行了 29 年,行程达 75,000 英里。

灵活的多程、多机场航班搜索,可在完整行程范围内找到最便宜的路线 — 提供 CLI 和 MCP 服务,供 AI Agent 使用。

面向消费者的航班网站按单程定价。Rihla 则将整个旅程视为一个整体优化问题:

“9 月 15 日左右从 Montevideo — 或者从 Buenos Aires 出发,那里坐渡轮就能到 — 前往 Europe。停留 20–30 天,再去 Japan 待 15 天,然后回家。怎样组合最便宜?”

这个查询包含三程,每程两端都有可选机场、灵活的出发日期窗口,以及相互关联的停留时长限制。Rihla 会为每程的日期×机场网格各定价一次,然后完全通过本地计算找出最便宜的有效组合 — 因此,即使是包含 3–4 程的灵活查询,也只需少量 API 调用。

1. 1,297 USD   (44 days door-to-door)
     MVD -> AMS  2026-09-08  $    383  [mock, cached]  AA AA127
     FRA -> NRT  2026-10-07  $    481  [mock, cached]  KL KL411
     HND -> EZE  2026-10-22  $    433  [mock, cached]  AZ AZ933

2. 1,308 USD   (44 days door-to-door)
     MVD -> AMS  2026-09-14  $    446  [mock, cached]  AA AA127
     ...

请留意机场替换的效果:经 Amsterdam 入境 Europe,从 Frankfurt 离境,飞回 Buenos Aires — 每程都会从各自的机场集合中独立选出最便宜的机场组合。

快速开始

需要 Python ≥ 3.10。

pip install rihla            # CLI
pip install "rihla[mcp]"     # CLI + MCP server

开箱即可离线运行(无需密钥 — 使用确定性的模拟数据源):

RIHLA_PROFILE=mock rihla                # the canonical demo trip above
rihla examples/queries/canonical.json   # same trip, from a query file
rihla -i                                # build a query interactively

如需实时价格,请将 .env.example 复制为 .env,并至少添加一个 Travelpayouts 令牌(免费)。请参阅 数据源。

编写查询

查询是一个简短的 JSON 文件:包含出发机场、有序停靠点、第一程的出发日期窗口,以及在每个停靠点的停留时长。后续日期窗口会自动推导 — 无需手动计算“如果我 9 月 15 日出发并停留 20–30 天,什么时候飞往 Tokyo?”

{
  "origins": ["MVD", "EZE", "AEP"],
  "stops": ["EUROPE", ["NRT", "HND"], "MVD_AREA"],
  "earliest": "2026-09-08",
  "latest": "2026-09-22",
  "stays": [[20, 30], [15, 15]],
  "date_step": 3,
  "top": 5
}
  • origins — 作为一个出发机场集合尝试的 IATA 代码;每个日期选出最便宜的机场。
  • stops — 每个停靠点可以是区域名称或 IATA 代码列表。内置区域: EUROPE(MAD、BCN、LIS、CDG、FCO、AMS、FRA)、TOKYO(NRT、HND)、MVD_AREA (MVD、EZE、AEP)。将出发机场集合设为最后一个停靠点,即可飞回家。
  • earliest / latest — 仅第一程的出发日期窗口。
  • stays — 在每个中间停靠点停留的夜数 [min, max] (len(stays) == len(stops) - 1)。
  • date_step — 在日期窗口内每隔 N 天采样一次(间隔越大,API 调用越少)。
  • top — 返回的排序组合数量。
  • currency — 可选的 ISO 4217 代码(默认 USD)。

rihla -i 会引导你回答这些问题,并输出相应 JSON,方便保存以供复用。运行时添加 --links 可显示预订链接。

解读结果

Rihla 如实呈现数据质量,不会假装所有航班都能预订:

  • 每个航班都会标注数据来源;如果价格仅供参考,则会标记为 cached (Travelpayouts 数据是汇总的搜索历史,并非实时票价);真实且可预订的票价则来自 SerpApi / Google Flights。
  • 如果某些航段无法定价(冷门航线确实存在,缓存数据源也会有缺口),你会得到仅针对已找到航段的部分结果,绝不会悄悄给出错误的总价。
  • 对于无法定价的航段,Rihla 会显示你的出发日期窗口之外最近的缓存票价 — 提示你调整或扩大日期范围。

v0.1 仅按价格排序。默认允许在一个区域内采用不同城市进出的开口行程(从一个城市进入 Europe,从另一个城市离开);不会计算区域内调位的成本。

数据源与配置文件

来源角色费用备注
Travelpayouts / Aviasales主要免费缓存数据,获得再分发许可。每次调用可获取一个月的价格,因此调用预算很低。价格仅供参考;覆盖范围取决于航线的热门程度。
SerpApi(Google Flights)补充每月免费搜索 250 次(自带密钥)可实际预订的票价;可补充 Travelpayouts 未覆盖的航线。仅用于未覆盖的航线。
Mock离线—用于开发和演示的确定性虚假价格。

通过 .env(参见 .env.example)或环境变量配置: TRAVELPAYOUTS_TOKEN、SERPAPI_KEY 和 RIHLA_PROFILE:

  • local(默认)——使用所有已设置密钥的数据源,包括 SerpApi。
  • hosted ——仅使用获得再分发许可的数据源(禁用 SerpApi:它会抓取 Google, 因此不要在公开托管的实例中提供它)。
  • mock ——强制使用离线获取器,不访问网络。

如果未设置密钥,Rihla 会回退到 Mock 数据源,并说明这一点。

MCP 服务

Rihla 附带一个 MCP 服务(stdio),让 Claude 等 Agent 可以执行行程搜索:

pip install "rihla[mcp]"
claude mcp add rihla -- rihla-mcp        # Claude Code

或在任意 MCP 客户端配置中:

{
  "mcpServers": {
    "rihla": {
      "command": "rihla-mcp",
      "env": {
        "TRAVELPAYOUTS_TOKEN": "your-token",
        "SERPAPI_KEY": "your-key"
      }
    }
  }
}

(服务还会从其工作目录加载 .env,因此如果你从代码检出目录运行它,env 是可选的。)

它提供两个只读工具,并强制遵守以下规范:

  1. resolve_airports ——Agent 根据旅行者提到的地点提出 IATA 代码;Rihla 会验证并补充信息(包括附近的替代机场)。成本低且不消耗配额。
  2. search_trip ——定价搜索,会消耗有限配额。工具说明要求 Agent 在消耗配额前,先获得旅行者对机场的明确确认。

mcp-name: io.github.leojg/rihla

工作原理

各航段的价格相互独立——MVD→欧洲的票价不受东京日期的影响。因此,Rihla 会一次性获取每个航段的日期×机场网格,然后完全在内存中枚举符合条件的日期组合(同时遵守停留时间限制)。组合爆炸发生在本地计算中,而非 API 调用中。

core.py            data model + the pure optimizer (no I/O)
fetchers/          PriceFetcher protocol: Mock / Travelpayouts / SerpApi + merge
places.py          airport sets / regions
api.py             search_trip: serializable query in, result dict out
cli.py             thin CLI over search_trip
mcp_server.py      thin MCP wrapper over the same seam

添加数据源(Duffel、Kiwi 等)只需再实现一个类,该类实现一个仅含一个方法的协议:quote(origin, dest, day) -> Quote。

**范围(v0.1):**仅搜索航班——不包含住宿、预订或支付;仅限一名成人、一个舱位。搜索会返回预订链接,但不会处理交易。

开发

git clone https://github.com/leojg/rihla && cd rihla
pip install -e ".[dev,mcp]"
pytest              # offline, no keys needed
ruff check .

许可证

依据 Apache License 2.0 许可——请参阅 LICENSE。

评论

支持 Markdown

第一次接触 MCP?

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

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