内容
# 佳明MCP桥接器
将您的佳明训练数据导入Claude,并将结构化训练计划推送回您的手表。
佳明没有针对个人的公开API。他们的Connect开发者API需要合作伙伴协议,而非官方的爬虫库在佳明更改某些内容时就会崩溃。这个桥接器通过[Intervals.icu](https://intervals.icu)来弥补这一空白,Intervals.icu可以与佳明Connect双向同步,并提供一个有文档记录的API,带有普通的API密钥。
```
佳明手表 ──► 佳明Connect ──► Intervals.icu ──► 这个MCP服务器 ──► Claude
▲ │
└────────── 计划训练 ◄───────────────────────┘
```
免费,本地运行,无第三方服务持有您的数据。Intervals.icu免费使用(支持捐赠)。
## 您将获得
您的MCP客户端可以调用的九种工具:
| 工具 | 功能 |
|---|---|
| `check_connection` | 验证API密钥,报告速率限制余量 |
| `get_athlete_profile` | 阈值,心率/配速/功率区,FTP,体重 |
| `list_activities` | 日期范围内的活动,包含时间,距离,海拔和负荷的总计 |
| `get_activity` | 详细的单个训练,包括检测到的区间 |
| `get_activity_streams` | 时间序列(心率,海拔,配速,坡度,步频),降采样 |
| `get_wellness` | 心率变异性,静息心率,睡眠,体重,CTL/ATL,以及计算出的基准 |
| `list_planned_workouts` | 日历:计划的训练,会话,比赛 |
| `create_planned_workout` | 创建结构化训练计划 → 同步到您的手表 |
| `delete_planned_workout` | 删除日历条目 |
然后您可以问诸如 *"比较我过去四周的负荷与之前的训练块"*, *"我的轻松配速是否有所偏移"*,或 *"为明天的阈值训练创建计划并将其放在我的手表上"*。
## 要求
- 一个MCP客户端。Claude Desktop是参考客户端;任何支持MCP的客户端都可以使用。
- 一个具有活动的佳明Connect账户。
- 一个Intervals.icu账户(免费)。
- Python 3.10+。安装程序通过[uv](https://docs.astral.sh/uv/)设置此环境,如果您没有它。
## 设置
### 1. 创建一个Intervals.icu账户
在[intervals.icu/signup](https://intervals.icu/signup)注册账户。您可以使用Strava,Google或电子邮件登录。
### 2. 连接佳明
在**设置 → 连接**中,找到佳明Connect卡并授权。确保选中:
- **下载活动**
- **下载健康数据** - 心率变异性,睡眠,静息心率
- **上传计划训练** - 如果您想让训练计划到达您的手表,则需要此项
### 3. 运行补全
这是人们经常忽略的一步。佳明只会从您连接的那一刻起推送**新的**活动。您的历史数据不会自动到达。
在同一个佳明卡上,点击**下载旧数据** - 在*下载活动*和*下载健康数据*下各一次。它们是分开的。选择一个足够远的起始日期,以涵盖您关心的训练。
给它几分钟。如果一个小时后仍然没有数据到达,那么连接本身就是问题所在:在*两个*方面 - Intervals.icu和佳明Connect的账户设置 → 已连接的应用 - 断开连接,然后重新连接。
### 4. 获取您的API密钥
**设置 → 开发者设置**(页面底部)→ 生成密钥。
此密钥授予对您的Intervals.icu数据的完全访问权限。请像密码一样保护它。
### 5. 安装
```bash
git clone https://github.com/jonas-theobald/garmin-mcp-bridge.git
cd garmin-mcp-bridge
```
**macOS / Linux**
```bash
./scripts/install.sh
```
**Windows**
```powershell
powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1
```
安装程序检查uv,构建环境,询问您的API密钥,运行针对实时API的完整自测,并在备份现有的配置后将服务器注册到Claude Desktop。
### 6. 重启您的客户端
完全退出Claude Desktop(macOS上为Cmd+Q,Windows上为托盘图标 → 退出),然后再次启动。它只会在启动时读取MCP配置。
然后询问: *"调用check_connection。"*
## 手动安装
如果您不想运行脚本:
```bash
uv sync
INTERVALS_API_KEY=您的密钥 uv run selftest.py
```
然后将以下内容添加到客户端的配置文件中:
| 操作系统 | 路径 |
|---|---|
| macOS | `~/Library/Application Support/Claude/claude_desktop_config.json` |
| Windows | `%APPDATA%\Claude\claude_desktop_config.json` |
| Linux | `~/.config/Claude/claude_desktop_config.json` |
```json
{
"mcpServers": {
"garmin": {
"command": "/绝对路径/to/garmin-mcp-bridge/.venv/bin/python",
"args": ["-m", "garmin_mcp_bridge.server"],
"env": {
"INTERVALS_API_KEY": "您的密钥"
}
}
}
}
```
使用`.venv`内的解释器的绝对路径,而不是`uv run`。客户端在没有您的shell环境的情况下启动服务器,因此`uv`不会在PATH上。在Windows上,解释器位于`.venv\Scripts\python.exe`。
如果文件中已经有其他设置,请合并此内容,而不是替换它 - 并注意逗号。无效的JSON会被静默忽略,看起来与服务器启动失败完全一样。
## 验证其工作
自测试练习每个读取路径以及带有 `--write` 的训练创建路径:
```bash
INTERVALS_API_KEY=您的密钥 uv run selftest.py --write
```
```
PASS 认证 + 运动员资料 运动员 i123456(您的姓名)
PASS 运动设置 / 区 LTHR=172 maxHR=190 区=7
PASS 列出活动(30天) 15个活动,最新:TrailRun 2026-07-18T06:59:59
PASS 活动详情 + 间隔 比赛 — 49个间隔
PASS 活动流 流:{'heartrate': 37292, 'altitude': 37292}
PASS 健康状况(HRV/睡眠/静息心率) 31天,27天有HRV
PASS 日历事件 未来30天内有0个计划事件
PASS 创建 + 删除计划训练 已创建+删除,解析了3个步骤
```
要检查配置和服务器,您的客户端将实际启动它们:
```bash
python3 - <<'EOF'
import json, os, subprocess
path = os.path.expanduser("~/Library/Application Support/Claude/claude_desktop_config.json")
srv = json.load(open(path))["mcpServers"]["garmin"]
msgs = [
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
"protocolVersion":"2024-11-05","capabilities":{},
"clientInfo":{"name":"verify","version":"1"}}},
{"jsonrpc":"2.0","method":"notifications/initialized"},
{"jsonrpc":"2.0","id":2,"method":"tools/list"},
]
proc = subprocess.run([srv["command"], *srv["args"]],
input="".join(json.dumps(m)+"\n" for m in msgs),
capture_output=True, text=True,
env={**os.environ, **srv.get("env", {})}, timeout=30)
for line in proc.stdout.splitlines():
try: msg = json.loads(line)
except ValueError: continue
if msg.get("id") == 2:
print("OK —", len(msg["result"]["tools"]), "工具")
break
else:
print("FAILED\n", proc.stdout[:500], "\n", proc.stderr[:1000])
EOF
```
## 编写训练计划
`create_planned_workout` 使用Intervals.icu的原生训练语法:
```
- 15分钟 Z2 热身
3x
- 8分钟 Z4
- 3分钟 Z1
- 10分钟 Z1 冷却
```
一行一个步骤,以 `- ` 开头。裸 `Nx` 行启动一个重复块,涵盖直到下一个空行之前的步骤。持续时间使用 `s`、`m`、`h`。目标可以是区域(`Z2`)、阈值的百分比(`75-82%`)、绝对心率(`150-160bpm`)或配速(`5:30/km`)。
设置 `target` 为 `HR`、`PACE` 或 `POWER`。对于越野和徒步,使用 `HR` - 配速在25%的坡度上毫无意义。
### `workout_doc` 陷阱
**永远不要在有效载荷中包含 `workout_doc` 字段。**
计划训练仅在Intervals.icu将描述解析为结构化步骤时才会同步到您的手表。触发该解析的内容未记录,而直观的猜测是错误的:发送 `workout_doc: {}` 以*请求*解析实际上**抑制**了它。服务器读取该字段的存在并将其视为“步骤已提供”,因此跳过解析器。训练计划以未结构化的形式出现在日历中,永远不会到达手表。
针对实时API的测量 - 以下每个案例均发送 `workout_doc: {}`,除了最后一个:
| 有效载荷 | 结果 |
|---|---|
| 单个终点 / 跑步 / 区域 / 心率 | 未解析 |
| 批量终点 / 跑步 / 区域 / 心率 | 未解析 |
| 单个 / 跑步 / LTHR百分比 / 心率 | 未解析 |
| 单个 / 跑步 / 绝对心率 / 心率 | 未解析 |
| 单个 / 跑步 / 配速 / 配速 | 未解析 |
| 单个 / 骑行 / FTP百分比 / 功率 | 未解析 |
| **单个 / 跑步 / 区域 / 心率,无`workout_doc`** | **已解析 - 3个步骤,1380秒** |
省略该字段后,解析功能在两个终点、两个测试的运动、区域、百分比、心率和配速语法方面都起作用。
该服务器省略了它,并在每次写入后报告:
- `parsed_steps` - 服务器识别的步骤数
- `garmin_sync_likely` - `false` 当没有解析时
如果您收到 `false`,请在Intervals.icu网页应用中打开训练计划并保存它 - 这强制解析 - 然后检查您的描述语法。
## 故障排除
**客户端中没有出现工具。** 配置文件只在启动时读取;请完全退出并重新启动。然后检查文件是否为有效的JSON(`python3 -m json.tool <path>`)以及 `command` 路径是否存在。无效的JSON会被忽略而不会显示错误信息。
**401 未授权。** 密钥已重新生成或复制不完整。请从开发者设置中获取新的密钥。
**零活动。** 补全功能未运行 - 请参见步骤3。健康状况和活动补全功能是分开的。
**零星的403报错。** Intervals.icu位于Cloudflare后面,后者会挑战默认的库用户代理。客户端会发送类似浏览器的用户代理,因此请勿删除它。
**429 速率限制。** 每天5000次请求,每15分钟2500次, 每秒10次,按IP地址计算。在个人使用中实际上无法达到。客户端会等待短暂的回退并将较长的回退显示为错误,而不是挂起。
**计划负荷为空的跑步。** Intervals.icu计算基于功率的训练计划负荷,但不计算基于心率的跑步负荷。如果您希望未来的CTL预测有意义,请显式传递 `training_load`。
## 将密钥保存在配置文件之外
安装程序将您的API密钥以纯文本形式写入客户端配置文件。这是MCP服务器的正常做法,但如果您不想这样做:
**macOS** - 存储在Keychain中:
```bash
security add-generic-password -a "$USER" -s intervals-icu -w "您的密钥"
```
然后将 `command` 指向一个包装脚本(`chmod +x`),并删除 `env` 块:
```bash
#!/bin/bash
export INTERVALS_API_KEY=$(security find-generic-password -a "$USER" -s intervals-icu -w)
exec /绝对路径/to/.venv/bin/python -m garmin_mcp_bridge.server
```
**Windows** - 使用Credential Manager通过 `cmdkey` 读取的模式适用于 `.cmd` 包装器。
## 设计笔记
**流已降采样。** 三小时的越野跑约有10,000个样本/流。工具返回从原始数据计算出的最小值、最大值和平均值,以及一个系列块平均到大约200个点。形状决定了指导;个别样本只会占用上下文。
**字段已过滤。** 原始活动载荷包含200多个字段,其中大部分是自行车功率指标。工具返回精选的子集。如果您需要的字段缺失,请在 `server.py` 中将其添加到 `_ACTIVITY_FIELDS`。
**传输与逻辑分离。** `client.py` 没有MCP依赖关系。将此改为HTTP/SSE服务器 - 例如,在树莓派上,以便Webhook可以对每次上传做出反应 - 只需替换 `server.py`。
**为什么现在不运行在Pi上?** stdio服务器由客户端作为子进程启动,因此它必须位于同一台机器上。远程托管意味着HTTP传输、身份验证层和TLS,而客户端仅在您的桌面上运行。
## 来源
上述未记录的行为是针对实时API通过实证建立的。已记录的部分:
- [Intervals.icu的API访问](https://forum.intervals.icu/t/api-access-to-intervals-icu/609) - 认证,速率限制,Cloudflare注释
- [上传计划训练计划](https://forum.intervals.icu/t/uploading-planned-workouts-to-intervals-icu/63624) - 事件有效载荷
- [API集成手册](https://forum.intervals.icu/t/intervals-icu-api-integration-cookbook/80090) - 健康状况,活动,Webhooks
- [API参考](https://intervals.icu/api-docs.html)
## 许可证
MIT。参见 [LICENSE](LICENSE)。
不隶属于Garmin或Intervals.icu。