内容
# 🏔️ 山屋预订 MCP
> 直接从您的 AI 代理找到、检查和预订瑞士阿尔卑斯俱乐部(SAC)的山屋——**默认安全写入**。
[](https://www.npmjs.com/package/hut-reservation-mcp)
[](https://www.npmjs.com/package/hut-reservation-mcp)
[](./LICENSE)
[](https://modelcontextprotocol.io)
一个 [模型上下文协议](https://modelcontextprotocol.io) 服务器,允许任何支持 MCP 的代理(Claude、Codex、Cursor 等)搜索 [`hut-reservation.org`](https://www.hut-reservation.org) 上的山屋,检查确切日期的可用性,并准备预订和取消。
询问您的代理类似的问题:
- *"在 Zermatt 20 公里范围内找到可以容纳 2 人的山屋,日期为 7 月 12 日。*
- *"Cabane du Mont Fort 下周末有空吗?*
- *"为 Britanniahütte 预订 2 晚并给我确认链接。*
- *"列出我的即将到来的山屋预订。*
**为什么安全写入?** 预订和取消不会盲目触发。默认情况下,服务器会**准备草稿**,并为您提供一个浏览器 URL 以确认最终步骤 - 这样代理可以完成所有搜索和准备工作,而无需承担意外预订的风险。确认上游写入是可选的。请参见[安全模型](#safety-model)。
---
## 快速开始
```bash
npx hut-reservation-mcp
```
服务器通过 stdio 使用 MCP,因此您通常不需要手动运行它 - 而是让您的 MCP 客户端指向它并让客户端生成它。请选择下面的客户端。
<details>
<summary><strong>Claude 代码</strong></summary>
```bash
claude mcp add hut-reservation -- npx -y hut-reservation-mcp
```
添加后重启 Claude Code 以重新生成服务器,然后检查 `/mcp`。
</details>
<details>
<summary><strong>Claude 桌面版</strong></summary>
将以下内容添加到您的 `claude_desktop_config.json`(设置 → 开发人员 → 编辑配置):
```json
{
"mcpServers": {
"hut-reservation": {
"command": "npx",
"args": ["-y", "hut-reservation-mcp"]
}
}
}
```
编辑文件后重启 Claude Desktop。
</details>
<details>
<summary><strong>Codex</strong></summary>
```bash
codex mcp add hut-reservation -- npx -y hut-reservation-mcp
```
Codex 在 `config.toml` 中存储服务器。启动一个**新** Codex 会话(MCP 工具不会被注入正在运行的回合),然后使用 TUI 中的 `/mcp` 进行确认。
</details>
<details>
<summary><strong>Cursor / 其他 JSON 配置客户端</strong></summary>
大多数客户端接受以下格式的配置:
```json
{
"mcpServers": {
"hut-reservation": {
"command": "npx",
"args": ["-y", "hut-reservation-mcp"],
"env": {
"HUT_RESERVATION_CACHE_DIR": "$HOME/.cache/hut-reservation-mcp"
}
}
}
}
```
</details>
**软件包附带了一个捆绑的山屋目录**,因此 `search_huts` 和 `search_hut_availability` 立即生效,无需登录。可用性查询也是未经身份验证的。您将在结果中收到警告,表明捆绑的目录可能已过时 - 运行 `refresh_hut_catalog` 并使用凭证更新它。预订、取消、列出您的预订和刷新目录需要身份验证。请参见[配置和身份验证](#configuration--authentication)。
---
## 工具
所有面向工具的日期均使用 ISO `YYYY-MM-DD`。服务器内部将日期转换为上游瑞士 `DD.MM.YYYY` 格式。
| 工具 | 用途 | 需要身份验证 | 写操作? |
| --- | --- | :---: | :---: |
| `auth_status` | 报告登录、目录、地理编码器、区域缓存和草稿缓存的准备情况。设置时首先运行此命令进行诊断。 | 否 | — |
| `search_huts` | 按文本、国家、州或坐标周围的距离搜索缓存的山屋。如果没有本地缓存,则使用捆绑目录。 | 否¹ | — |
| `search_hut_availability` | 搜索匹配山屋的精确日期可用性。可用性查询未经身份验证。 | 否¹ | — |
| `refresh_hut_catalog` | 从上游山屋列表刷新缓存的山屋元数据。用新鲜数据替换捆绑目录。 | **是** | — |
| `refresh_area_cache` | 通过反向地理编码器刷新州/国家区域数据。需要 `NOMINATIM_BASE_URL`,不需要登录。 | 否² | — |
| `prepare_booking` | 创建一个安全的预订**草稿**(不确认)。 | **是** | — |
| `confirm_booking` | 确认准备好的预订,或返回浏览器交接 URL。 | **是** | ⚠️ |
| `list_bookings` | 通过身份验证的端点列出您的预订。 | **是** | — |
| `prepare_cancellation` | 创建一个安全的取消**草稿**(不确认)。 | **是** | — |
| `confirm_cancellation` | 确认准备好的取消,或返回浏览器交接 URL。 | **是** | ⚠️ |
¹ 使用捆绑目录时无需凭证。结果包括过时警告;运行 `refresh_hut_catalog` 以更新凭证。
² 需要配置的 Nominatim 兼容地理编码器(`NOMINATIM_BASE_URL`),但不需要 hut-reservation.org 登录。
> ⚠️ 确认工具默认返回**浏览器交接 URL**。仅当显式启用[实验写入](#safety-model)并提供原始有效载荷时,它们才会执行实际的上游写入。
`search_hut_availability` 默认检查每个匹配的山屋。仅当您故意想要更快的部分搜索时,请设置 `maxCandidates`;部分响应包括 `truncated`、`totalCandidates`、`checkedCandidates` 和警告。
---
## 建议的工作流程
**查找有空的山屋**(无需登录即可完成步骤 1-2)
1. `search_huts` → 2. `search_hut_availability`。如果不存在本地缓存,则自动使用捆绑目录;请注意过时警告。
3. (可选)身份验证 → `refresh_hut_catalog` → 重复以获取最新的山屋列表。
4. 对于州筛选:配置反向地理编码器 → `refresh_area_cache`(无需登录)。
**准备预订**
1. 搜索山屋 + 可用性 → 2. `prepare_booking` → 3. 查看草稿 → 4. `confirm_booking` → 5. 完成浏览器交接(除非启用实验写入)。
**准备取消**
1. 身份验证 → 2. `list_bookings` → 3. `prepare_cancellation` → 4. 查看草稿 → 5. `confirm_cancellation` → 6. 完成浏览器交接(除非启用实验写入)。
---
## 安全模型
高风险的上游写入操作故意是保守的。公共 SPA 公开 `preBook`、`submit`、`myReservations`、`reservationSummary`、`delete/{id}` 和部分取消费用端点,但完整的预订表单有效载荷未记录 - 因此盲目自动写入将很脆弱且存在风险。
默认情况下,`confirm_booking` 和 `confirm_cancellation` 返回一个**浏览器交接 URL** 而不是写入。实际写入需要**两者**:
- `HUT_RESERVATION_EXPERIMENTAL_WRITES=true`,以及
- 调用者提供的原始有效载荷。
将会话 cookie、XSRF 令牌、密码和原始预订有效载荷视为持有者凭证。将它们保存在忽略的本地文件中、您的 MCP 客户端的环境配置中或秘密管理器中。**永远不要提交它们**。
---
## 配置和身份验证
### 我需要身份验证吗?
**不 - 搜索功能开箱即用。** 软件包捆绑了一个山屋目录,山屋可用性也是一个公共端点,因此您可以在无需任何设置的情况下找到山屋并检查日期。只有当您想要更新数据或处理您自己的预订时,才添加凭证。
| 您要做的事情 | 工具 | 凭证 |
| --- | --- | :---: |
| 搜索山屋和检查可用性 | `search_huts`、`search_hut_availability` | 不需要(使用捆绑目录) |
| 更新目录到最新的山屋列表 | `refresh_hut_catalog` | **需要** |
| 获取州筛选 | `refresh_area_cache` | 不需要 - 但需要地理编码器 |
| 列出您的预订 | `list_bookings` | **需要** |
| 准备/确认预订或取消 | `prepare_booking`、`confirm_booking`、... | **需要** |
捆绑目录仅在山屋开放、关闭或更名时才会更改 - 很少见。搜索结果会在目录变旧时标记,因此您的代理可以建议 `refresh_hut_catalog`。
### 哪种身份验证模式?
> **⚠️ 如果您通过 Swiss Alpine Club 登录 hut-reservation.org(即您的帐户是 SAC 帐户),则必须使用 `sac` 模式。** `standard` 用户名/密码流程仅适用于原生 hut-reservation.org 帐户;SAC 链接的电子邮件将进行身份验证,但会话被视为“无效会话”。如果有疑问,请使用 `sac`。
**`standard`** - 原生 hut-reservation.org 帐户(用户名 + 密码):
```bash
HUT_RESERVATION_AUTH_MODE=standard
HUT_RESERVATION_USERNAME=person@example.com
HUT_RESERVATION_PASSWORD=...
```
**`sac`** - SAC 帐户,通过浏览器会话 cookie。 在 `hut-reservation.org` 通过 SAC 在浏览器中登录,然后打开 DevTools → **Application → Cookies → `https://www.hut-reservation.org`** 并复制 `SESSION` 和 `XSRF-TOKEN` 值:
```bash
HUT_RESERVATION_AUTH_MODE=sac
HUT_RESERVATION_SESSION_COOKIE=...
HUT_RESERVATION_XSRF_TOKEN=...
# 或者,等效地,同时在一个头部中:
# HUT_RESERVATION_COOKIE_HEADER="SESSION=...; XSRF-TOKEN=..."
```
SAC cookie 过期 - 当目录刷新开始因身份验证错误而失败时,请从浏览器获取新的 cookie 值。
### 使用 `npx` 安装设置这些变量
由于您的 MCP 客户端(不是您的 shell)会生成服务器,因此请在客户端配置中设置凭证,而不是依赖 shell 环境。有两个选项:
**1. 内联在客户端的 `env` 块中**(或 `claude mcp add` 使用 `-e KEY=val`):
```json
{
"mcpServers": {
"hut-reservation": {
"command": "npx",
"args": ["-y", "hut-reservation-mcp"],
"env": {
"HUT_RESERVATION_AUTH_MODE": "sac",
"HUT_RESERVATION_SESSION_COOKIE": "...",
"HUT_RESERVATION_XSRF_TOKEN": "..."
}
}
}
}
```
**2. 通过绝对路径指向 `.env` 文件** - 将秘密文件保存在客户端配置之外:
```json
"env": { "HUT_RESERVATION_DOTENV_PATH": "/Users/me/.config/hut-reservation/.env" }
```
服务器还会自动加载 `.env` 文件,但使用 `npx` 时工作目录不可预测,因此请优先使用 `HUT_RESERVATION_DOTENV_PATH`。来自 `env` 块的值会覆盖来自 `.env` 文件的值。请参阅 [.env.example](./.env.example) 以获取模板,并将 cookie、令牌和密码视为秘密 - 永远不要提交它们。
### 所有环境变量
| 变量 | 描述 |
| --- | --- |
| `HUT_RESERVATION_AUTH_MODE` | `standard`(用户名/密码)或 `sac`(浏览器会话 cookie)。 |
| `HUT_RESERVATION_USERNAME` / `HUT_RESERVATION_PASSWORD` | 标准 `hut-reservation.org` 凭证。 |
| `HUT_RESERVATION_SESSION_COOKIE` / `HUT_RESERVATION_XSRF_TOKEN` | SAC `SESSION` 和 `XSRF-TOKEN` cookie 值。 |
| `HUT_RESERVATION_COOKIE_HEADER` | 组合的 cookie 头部,例如 `SESSION=...; XSRF-TOKEN=...`。 |
| `HUT_RESERVATION_CACHE_DIR` | 缓存目录。默认为 `~/.cache/hut-reservation-mcp`。 |
| `HUT_RESERVATION_REQUEST_TIMEOUT_MS` | 上游请求超时(毫秒)。默认 `15000`。 |
| `HUT_RESERVATION_EXPERIMENTAL_WRITES` | `true` 允许原始有效载荷确认写入。默认 `false`。 |
| `HUT_RESERVATION_DOTENV_PATH` / `HUT_RESERVATION_DOTENV_DISABLED` | 指向特定的 `.env` 文件,或禁用 dotenv 加载。 |
| `NOMINATIM_BASE_URL` | 反向地理编码器基准 URL。 |
| `NOMINATIM_USER_AGENT` / `NOMINATIM_EMAIL` / `NOMINATIM_MIN_INTERVAL_MS` | 标识用户代理、联系电子邮件和地理编码器请求的速率限制。 |
### 反向地理编码器(可选,用于州筛选)
```bash
NOMINATIM_BASE_URL=https://your-nominatim.example
NOMINATIM_USER_AGENT="hut-reservation-mcp/0.1.0 you@example.com"
NOMINATIM_MIN_INTERVAL_MS=1000
```
服务器**永远不会**隐含使用公共 Nominatim。配置显式提供程序和标识用户代理,然后调用 `refresh_area_cache`。遵循提供商的使用策略,缓存响应,并保留 OpenStreetMap 属性。
---
## 故障排除
| 症状 | 修复 |
| --- | --- |
| 搜索结果包括捆绑目录警告 | 使用捆绑目录。运行 `refresh_hut_catalog` 并使用有效凭证更新本地最新副本。 |
| `refresh_hut_catalog` 失败并显示“需要完整身份验证” | 您未身份验证。配置凭证;目录端点是身份验证门控的。 |
| 身份验证失败并显示“无效会话” | 您的帐户可能是 SAC 帐户 - 切换到 `sac` 模式并使用新的浏览器 cookie,或您的 SAC cookie 已过期。 |
| 州筛选器返回空结果 | 配置 Nominatim 兼容的地理编码器,然后运行 `refresh_area_cache`。 |
| 可用性搜索速度慢 | 首先缩小搜索筛选器,或为有意的部分搜索设置 `maxCandidates`。 |
| 身份验证工具失败 | 检查 `HUT_RESERVATION_AUTH_MODE` 和凭证,然后重启客户端以重新生成具有新 env 的服务器。 |
| Codex 看不到工具 | 启动新的 Codex 会话(或重新加载),然后检查 `/mcp`。 |
| 确认返回浏览器网址 | 预期 - 除非 `HUT_RESERVATION_EXPERIMENTAL_WRITES=true` 并提供原始有效载荷。 |
---
## 从源代码开发
```bash
git clone https://github.com/domwoe/hut-reservation-mcp.git
cd hut-reservation-mcp
pnpm install
pnpm dev # 从 TypeScript 源代码运行在 stdio 上
```
让客户端指向本地检查点:
```bash
claude mcp add hut-reservation -- pnpm --dir /absolute/path/to/hut-reservation-mcp dev
# 或,对于构建的入口点:
pnpm build
claude mcp add hut-reservation -- node /absolute/path/to/hut-reservation-mcp/dist/index.js
```
### 重新生成捆绑目录
该软件包提供 `data/catalog.json`,以便用户无需身份验证即可搜索。 在发布新版本之前重新生成:
```bash
# .env 中需要有效的凭证(标准或 sac 模式)
pnpm generate:catalog
# 然后提交 data/catalog.json 并增加版本号
```
山屋目录很少更改(新建山屋开放,更名)。每发布一次更新即可重新生成一次。
### 验证
```bash
pnpm typecheck
pnpm test
pnpm run smoke:mcp:source
pnpm build
pnpm run smoke:mcp:dist
```
可选的仅读实时烟雾测试对抗上游:
```bash
HUT_RESERVATION_LIVE_SMOKE=true pnpm smoke:read
```
---
## 免责声明
这是一个非官方的社区项目,与 Swiss Alpine Club(SAC)或 `hut-reservation.org` 无关。请负责任地使用并遵守网站的服务条款。