一个基于 TypeScript、支持官方 Personal API 与安全浏览器 MFA 认证的 Garmin…
50.3/100
综合分
40
GitHub 星标
1,493
npm 周下载
—/5
用户评分
数据截至 2026/10/23 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add dsh-plugin-garmin-connectnpm 源 · dsh-plugin-garmin-connect 的发布者账号已校验与本仓库一致
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · browser
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 12 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安装兼容性检查✓ 自动检查通过展开查看检查明细 ↓
以下结论由程序自动检查 npm 包、engines 声明与入口文件得出,未做人工实机验证——能装不等于用着没问题。
✓npm 包dsh-plugin-garmin-connect @ 0.1.20
✓Node 引擎要求 >=20.0.0 · 基线 Node 22.19 满足
✓dsh CLI 依赖未声明 dsh 版本约束
✓入口文件main/exports/bin 已声明
验证方式:npm registry 存在性 + package.json 静态校验 · 最后检查 2026/10/31 22:55:43
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 27 处,展示前 23 条)
- 发起网络请求lib/dsh-client.js:1389
onLogin: (request) => loginRequests.request(request), - 读取密钥环境变量lib/mcp.js:297
const password = process.env.GARMIN_PASSWORD; - 读取密钥环境变量lib/mcp.js:298
const sessionToken = process.env.GARMIN_SESSION_TOKEN; - 读取密钥环境变量lib/mcp.js:299
const sessionTokenFile = process.env.GARMIN_SESSION_TOKEN_FILE?.trim() - 读取密钥环境变量lib/mcp.js:310
const personalApiKey = process.env.GARMIN_PERSONAL_API_KEY?.trim() || ''; - 读取密钥环境变量lib/mcp.js:311
const personalApiKeyFile = process.env.GARMIN_PERSONAL_API_KEY_FILE?.trim() || ''; - 读取密钥环境变量lib/mcp.js:377
process.env.GARMIN_SESSION_TOKEN_FILE, - 读取密钥环境变量lib/config.js:183
personalApiKey: preferNonEmpty(readVolatile(input.personalApiKey), process.env.GARMIN_PERSONAL_API_KEY), - 读取密钥环境变量lib/config.js:184
personalApiKeyFile: preferNonEmpty(readVolatile(input.personalApiKeyFile), process.env.GARMIN_PERSONAL_API_KEY_FILE), - 读取密钥环境变量lib/config.js:215
password: preferNonEmpty(input.password, process.env.GARMIN_PASSWORD), - 读取密钥环境变量lib/config.js:216
sessionToken: preferNonEmpty(input.sessionToken, process.env.GARMIN_SESSION_TOKEN), - 读取密钥环境变量lib/config.js:217
sessionTokenFile: preferNonEmpty(input.sessionTokenFile, process.env.GARMIN_SESSION_TOKEN_FILE), - 发起网络请求lib/browser-auth-canary.js:382
const response = await http.request({ - 发起网络请求lib/browser-auth-canary.js:435
const response = await http.request({ - 发起网络请求lib/browser-auth-canary-runtime.js:122
const serviceTicket = serviceTicketFromBlockedRedirect(route.request(), page, options); - 发起网络请求lib/browser-auth-canary-runtime.js:187
?? ((config) => axios_1.default.request(config)); - 发起网络请求lib/personal-client.js:42
const request = this.request(sdk => sdk.getUserProfileSettings()).then(profile => { - 发起网络请求lib/personal-client.js:96
const result = await this.cache.getOrSet(key, () => this.request(action)); - 发起网络请求lib/personal-client.js:148
const bytes = await this.request(sdk => sdk.downloadActivity(activityId)); - 发起网络请求lib/vendor/connect-personal-api/client.js:323
const response = await this.#fetch(url, { - 发起网络请求lib/client.js:1039
return axiosClient.request(retryRequest); - 发起网络请求lib/di-session.js:170
return client.request({ - 发起网络请求lib/di-session.js:450
const response = await axios_1.default.request({
扫描于 2026/11/3(0 天前) · 范围 入口闭包 + 全包扫描 · 来源 npm 发布包
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/schemastery@deepseek-ai/cordis@deepseek-ai/dsh-client-connection@deepseek-ai/dsh-client-ui-layout@deepseek-ai/dsh-client-ui-slots给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
界面预览
2 张 · 点击查看大图功能亮点
- 安全浏览器MFA认证
- 配合智能体使用
基于 TypeScript 的 Garmin Connect 插件和 MCP 服务器,支持安全的浏览器 MFA,为 DeepSeek Harness 打造,也能配合其他智能体使用。
最近更新
在 GitHub 查看全部 →v0.1.202026-10-22
· 新增课表排期 / Workout scheduling
· create_garmin_workout 新增可选 scheduleDate,确认预览后创建课表并安排到指定日期。
· 新增 schedule_garmin_workout,可将已有课表安排到某一天;DSH 插件和 MCP 均支持。
· 排期确认绑定账号、课表和日期,避免重复写入;创建成功但排期失败时保留课表 ID,便于继续处理。
· 更新内置 Agent 指引及中英说明。Connect 会话账号共 29 个工具;Personal API 保持 15 个只读工具。
Add an optional scheduleDate when creating a workout, or use schedule_garmin_workout to schedule an existing template. Both DSH and MCP use previews and account/workout/date-bound, one-use confirmations. Partial success preserves the created workout ID for recovery.
· 验证 / Verification
· CI 的 Node 20、Node 22 均通过 50 套、1,194 项测试及构建;macOS 51 项、Windows 15 项会话权限测试通过。维护 SDK 依赖与发布包检查通过。
· 开发候选已在真实 DeepSeek Harness 0.2.1-rc.2 和大陆主账号完成创建、两天排期、回读及清理;原 42 条课表与账号配置保持不变。
· 正式包的 217 个编译文件与该验收候选一致。
· 排期成功后等待 Garmin Connect 同步;本轮未验证实体手表收取。
真实桌面验收记录 · npm
npm install dsh-plugin-garmin-connect@0.1.20
v0.1.192026-10-22
· 更新内容
· DSH 与 MCP 正式支持 Garmin 官方 Personal API,集成自维护的 TypeScript SDK。
· Personal 账号只需填写别名和 API Key,无需邮箱或密码;支持最多 5 个独立账号,保留原有 Connect 网页会话方式。
· Personal 提供 15 个兼容工具,包含活动、HRV、血氧、呼吸日汇总等读取,以及本地 FIT 下载和训练知识查询。原网页会话账号继续使用 28 个工具及课表、日历管理能力。
· 设置页增加连接验证;Key 保存后不回填,账号凭据按稳定 ID 隔离。
· 更新内置技能、中英 README 和 9 图 Personal API 教程,补充真实 Harness 桌面截图。
· 大陆站页面文案尚未完善,对应 Personal 端点换取令牌返回 HTTP 526,当前无法读取数据;国际端点已通过验证。
· 验证
· Host/client 构建、SDK 依赖检查、7 套共 146 项定向测试通过。
· GitHub CI:Node 20/22 各 49 套、1112 项测试及构建通过;Node 22 包检查、Windows 15 项 ACL 测试、macOS 51 项 ACL/Session 测试全部通过。CI 记录。
· 真实 Harness 0.2.1-rc.2 桌面候选通过设置保存、连接验证、5 项 Personal 读取与 1 项原大陆网页账号读取。重启后配置保留,再次连接验证成功。
· 正式包 217 个编译文件与上述桌面候选完全一致。
· 官方 npm 全新安装、MCP 启动和 15 项 Personal 工具发现通过;本机 DSH 已切换正式 0.1.19,账号配置保留,Personal 连接复核成功。
· HRV 时序与血氧测量值存在空缺,按原始响应保留;呼吸为每日摘要。
桌面验收记录
· 安装
npx @deepseek-ai/dsh plugin --profile desktop add dsh-plugin-garmin-connect@0.1.19 --registry=
MCP:使用 dsh-plugin-garmin-connect@0.1.19,更新后重新加载连接器。
· English
Adds official Garmin Personal API support to DSH and MCP. Configure a Personal account with an alias and API Key; no email or password is needed. Includes 15 compatible Personal tools, keeps existing web-session accounts and tools, isolates credentials by account ID, and provides a connection check. International access and a real Harness desktop candidate passed validation. The mainland Personal token endpoint currently returns HTTP 526. Build, dependency checks and 146 focused tests pass; all 217 compiled release files match the desktop-tested candidate.
v0.1.182026-10-22
· 更新内容
· 新增血氧 get_garmin_spo2 和呼吸 get_garmin_respiration:DSH 与 MCP 共用,支持日期和已有账号选择,保留完整摘要与时序数据。
· 内置技能补充新工具的发现、调用与空数据处理。共 28 个工具,其中 24 个用于查询或本地建议。
· 中英文 README 补充 Garmin、Apple、Android 手表的 WristTale 对应链接。
· 继续精确依赖官方 npm 上已发布的自维护 SDK 1.7.0,通过其认证 HTTP 传输调用,无需未发布依赖。
· 验证
· 完整构建、SDK 依赖校验及 6 套共 155 项专项测试通过。
· 已通过大陆、国际现有 Session 和真实 DeepSeek Harness 对话验收;四次桌面工具调用均成功。
· 国际账号返回了血氧、呼吸测量数据;大陆账号测试日期的测量字段为空,接口正常可访问,不据此判定整个区域不支持。
· 正式包的 182 个编译文件与桌面验收候选完全一致。
验收记录
· English
Adds daily blood oxygen and respiration read-only tools to DSH and MCP, retaining complete service responses and existing account selection. Updates the bundled skill and bilingual documentation. Build, dependency checks, 155 focused tests and real Harness calls passed. Empty China-account measurements remain distinct from API availability.
· 安装 / Install
npx @deepseek-ai/dsh plugin --profile desktop add dsh-plugin-garmin-connect@0.1.18 --registry=
MCP: install dsh-plugin-garmin-connect@0.1.18 and restart the configured MCP server.
· 平台检查说明
GitHub 的 Node 20/22 与 Windows 检查均已通过。macOS 云端任务因托管 arm64 Runner 容量不足未能启动,并非测试失败;对应 51 项 ACL/Session 专项已在本机 macOS 通过,Host 构建也已通过。云端任务记录。
数据来自仓库的 GitHub Release,可能与插件实际版本不一致。
README
由 DeepSeek 最新模型翻译生成dsh-plugin-garmin-connect
一个基于 TypeScript、支持官方 Personal API 与安全浏览器 MFA 认证的 Garmin Connect 插件与 MCP 服务器:为 DeepSeek Harness 打造,也适用于更多 AI Agent。
由李二牛开发,让 AI 更懂你的 Garmin 训练。
这是一款开源的 DeepSeek Harness 插件与 MCP 连接器,支持中国区和国际区账号。让 AI 查询完整活动与分段、睡眠、心率和 HRV 等数据,并在你确认后创建、排期、删除训练课表或取消日历排期,更方便地分析训练、调整安排。
账号由你掌握,密码不交给 AI。 使用推荐的 Garmin 官方网页登录流程,密码和验证码只在官方页面输入,不交给 AI 或开发者。登录会话凭据保存在本机,并通过私密文件权限保护;你授权查询的运动与健康数据,会返回给你选择的 AI 客户端用于分析。
支持主流 Coding Agent 与 AI 工作台 DeepSeek Harness · WorkBuddy ·千问办公 · ZCode · Claude Code · Codex · Cursor · Windsurf 根据客户端能力,通过 MCP 或 SKILL.md 工作流接入。
[!
展开完整文档(README 剩余 1 节)
dsh-plugin-garmin-connect
一个基于 TypeScript、支持官方 Personal API 与安全浏览器 MFA 认证的 Garmin Connect 插件与 MCP 服务器:为 DeepSeek Harness 打造,也适用于更多 AI Agent。
由李二牛开发,让 AI 更懂你的 Garmin 训练。
这是一款开源的 DeepSeek Harness 插件与 MCP 连接器,支持中国区和国际区账号。让 AI 查询完整活动与分段、睡眠、心率和 HRV 等数据,并在你确认后创建、排期、删除训练课表或取消日历排期,更方便地分析训练、调整安排。
账号由你掌握,密码不交给 AI。 使用推荐的 Garmin 官方网页登录流程,密码和验证码只在官方页面输入,不交给 AI 或开发者。登录会话凭据保存在本机,并通过私密文件权限保护;你授权查询的运动与健康数据,会返回给你选择的 AI 客户端用于分析。
支持主流 Coding Agent 与 AI 工作台 DeepSeek Harness · WorkBuddy ·千问办公 · ZCode · Claude Code · Codex · Cursor · Windsurf 根据客户端能力,通过 MCP 或 SKILL.md 工作流接入。
[!NOTE]
0.1.6 MFA 支持状态: dsh 本机网页、garmin-connect-auth serve 系统浏览器流程与 MCP URL elicitation 均可为中国区和国际区账号初始化同一种 owner-only session。
2026-08-29 已在本机完成两个区域的真实 MFA:中国区跑通了浏览器到 session 落盘及只读调用全链路,国际区跑通了系统浏览器、DI 交换与 owner-only session 落盘。个别浏览器策略仍可能阻断单次流程。旧的 login --browser 命令仅保留用于诊断。
我的更多应用
| 图标 | 应用 | 一句话介绍 |
| | WristTale | 在 Garmin、Apple、Android 手表上阅读 TXT 和 Markdown 电子书 |
| | JiaKe.app | 把 Garmin 截图做成精美宣传图 |
| | GameraSnap | 用佳明手表远程控制手机拍照/录像 |
| | WristAlbum | 在佳明手表上保存私人照片相册 |
| | WristPass | 把会员卡、票券装进手腕,随时出示 |
| | 2FA4G | 在佳明手表上保存离线两步验证码 |
这个插件做什么?
安装本插件后,DeepSeek Harness 或任何兼容 MCP 的 AI Agent 都可以通过自然语言自动调用 Garmin Connect 数据。你只需要说一句话,比如:
- "我昨晚睡得怎么样?"
- "帮我看一下最近 5 次跑步的配速变化。"
- "我今天走了多少步?"
代理会自动选择合适的工具调用 Garmin API,并将结果格式化后反馈给你。
注册的工具
0.1.20 为 Connect 网页会话账号提供 29 个工具,其中 24 个用于读取数据或本地知识查询; download_garmin_activity_fit 会在 MCP/dsh 所在主机写入一个本地文件。
创建课表、安排日期、删除课表和取消日历排期会在用户显式确认后修改 Garmin 数据。
仅配置 Personal 的 DSH 连接和 Personal MCP 服务提供 15 个兼容工具,覆盖 Garmin 数据读取、FIT 本地下载和本地训练知识查询。DSH 混合配置两种账号时保留工具合集,并按所选账号的能力执行调用。
0.1.14 引入的下方 13 个恢复与训练工具通过精确 npm 别名依赖已发布的维护版 SDK,详见自行维护的 SDK 依赖。
| 工具名 | 用途 | 参数示例 |
| get_garmin_activities | 获取近期运动记录,默认返回完整详情;可选 compact 精简模式 | {"limit": 5} |
| get_garmin_sleep | 获取指定日期或日期范围的睡眠评分、时长与阶段分布 | {"startDate": "2023-10-01", "endDate": "2023-10-02"} |
| get_garmin_steps | 获取指定日期或日期范围的步数;仅当 Garmin 上游提供时才包含目标与步行距离 | {"startDate": "2023-10-01"} |
| get_garmin_heart_rate | 查询指定日期或日期范围的静息、最高与最低心率 | {"startDate": "2023-10-01", "endDate": "2023-10-02"} |
| get_garmin_weight | 查询指定日期或日期范围的身体成分(体重、BMI、体脂率、骨骼肌等) | {"startDate": "2023-10-01"} |
| get_garmin_workouts | 查询 Garmin 训练库中的可复用训练模板(不是日历排期) | {"limit": 10, "offset": 0} |
| get_garmin_profile | 获取经过字段白名单过滤的个人资料摘要 | {} 或省略 |
| get_running_skill_advice | 讲解 8 种课型与 4 套训练理念,或先完成必问信息再提供个性化建议 | {"mode": "explain", "query": "丹尼尔斯", "language": "zh-CN"} |
| download_garmin_activity_fit | 下载活动的原始归档,并把其中唯一的 FIT 文件安全提取到所配置父目录下的账号目录 | {"activityId": 123456789} |
| create_garmin_workout | 预览并确认创建结构化训练;可用 scheduleDate 同时安排日期 | {"name": "门槛巡航3×8分钟", "steps": [...], "scheduleDate": "2026-10-24"} |
| schedule_garmin_workout | 为已有课表预览并确认日历日期 | {"workoutId": "123456", "date": "2026-10-24"} |
恢复与训练工具(0.1.14 新增)
DSH 和 MCP 共用以下工具,直接对应自行维护的 SDK API:
| 工具名 | SDK 方法 | 数据与参数示例 |
| get_garmin_hrv | getHrvData | 每日 HRV 状态、基线与完整夜间读数;{"date":"2026-10-15"} |
| get_garmin_hrv_summaries | getHrvSummaries | 每日 HRV 摘要;{"startDate":"2026-10-09","endDate":"2026-10-15"} |
| get_garmin_stress | getStressData | 每日压力与可用的 Body Battery 完整时序;{"date":"2026-10-15"} |
| get_garmin_stress_summaries | getStressSummaries | 每日压力摘要;{"startDate":"2026-10-09","endDate":"2026-10-15"} |
| get_garmin_body_battery | getBodyBattery | 每日身体电量报告及完整时序;{"startDate":"2026-10-09","endDate":"2026-10-15"} |
| get_garmin_training_readiness | getTrainingReadiness | 所有训练准备度快照与恢复因素;{"date":"2026-10-15"} |
| get_garmin_daily_training_status | getDailyTrainingStatus | 每日训练状态、急性/慢性负荷,保留所有返回设备;{"date":"2026-10-15"} |
| get_garmin_training_status | getTrainingStatus | 聚合训练状态、VO2 max 与负荷;{"date":"2026-10-15"} |
| get_garmin_training_load_balance | getTrainingLoadBalance | 截至指定日期的四周训练负荷平衡;{"date":"2026-10-15"} |
| get_garmin_max_metrics | getMaxMetrics | 每日最大指标,包括可用的 VO2 max;{"date":"2026-10-15"} |
| get_garmin_max_metrics_range | getMaxMetricsRange | 通过原生范围请求获取最大指标;{"startDate":"2026-10-09","endDate":"2026-10-15"} |
| get_garmin_race_predictions | getRacePredictions | 当前认证账号的最新比赛预测;{} |
| get_garmin_race_predictions_range | getRacePredictionsRange | 比赛预测历史;{"startDate":"2026-10-09","endDate":"2026-10-15","aggregation":"daily"} |
血氧与呼吸读取(0.1.18 新增)
DSH 和 MCP 共用以下只读工具,通过自行维护 SDK 的认证 HTTP 传输读取,保留服务端返回的完整响应,包括可用的摘要字段、描述符和时序数据:
| 工具名 | 客户端方法 | 数据与参数示例 |
| get_garmin_spo2 | getSpO2Data | 每日血氧(SpO₂)数据;{"date":"2026-10-20"} |
| get_garmin_respiration | getRespirationData | 每日呼吸数据;{"date":"2026-10-20"} |
例如可以问:“帮我看看 2026 年 10 月 20 日的血氧和呼吸记录。”两项工具均使用单日 date,不接收日期范围。是否有记录取决于所选账号、日期和设备实际记录的数据;缺失字段、null 和空数组保留原状,不填成 0。使用前需升级插件/MCP 并重新连接,再检查当前会话实际提供的工具 schema。
2026-10-21 已使用本机中国区、国际区 Session 验证共用 DSH/MCP 读取链路,并在真实 Harness 桌面对话中完成本地候选版的 4 次新工具调用。国际账号返回血氧与呼吸记录;大陆账号在测试日期返回成功,但测量字段为空。详见血氧与呼吸验收记录。
每日工具使用 date,默认主机本地当天日期。范围工具使用包含首尾的 startDate、 endDate;开始日期默认今天,结束日期默认等于开始日期。比赛预测历史的 aggregation 支持 daily(默认)和 monthly,最大日历跨度 366 天。所有日期必须是真实的 YYYY-MM-DD 日历日期。输出保留服务端原始响应字段、设备映射、未知字段与完整时序;null 或空数组属于正常的无数据结果,不会被当作认证失败。
Harness 配置多个账号时,访问账号数据的工具调用需添加 account 参数,值为设置页显示的稳定账号 ID;只有一个账号时可省略。显示别名帮助识别账号,区域决定 Garmin 服务,两者都不会替代账号 ID;同一区域可以配置多个账号。上述恢复工具也遵循此规则,例如 {"account":"personal","date":"2026-10-15"}。独立 MCP 使用该进程配置的账号,通过选择对应的 MCP 服务器区分账号,不接收工具级 account 参数。
创建训练采用两次调用流程。首次调用只返回预览和一次性 confirmationId;用户确认未更改的预览后,再使用相同训练定义、 confirmed: true 及该 confirmationId 调用。确认 ID 10 分钟后失效,且不可复用。
课表排期(0.1.20)
使用 Connect 网页会话账号,可以说:“创建这节训练并安排到 2026-10-24”,或 “把课表 123456 安排到 2026-10-24”。Personal API 账号仍只读。该能力由 0.1.20 正式提供。
- 新课表:向 create_garmin_workout 添加可选 scheduleDate: "2026-10-24"。一次预览展示课表与日期;用户明确确认后,以完全相同的参数、confirmed: true 和返回的 confirmationId 执行。不传日期只保存到训练库。
- 已有课表:用 workoutId、date 调用 schedule_garmin_workout 取得预览,用户确认后,以相同账号、课表、日期以及 confirmed: true 和一次性 confirmationId 执行。更换账号、课表或日期时重新预览和确认。
- 完成状态:日历写入成功后显示“已排期,等待 Garmin Connect 同步”。插件不主动触发手表同步,也不把排期成功称为已到手表。排期工具新增一次日历记录;移动或取消已有排期需要用户另行明确要求。
如果课表已创建但排期失败,保留返回的 workoutId,先通过 get_garmin_scheduled_workouts 查询目标日期;仍需补排时,只使用 schedule_garmin_workout 重新预览和确认,不要重复创建课表。任何写操作结果不明确时,先只读核对,再决定下一步。
开发候选已通过大陆主账号的真实 Harness 桌面验收:创建并排期、已有课表单独排期均成功,测试模板与两条排期已清理,原有 42 条训练库课表保留。详见排期实测记录。
课表删除与取消排期(0.1.17)
0.1.17 新增以下 3 个课表管理工具(该版本共 26 个工具):
已通过大陆主账号的真实 Harness 桌面验收,详见取消排期与删除课表实测记录。
| 工具 | 用途 | 预览参数示例 |
| get_garmin_scheduled_workouts | 查询包含首尾、最多 31 天的日历课表排期,获得真实排期 ID | {"startDate":"2026-10-18","endDate":"2026-10-24"} |
| delete_garmin_workout | 删除训练库中的课表模板 | {"workoutId":"123456"} |
| unschedule_garmin_workout | 取消一次日历排期,保留训练库模板 | {"scheduleId":"654321"} |
workoutId 与 scheduleId 是不同资源的 ID,不能互换。ID 支持正整数字符串;数字形式必须在 JavaScript 安全整数范围内。两个删除工具先读取目标并返回预览,用户确认后才以同一目标、confirmed: true 和对应 confirmationId 执行。确认绑定账号、动作与目标详情,10 分钟内一次有效;目标变化时重新预览。删除超时或返回结果不明确时先只读核对,不自动重放。
个性化跑步训练问询
get_running_skill_advice 明确区分“知识讲解”和“个性化规划”:
- mode: "explain" 只讲解课型或训练理念,不生成针对某位跑者的日程。
- 任何针对个人的建议或计划都必须使用 mode: "personalized"。下列六组信息必须全部回答;如果缺失,工具只返回需要追问的问题,不读取 Garmin 活动,也不得先猜测训练量、强度或生成逐日/逐周计划。
| 问询字段 | 助手必须询问的内容 |
| goal | 目标距离/赛事、未来的 ISO YYYY-MM-DD 日期,以及完赛目标或理想/最低可接受成绩 |
| currentPerformance + performanceBasis | 过去两年内代表性比赛/计时测试的距离、成绩、不晚于今天的日期、努力程度与条件,或明确填写 no_recent_benchmark |
| trainingBackground | 跑龄、最近 4–8 周跑量/时长、频率、最长跑、质量课和中断情况 |
| availability | 每周可训练天数和时长、固定休息/长跑日、场地限制、力量训练时间,以及是否具备双练条件 |
| healthConstraints + hasWarningSymptoms | 当前/过去一年伤病、疼痛、相关疾病/用药、睡眠和恢复,并明确回答是否存在健康警示症状 |
| trainingPreference + 偏好细节 | steady、hard_easy 或 mixed,并填写 maxQualitySessionsPerWeek(0–7)与 intensityGuidancePreference(pace、heart_rate、rpe 或 mixed) |
如果 hasWarningSymptoms 为 true(例如当前胸部不适、轻微活动异常气短、晕厥/眩晕或异常心悸),工具会直接返回安全停止结果,不返回课型素材,也不读取 Garmin 活动;它只建议先取得医疗专业人员许可,不自行诊断。如果 performanceBasis 为 no_recent_benchmark,则只建议先建立轻松跑基础或完成低风险基准测试,不能凭空给出精确门槛/间歇配速。
精简的训练理念层包括:
- 汉森法:高频、较均匀的周跑量,强调配速纪律和累积疲劳;不能脱离整套训练量单独照抄“16 英里长跑”。
- 丹尼尔斯法:用近期真实成绩估计当前 VDOT,再组合 E/M/T/I/R 强度;不能用目标成绩反推训练配速。
- 挪威阈值法:可借鉴受控、非力竭的阈值训练和难易日分离;默认不安排双阈值,也不照搬精英跑量或固定乳酸值。
- 极化训练:大部分训练真正轻松,少量训练明确艰苦;80/20 是方向,不是必须精确凑出的比例。
近期 Garmin 跑步数据只能补充上述问询,不能代替用户回答。方法来源、证据边界和适用限制见训练方法研究说明。
每条训练理念和课型卡还会把相应内容标成 system_principle(体系理念)、 research_evidence(研究证据)或 application_inference(应用推断),避免把方法定义误写成优越性证据。
快速开始
1. 安装本插件 — 从 npm registry(推荐)
npx @deepseek-ai/dsh plugin --profile web add dsh-plugin-garmin-connect
这一条命令会同时安装依赖并激活插件层,首次运行会自动初始化 web profile。你只需要 pnpm 在你的 PATH 中:
npm install -g pnpm
不启动即可验证插件层是否已组合进配置:
npx @deepseek-ai/dsh --profile web --dump-config | grep -A 2 garmin-connect
其他安装方式:
本地源码调试
cd garmin-connect-plugin-for-dsh && npm install
npx @deepseek-ai/dsh plugin --profile web add .
GitHub 源码安装
npx @deepseek-ai/dsh plugin --profile web add github:<owner>/<repo>
2. 安装 Harness CLI(如果还没有)
npx @deepseek-ai/dsh web
默认在 http://127.0.0.1:3080 打开 Web 界面。如果通过 npx 启动,下面的命令同样加上 npx @deepseek-ai/dsh 前缀;如果已全局安装 dsh,则可以去掉 npx @deepseek-ai/ 前缀。
3. 准备登录时再配置 Garmin 账号
每个账号分别选择接入方式。原有浏览器流程继续可用;新的 Personal API 方式见下方说明。
官方 Personal API(0.1.19 新增)
0.1.19 已提供。 插件使用参考佳明官方 Python 客户端开发、独立维护的 connect-personal-api-ts, SDK 已以 @likenttt/connect-personal-api-ts@0.1.0 发布到官方 npm。所需 SDK 随插件提供,使用者无需额外安装。
SDK 负责 Personal API Key 换取令牌及其支持的数据读取。
在 Harness 插件设置中,点击 +,选择官方 Personal API(国际版,只读) 接入方式,填写别名和 API Key,保存后点击验证连接。不要求邮箱或 Garmin 密码; 新建 Personal 账号只需别名和 API Key 两项,默认连接国际版 .com,不要求填写邮箱、密码或地区。已有大陆 Personal 账号保留 cn 配置,并显示当前不可访问提示。
保存后的 Key 不会回填到设置表单,也不返回给 AI 工具。
真实 Harness 桌面截图和桌面验收报告记录了候选版的 6 次真实读取:5 次 Personal API、1 次原大陆网页会话,全部通过。重启后设置保留,再次验证连接成功。
独立 MCP 可直接使用正式 npm 包:
{
"mcpServers": {
"garmin-personal": {
"command": "npx",
"args": ["-y", "--registry=https://registry.npmjs.org/", "--package", "dsh-plugin-garmin-connect@0.1.20", "garmin-connect-mcp"],
"env": {
"GARMIN_PROVIDER": "personal",
"GARMIN_ACCOUNT": "my-garmin",
"GARMIN_ALIAS": "我的佳明国际版", "GARMIN_REGION": "global", "GARMIN_PERSONAL_API_KEY_FILE": "/absolute/private/path/garmin-personal.key" } } } }
密钥文件只包含 Key,使用仅所有者可访问的权限。也支持由私密环境注入 GARMIN_PERSONAL_API_KEY;真实 Key 不写入可分享的 JSON、源码、截图或 AI 对话。
这种方式不需要 GARMIN_USERNAME 或浏览器 session。GARMIN_ALIAS 是显示别名, GARMIN_ACCOUNT 是稳定的机器 ID,两者均不是邮箱。独立 MCP 保留显式地区配置: GARMIN_REGION=global 使用 personal.connectapi.garmin.com,GARMIN_REGION=cn 使用 personal.connectapi.garmin.cn;应与创建 Key 的区域对应。Personal 认证失败不会静默切换浏览器会话,也不会把 Key 发送到另一区域。
Personal 支持其公开范围内的读取,包括 HRV、血氧;呼吸读取为可用的日/睡眠汇总。
创建、删除课表和日历操作仍需单独配置Connect 网页会话(原有方式)账号,Personal 当前不提供这些操作或 Webhook。原有方式虽然在 Garmin 官方页面登录,其网页会话数据调用并不等于 Personal API 官方授权。详见图文申请指南与实测结果及官方申请说明。
2026-10-22 区域验证:国际账号新建的独立 Key 请求 .com,令牌交换、8 项 SDK 读取和 5 项真实 MCP 工具读取通过;大陆 Key 请求 .cn 返回 HTTP 526, 大陆 Personal 端点当前不可用。两区凭据分开保存与使用,没有跨区回退。详见端点测试报告。
维护 SDK 时,先提交独立仓库,再运行 npm run sync:personal-sdk -- /absolute/path/to/connect-personal-api-ts。
插件内的源码快照会记录来源提交、文件哈希与版权声明。
浏览器 Connect 配置
Harness 插件安装和启动时可以不填 Garmin 邮箱。在本机 Harness 的插件页面打开 dsh-plugin-garmin-connect,找到Garmin 账号配置,点击 + 逐个添加账号,最多五个。每个账号分别选择中国区(cn)或国际区(global),同一区域可添加多个账号,也可设置显示别名。点击保存并登录后,Harness 会在内嵌页面打开 Garmin 登录流程;密码和 MFA 验证码仍输入在 Garmin 官方页面。已保存的邮箱会以掩码显示,点击邮箱框可输入新邮箱,已保存的完整邮箱不会回传到设置页。更换邮箱时点击保存并重新登录,用新邮箱启动 Garmin 登录。每个账号都有独立会话和设置页可见的稳定账号 ID;配置多个账号时,工具调用需指定该 ID 作为 account 参数,以免读取或写入错误的账号。
CLI、MCP 或无界面运行时可以通过环境变量(或启动器提供的密钥存储)配置账号,请确保 .env 不进入版本控制。本机 Web MFA 流程会在用户确认 profile 后,由 Host 原子保存仅所有者可访问的 DI session 文件,但绝不会保存密码、MFA 验证码或 CAPTCHA 答案。
仅源码目录:复制随仓库提供的模板
cp .env.example .env
仅在使用 CLI/MCP 或环境变量配置时编辑 .env
如果通过 registry 安装且选择环境变量配置,请在运行 dsh 的目录(工作区根目录)新建 .env,再按下表填写变量;包内模板不会出现在当前工作目录。插件启动时会自动加载该文件。插件设置中明确保存的邮箱优先于 GARMIN_USERNAME。
| 环境变量 | 必填 | 说明 |
| GARMIN_USERNAME | 浏览器 CLI/MCP | Garmin 账号邮箱;Harness 用户可在安装后通过插件设置填写。Personal API 不需要 |
| GARMIN_ACCOUNT | ❌ | Web/CLI/MCP 隐式 session 路径使用的小写本地别名(未设置时为 default) |
| GARMIN_PASSWORD | ✅* | 旧版直接登录密码;不要用于下方的 MFA 交互式初始化 |
| GARMIN_SESSION_TOKEN | ✅* | 内联预认证令牌(仍支持,但 session 文件更安全) |
| GARMIN_SESSION_TOKEN_FILE | ✅* | 本地认证命令生成的 owner-only DI v2(或兼容的旧 OAuth)session 文件路径 |
| GARMIN_REGION | ❌ | global(默认,国际版)或 cn(佳明中国) |
| GARMIN_FIT_DOWNLOAD_DIR | 仅 FIT | 用户为 FIT 导出显式选择的主机父目录;无默认值,生成的账号目录会包含 GARMIN_REGION |
| GARMIN_CACHE_TTL | ❌ | 缓存有效期,单位秒(默认 300) |
| GARMIN_REQUEST_TIMEOUT_MS | ❌ | Garmin 请求超时,单位毫秒(默认 15000) |
| GARMIN_LOG_LEVEL | ❌ | 日志级别:debug \| info \| warn \| error |
| GARMIN_ACTIVITY_DETAIL | ❌ | full(默认,保留活动列表中可用的扩展字段;仅当 Garmin 提供时才包含圈数和分段摘要,且可能包含精确路线/位置)或 compact(精简输出)。凭据及无关账号/社交标识会被过滤。 |
\* 浏览器 Connect 读取数据时,GARMIN_PASSWORD、GARMIN_SESSION_TOKEN、 GARMIN_SESSION_TOKEN_FILE 三选一即可;本机 Web、auth:serve 和独立 MCP 可以在三者都没有时启动,并创建隐式账号 session 文件。开始登录前仍需配置账号邮箱; Harness 用户可以安装后在插件设置中填写。受保护的 session 文件比内联 token 更安全,尤其适合隔离多个进程。如果同时配置,内联 token 会优先于文件,直到 Garmin 明确拒绝它;此后新写入且账号匹配的 session 文件可在重试时接管。有效 session 优先于密码登录。
⚠️ 如果密码包含 # 等特殊符号,请用双引号包裹,否则 # 后的内容会被当作注释截断:
GARMIN_PASSWORD="my#secret!pass"
GARMIN_SESSION_TOKEN 与 GARMIN_SESSION_TOKEN_FILE 的内容都和密码一样敏感。
Token 导出不会作为 AI 可调用工具提供,也绝不要把 Token 粘贴进 AI 对话。
两步验证——浏览器 MFA
当 dsh 与它的 Web UI 运行在同一台本机时,先在插件的Garmin 账号配置中保存对应区域和邮箱,再在设置页点击该账号的登录。每个账号分别使用自己的登录流程和会话。Harness 内嵌页面会打开随机 127.0.0.1 端口上的自定义桥页;Garmin 官方 GAuth 页面嵌入这个独立桥页,而不是直接嵌入 dsh 页面。账号邮箱会保存在本机 Harness 插件配置中;Garmin 登录页上再次输入的邮箱、密码、MFA 验证码和任何 CAPTCHA 都留在 Garmin iframe 中。
让这套流程既可用又安全,远不是增加一个“验证码”输入框那么简单。我们首先把 Garmin 官方 GAuth 页面保留在本地 iframe 中,让 Garmin 登录表单字段留在 Garmin origin;随后逐一处理了跨域消息、官方样式缺失、CSP/Trusted Types、第三方 frame 策略、MFA 重定向和精确 ticket/service 绑定。受 Zhitao 在 DailySync 中“用新标签页完成 Garmin SSO”思路的启发,我们又为 CLI 和 MCP 客户端加入了系统浏览器 loopback broker。新标签页返回的只是一次性、短期 service ticket;Host 会立即将它交换为更长期的 DI session/refresh 凭据,复核 Garmin profile,并以 owner-only 方式落盘。因此“可能长期(包括约一年)可用”的是交换后的 session/refresh 凭据,不是 service ticket 本身;实际有效期始终由 Garmin 决定。
Garmin 产生的短期 service ticket 只会到达隔离的 loopback 桥页。桥页会校验预期区域、消息来源、iframe 来源、service 与 ticket,然后立即交给插件 Host 执行严格绑定区域的 DI token 交换。中国区 Garmin 在 MFA 后可能把 ticket 绑定到本次精确的 http://127.0.0.1:<端口> 桥页,而不是固定的 Garmin embed URL;插件会原样保留 ticket/service 配对,并在请求 DI 前拒绝其他 loopback 主机、端口、路径、查询参数或区域。
一次性 ticket 不会被改写 service 或用后备 service 重试。Host 探测 Garmin profile,向用户显示安全化后的 profile 供确认。只有用户确认该 Garmin 账号与配置邮箱对应后,才原子写入绑定配置账号与区域、且仅所有者可访问的 session。外层 dsh 页面会收到公开的登录进度;账号完成身份验证后,设置页可显示该账号邮箱。模型上下文和 AI 可调用工具返回都拿不到 ticket、DI token、密码、 MFA 验证码或 CAPTCHA 答案。
当 Host 已通过密码登录、绑定 profile 的 DI session 或刚完成的 Web 登录确认账号身份时,插件设置中对应账号会显示已登录。仅加载但尚未验证身份的旧版 OAuth token 不会显示为已登录;状态接口也不会返回 ticket 或 token。登录对话框只在用户点击该账号的设置页登录操作时打开。缺失或过期的 session 不会自动弹窗。
打开对话框前需在对应账号卡片中保存邮箱。该 Web 流程可不设置 GARMIN_SESSION_TOKEN_FILE:Host 会为每个账号使用各自独立、仅所有者可访问的 session 文件,迁移后的旧账号沿用原路径。用户确认并成功落盘后,当前插件会清除之前的 session 拒绝状态;下一次工具调用即可读取新文件,不需要重启 dsh。
该受支持的 Web 流程有意只支持 dsh 的 loopback 本机网页,不是远程、托管或隧道登录端点。
浏览器的第三方 Cookie 与 iframe 策略可能让 Garmin GAuth 无法完成。2026-08-29 已在本机跑通真实中国区 MFA 的浏览器、DI 交换、profile 确认、owner-only 落盘和只读 session 使用链路;国际区真实账号 MFA 也已跑通系统浏览器挑战、DI 交换、profile 确认和 owner-only session 落盘。这并不把同机流程扩展成远程或无限期 session 恢复保证。登录、MFA 与 profile 确认必须在桥页的 10 分钟有效期内完成。
完整的信任边界与数据流见两步验证登录目标架构。
本机系统浏览器认证
CLI 与 MCP 客户端推荐使用 loopback broker MFA 流程,并显式选择账号别名与区域。
该命令强制同时提供两个参数,不会从 GARMIN_ACCOUNT/GARMIN_REGION 推断,以免双账号环境把 session 写到错误账号:
已安装的可执行命令 garmin-connect-auth serve --account personal --region global --open garmin-connect-auth serve --account personal-cn --region cn --open
源码目录
npm run auth:serve -- --account personal --region global
npm run auth:serve -- --account personal-cn --region cn
serve 会在随机 127.0.0.1 端口启动一次性桥页,并用系统默认浏览器打开。它不会创建或管理隔离的 Chrome/Playwright profile;操作系统可能复用已经运行的默认浏览器,也可能启动已配置的默认浏览器。CLI 可能读取已配置的账号邮箱,但密码、MFA 验证码和 CAPTCHA 始终只在 Garmin 页面中输入,不能通过命令行参数、环境变量、MCP 工具参数或模型输入传入。桥页只接收短期 service ticket,并交给本地 runtime 完成区域绑定的 DI exchange;页面显示安全化 profile 供确认后,runtime 才写入 owner-only session。
登录、MFA 与 profile 确认未在 10 分钟内完成时,本次流程会过期,需要重新发起。
未配置 GARMIN_SESSION_TOKEN_FILE 时,输出路径由 GARMIN_ACCOUNT/--account 推导: POSIX 常规配置路径为 ~/.config/dsh-plugin-garmin-connect/accounts/<alias>.session.json(其他平台使用对应配置根目录)。随后进程只需下列非密码配置:
GARMIN_USERNAME=your-email@example.com
GARMIN_ACCOUNT=personal
GARMIN_REGION=global
GARMIN_FIT_DOWNLOAD_DIR=/absolute/path/to/garmin-fit-parent
该浏览器初始化已正式支持中国区和国际区的同机认证。2026-08-29 已在本机跑通两个区域的真实 MFA。真实 refresh token 轮换仍会纳入持续兼容性覆盖,但不再影响 MFA 的正式支持状态。
旧版浏览器诊断
garmin-connect-auth login --browser 仅保留用于开发和诊断,不再是 serve 或 MCP 认证的推荐后备。它通过 Playwright 启动隔离 Chrome,仍可能遇到重定向拦截。无落盘 canary 也使用这条旧链路:
garmin-connect-auth login --browser --account personal --region global
garmin-connect-auth login --browser --account personal-cn --region cn
npm run auth:canary -- --region global
npm run auth:canary -- --region cn
为兼容旧用法,不带 --browser 的终端密码尝试仍保留。密码提示处直接回车会打开共享的系统浏览器流程;检测到明确的 MFA/CAPTCHA 页面标记时也会转到同一流程,不再在终端询问 MFA 验证码。含糊的密码、网络或 no-ticket 错误不会自动打开浏览器。这些诊断入口与正式支持的系统浏览器 MFA 初始化相互独立。
DI v2 文件会通过不可逆摘要绑定规范化 username、region,以及刚探测到的 Garmin profile(包括 profileIdHash);绑定信息不会重复保存明文邮箱。运行时会在发布刷新后的凭据前拒绝 username、region 或 profile 不匹配的文件。access token 会在到期前提前刷新,轮换后的 refresh token 会先安全写回再投入使用;认证失败时只允许幂等 GET 最多重放一次,训练创建等写请求绝不会自动重放。
为保持向后兼容,只有 oauth1、oauth2 两个字段的旧 session 文件仍可读取。旧文件没有可校验的 profile 绑定;预期替代方案是浏览器生成、带错账号保护且经过验证的 DI v2 session。在 POSIX 系统中,旧文件本身仍须通过当前 owner-only 文件权限检查(通常为 0600)、完整安全祖先链校验,以及最终私有父目录校验(通常为 0700)。
POSIX 上会在打开 Garmin 认证前准备默认账号目录。如需自定义 session 文件,可添加 --output /absolute/private/path/personal.session.json。预检会规范化已有且安全的链接目标、拒绝可被他人写入的不安全祖先,并要求最终父目录属于当前有效 UID、owner 具备写入和执行权限且 group/other 无任何权限(通常为 0700);缺失层级会逐级以 0700 创建。写入器使用规范化后的目标,并在原子替换前再次核验父目录、已有目标和 no-follow 临时文件句柄。
macOS 上还会拒绝每个已检查祖先、父目录、已有文件和空临时文件中的授权型扩展 ACL;仅有看似私有的 0700/0600 mode 并不能绕过该校验。
如果常规配置根目录或其任一祖先目录可由 group/other 写入,预检会有意拒绝启动认证。
请自行修复该目录权限,或把 GARMIN_SESSION_TOKEN_FILE/--output 指向全新的 owner-only 应用目录;插件不会静默 chmod 共享或宽松权限的配置目录树。
Windows 上,隐式账号路径会优先使用当前用户的本机 LOCALAPPDATA,而不是可能被重定向的漫游 APPDATA。显式目标也请放在当前用户的本机系统 profile/config 根目录之下,并使用全新的专用子目录树;不支持 UNC/网络目录。从最长匹配的 Windows 特殊目录根到 session 父目录,每一级都必须使用受保护 DACL:owner 是当前 SID,且只有一条当前 SID 的 FullControl 规则。缺失层级会以该 DACL 原子创建;已有但不精确的层级和任何重解析点都会被拒绝,不会被改写。空临时文件也会在写入凭据字节前应用同样严格的文件 DACL,读取 session 时还会重新验证整条目录链和文件 ACL。早期实现中仅靠标记的目录不再可信;请迁移到全新的专用子目录树。
多账号:每个账号使用独立进程
当前支持的运行时模型是“每账号每进程隔离”:每个 dsh、Codex、Claude Code 或其他 MCP 进程分别设置自己的 GARMIN_USERNAME、GARMIN_REGION 与 GARMIN_ACCOUNT(或显式的 GARMIN_SESSION_TOKEN_FILE)。每个进程都可延迟读取自己的隐式账号 session 路径并使用正式支持的浏览器 MFA 初始化;真实中国区账号链路已完成端到端验证。
不要把一个 session 文件复制给其他进程,也不要让并发进程共享同一文件。Garmin 的 refresh token 可能轮换,否则并发写入可能互相覆盖或使凭据失效。例如分别使用 personal-dsh、personal-codex、personal-claude 别名,并为每个进程使用独立初始化的 session。不要通过符号链接或大小写不同的路径别名,让另一个运行时指向同一个物理文件。
多个进程可以共享同一个 GARMIN_FIT_DOWNLOAD_DIR 父目录,插件会按各自配置的区域和邮箱自动建立独立账号子目录,因此同一邮箱的 cn 与 global 账号也不会冲突。只有一个 MCP 条目时,普通 Garmin 查询默认使用该条目;有两个条目时命名为 garmin-cn 和 garmin-global,仅在目标账号有歧义时才需要在提问中指出服务器名。
这是进程隔离,不是单进程账号选择器,也不是多租户授权系统。不要把同一个 MCP 进程共享给互不信任的用户;当前尚未实现按用户访问控制。在同一对话中切换账号和自动跨账号同步仍属于路线图能力。
下载 FIT
download_garmin_activity_fit 只接受 activity ID,模型不能指定任意输出路径。工具先把 Garmin 原始活动 ZIP 下载到私有临时位置,执行大小限制,并要求归档中恰好存在一个有效 FIT 文件。假设用户配置的父目录是 ,最终路径为 /GARMIN_FIT_<cn|global>_<规范化邮箱>/<activityId>.fit,且不会覆盖已有文件。
cn 或 global 来自 GARMIN_REGION。<规范化邮箱> 会经过安全规范化:普通邮箱保持可读,路径分隔符、控制字符等不安全文件名字符会先被处理,再创建账号目录。用户根据自己配置的父目录和此规则定位文件。工具只返回 activityId、fileName、sizeBytes 和 sha256,不会返回父目录、账号子目录、邮箱或完整路径;ZIP/FIT 二进制内容也不会进入模型上下文。
父目录没有默认值,必须由用户通过 GARMIN_FIT_DOWNLOAD_DIR 显式选择。它只在调用此工具时必需;未设置时工具会在写入任何文件前失败,其他 Garmin 工具仍可正常使用。
多个账号进程可以安全共享同一个父目录,因为“区域+规范化邮箱”子目录会自动隔离,即使中国区与国际区使用同一邮箱也不会冲突。
已有的 GARMIN_FIT_<邮箱> 目录不会自动迁移;新下载使用带区域前缀的目录,旧文件保留在原位。
Garmin 的“原始文件”并不保证一定是 FIT。如果归档中没有唯一有效的 FIT 条目,工具会安全失败,不会把其他格式伪装成 .fit。
4. 启动
npx @deepseek-ai/dsh web
打开 http://127.0.0.1:3080。当 设置 → 插件 → 插件列表 中显示 plugin-garmin-connect 为 已挂载、已启用 时,说明插件已成功加载。然后直接对话:"我昨晚睡得怎么样?" 或 "帮我看一下最近 5 次跑步。"
5. 集成测试(可选,仅限源码目录)
集成测试脚本仅用于开发,不包含在 npm 包中。在已安装开发依赖的源码目录里配置好 .env 后,可以运行它验证 API 连通性:
npm run test:integration
脚本只检查读取接口;任一检查失败都会以非零状态退出。它不会创建、更新或删除训练及其他 Garmin 数据。
默认会隐藏账号标识,并只输出数量/状态,不显示活动或健康数值。只有在明确希望把规范化详情输出到本地终端时,才设置 GARMIN_INTEGRATION_VERBOSE=true。
📋 点击展开完整示例输出
🔌 Garmin Connect Integration Test
Domain : garmin.com
User : configured (identifier hidden)
Date : 2026-08-18
Scope : read-only (workout creation/update/deletion is not tested)
── 1. Authentication ──
✅ Password login successful
── 2. Activities ──
✅ Got 3 activities
── 3. Sleep ──
✅ Sleep data loaded
── 4. Steps ──
✅ Step data loaded
── 5. Heart Rate ──
✅ Heart-rate data loaded
── 6. Weight / Body Composition ──
✅ Body-composition data loaded
── 7. Workout Library ──
✅ Got 5 workout templates
── 8. User Profile ──
✅ Profile loaded
🏁 Integration test complete: 8 passed, 0 failed.
Write operations were intentionally not tested.
npm peer 依赖排错
legacy-peer-deps 的 npm 默认值 就是 false,常规命令无需额外指定。若通过 npx 启动时报依赖缺失,先用 npm config get legacy-peer-deps 检查;仅当结果为 true 时,可尝试 npx --legacy-peer-deps=false @deepseek-ai/dsh web,让本次命令恢复正常的 peer 依赖解析。缺少模块也可能有其他原因,仍需结合报错中的包名与安装状态排查。
🔐 安全设计
凭据只在本地用于直接登录 Garmin Connect,且绝不会由 AI 工具返回。
凭据解析优先级
1. 插件配置值(本机 Garmin 账号配置表单、profile patch 或 --patch 中指定的 config) ↓ 回退
2. 环境变量(.env 文件 / Shell 环境) ↓ 回退
3. Schema 中定义的默认值
安全措施一览
| 措施 | 状态 |
| 支持环境变量及标记为 secret 的配置 | ✅ |
| .env 已加入 .gitignore,不会被提交到 Git | ✅ |
| 账号标识与凭据字段均标记为 role('secret') | ✅ |
| dsh 本机 Web MFA 桥页 | ✅ 已支持;仅 loopback;真实中国区 MFA 链路已在本机通过 |
| CLI serve 与 MCP URL elicitation | ✅ 已支持;同机共享 runtime 与 owner-only session 落盘 |
| 旧 CLI login --browser / canary | ⚠️ 仅 Playwright 诊断,不作为认证后备 |
| DI v2 session 绑定 username、region 与 profileIdHash;旧两字段 session 保持兼容 | ✅ |
| 每进程独立初始化的 session 文件支持进程隔离多账号 | ✅ |
| access token 提前刷新;幂等 GET 最多重放一次,写请求不重放 | ✅ |
| 工具返回值中不包含任何原始凭据 | ✅ |
| FIT 二进制及本地/账号路径留在主机,模型只收到活动 ID、文件名、大小与 hash | ✅ |
| 内存缓存减少 API 调用次数,防止触发 Garmin 限流 | ✅ |
Session Token
仍然支持 Session Token 登录,但 Token 本身就是凭据,不能出现在代理输出或轨迹日志中。
因此,本插件不会把认证、MFA 提交或 Token 导出暴露为 AI 可调用工具。如果已经拥有经过验证的 owner-only DI v2 或兼容旧 session 文件,dsh/MCP 可以通过 GARMIN_SESSION_TOKEN_FILE 读取它,运行时不再需要账号密码。DI 文件会绑定规范化 username、region 和 profileIdHash;为兼容旧版本,无绑定的 oauth1/oauth2 两字段文件仍可读取。通过上方 dsh Web 桥页、serve 或 MCP URL elicitation 创建新的 MFA session 是正式支持的同机工作流。Garmin refresh token 可能轮换,因此 dsh、Codex、Claude Code 或其他进程之间不得并发共享或复制同一文件。
在其他 AI 编程助手中使用(MCP 协议)
本插件同时提供了一个独立的 MCP (Model Context Protocol) 服务器,让你可以在 OpenAI Codex、Claude Code、Claude Desktop、Cursor、Windsurf、WorkBuddy、ZCode 等任何支持 MCP 的客户端中使用相同的 Garmin 工具 — 无需安装 DeepSeek Harness。
当前可用性: npm 0.1.5 及之后版本已包含独立 MCP 入口;本地源码方式仍适合开发。
0.1.17 新增:连接时的 Agent 执行说明。 MCP 初始化会下发 instructions,指导 Agent 检查实际工具 schema、在首次读取账号数据或账号变化时确认资料、使用明确日期,并区分空数据、认证失败和其他请求错误。初始化仅发送说明,不会自动查询健康数据、升级软件或写入 Garmin。
使用此功能需要包含该改动的版本,并重启 MCP 进程、重载连接器。只更新 SDK 或 skill 不会给正在运行的旧连接增加工具。客户端决定是否将 server instructions 提供给模型;不支持时仍可使用随包的 garmin-connect skill。说明能改进调用流程,不能保证 Garmin 接口返回数据。
先构建本地服务器:
git clone https://github.com/Likenttt/garmin-connect-plugin-for-dsh.git
cd garmin-connect-plugin-for-dsh
npm install
npm run build
请把示例中的 /absolute/path/to/garmin-connect-plugin-for-dsh 替换为本地源码目录的真实绝对路径。
MCP 进程需要邮箱、显式区域和本地账号别名。session 文件路径可以不配置;此时服务会根据 GARMIN_ACCOUNT 推导 owner-only 路径。让客户端进程获得这些值及可选 FIT 父目录:
export GARMIN_USERNAME='你的佳明邮箱'
export GARMIN_REGION='cn'
export GARMIN_ACCOUNT='personal-cn'
export GARMIN_FIT_DOWNLOAD_DIR='/absolute/path/to/garmin-fit-parent'
可选覆盖;否则使用 accounts/personal-cn.session.json。
export GARMIN_SESSION_TOKEN_FILE='/absolute/path/to/personal-cn.session.json'
不要在这些环境变量中放密码或 MFA 验证码。工具遇到 session 缺失、过期、被拒绝或明确的 MFA/CAPTCHA 浏览器挑战,且客户端声明支持 MCP URL elicitation 时,本次工具调用会返回一个随机的本机 127.0.0.1 登录链接。打开链接,在浏览器中完成 Garmin 登录/MFA 与 profile 确认,等待完成通知后,再重试原请求。服务端不会自动重放,因此不会借认证流程重复执行写入。
不支持 URL elicitation 的客户端会收到等价的可信终端回退命令:
若环境中仍保留旧的 GARMIN_PASSWORD,无需 MFA 的密码登录仍可继续工作。只有 Garmin 响应中出现明确的 MFA 输入/表单或活动 CAPTCHA 标记,才会转换成同一个可由浏览器恢复的 MCP 认证状态;SDK 含糊的 no-ticket 文本、错误密码、HTTP 401 与网络错误不会被当作 MFA。
密码和上游错误文本都不会进入工具结果。
garmin-connect-auth serve --account personal-cn --region cn --open
如果该 MCP 条目显式设置了 GARMIN_SESSION_TOKEN_FILE,请在可信终端导出同一个值,或给命令追加 --output 并使用相同目标。回退错误不会把本机路径回显到模型上下文。
serve 成功写入内容已变化且账号匹配的 session 后,重新调用工具即可让仍在运行的 MCP 进程热加载同一个安全文件快照,无需重启 MCP。内容未变化的已拒绝文件、refresh 已过期的替换文件或其他账号的文件都不会被再次发给 Garmin 探测。如果内联 GARMIN_SESSION_TOKEN 已被明确拒绝,这个安全替换也会在内存中接管,旧内联凭据不会重试。
密码和 MFA 验证码只进入 Garmin 页面,不进入 MCP 工具或模型。session 文件与 FIT 父目录都需要保护,因为它们可能授予账号访问能力或包含精确位置与健康数据。每个同时运行的客户端进程都要使用独立别名/session,不得在 Codex、Claude Code、dsh 等进程间复制或并发共享同一文件。浏览器 MFA 已按上文正式支持,真实中国区账号链路已完成端到端验证。
OpenAI Codex(桌面端、CLI 与 IDE 扩展)
同一主机上的 Codex 客户端共用 ~/.codex/config.toml。推荐只在配置中声明需要转发的环境变量名,不把凭据值复制到 TOML。确保 Codex 进程能够读取上面的变量后,把以下内容加入 ~/.codex/config.toml:
[mcp_servers.garmin-connect]
command = "node"
args = ["/absolute/path/to/garmin-connect-plugin-for-dsh/lib/mcp.js"]
env_vars = ["GARMIN_USERNAME", "GARMIN_REGION", "GARMIN_ACCOUNT", "GARMIN_SESSION_TOKEN_FILE", "GARMIN_FIT_DOWNLOAD_DIR"]
只读工具可正常运行;写本地文件或 Garmin 数据前由 Codex 请求批准。
default_tools_approval_mode = "writes"
此配置使用单独分配给该 Codex 进程的 session。若 Codex 声明 URL elicitation 能力,它可以显示上文的本机登录链接;否则用同一别名执行可信终端 serve 命令。密码/MFA 仍只进入 Garmin 页面。不要复用已经分配给 dsh、Claude Code 或其他运行中进程的 session。国内与国际账号可分别新增 garmin-cn、garmin-global 等服务器表。它们可复用同一个 FIT 父目录,输出会自动进入该账号的“区域+规范化邮箱”子目录。
Codex 进程必须继承上面导出的变量。如果桌面端不是从该终端启动,请在 Settings → MCP servers 中添加服务器并提供环境变量,或通过你日常使用的密钥注入环境启动它。设置界面中填写的值属于本地凭据,请保护生成的配置文件。
如果只希望当前可信项目使用,可把同一配置写入项目内的 .codex/config.toml。
修改后重启 Codex 客户端,并检查已保存的配置:
codex mcp list
codex mcp get garmin-connect
在 Codex CLI 内输入 /mcp,确认服务器已经连接并查看工具。设置界面及 codex mcp add 的更多用法见 Codex 官方 MCP 文档。
Claude Code
Garmin 通常属于个人服务,因此推荐使用 user scope。下面的 bash/zsh 示例不会把 session 内容写入 ~/.claude.json,只配置 owner-only 文件路径:
claude mcp add-json --scope user garmin-connect \
'{"type":"stdio","command":"node","args":["/absolute/path/to/garmin-connect-plugin-for-dsh/lib/mcp.js"],"env":{"GARMIN_USERNAME":"${GARMIN_USERNAME}","GARMIN_REGION":"${GARMIN_REGION:-global}","GARMIN_ACCOUNT":"${GARMIN_ACCOUNT:-default}","GARMIN_SESSION_TOKEN_FILE":"${GARMIN_SESSION_TOKEN_FILE}","GARMIN_FIT_DOWNLOAD_DIR":"${GARMIN_FIT_DOWNLOAD_DIR}"}}'
该服务器使用单独分配给此 Claude Code 进程的 session。客户端若未显示 MCP URL elicitation,就用可信终端 serve 命令初始化;密码/MFA 仍只进入 Garmin 页面。每增加一个进程或账号,都以不同名称注册服务器并提供另一个独立初始化的 session 文件;不要复制其他进程的 session。
这些服务器可以复用同一个 FIT 父目录。
如果只希望当前项目使用,把 --scope user 改为 --scope local。以后每次启动 Claude Code 时都要保证这些路径变量可用,然后检查连接:
claude mcp get garmin-connect
claude mcp list
在 Claude Code 内输入 /mcp 可以查看连接状态和工具。作用域与 .mcp.json 的更多说明见 Claude Code 官方 MCP 文档。
不要把个人 Garmin 凭据提交到项目级配置。
在 Codex 或 Claude Code 中实际使用
当 garmin-connect 显示已连接后,直接用自然语言提问即可,客户端会自动选择 MCP 工具。如果工具选择不明确,可以明确说“使用 garmin-connect MCP 服务器”。例如:
- “使用 garmin-connect 查看我最近五次跑步。”
- “对比我最近七天的睡眠和静息心率。”
- “把 activity 123456789 的 FIT 下载到我配置的 Garmin FIT 父目录下。”
- “预览一个门槛跑训练,把步骤展示给我;在我确认前不要创建。”
创建训练仍然执行强制的两次调用确认流程:第一次只返回预览;只有用户批准并带上返回的一次性 confirmationId 后,第二次调用才会创建。
Claude Desktop
编辑 ~/Library/Application Support/Claude/claude_desktop_config.json(macOS)或 %APPDATA%\Claude\claude_desktop_config.json(Windows):
{
"mcpServers": {
"garmin-connect": {
"command": "node",
"args": ["/absolute/path/to/garmin-connect-plugin-for-dsh/lib/mcp.js"],
"env": {
"GARMIN_USERNAME": "你的佳明邮箱", "GARMIN_REGION": "cn", "GARMIN_ACCOUNT": "personal-cn", "GARMIN_SESSION_TOKEN_FILE": "/absolute/path/to/personal.session.json", "GARMIN_FIT_DOWNLOAD_DIR": "/absolute/path/to/garmin-fit-parent" } } } }
重启 Claude Desktop 后,你会看到 🔌 图标表示工具已加载。试试说:"帮我看下最近 5 次跑步记录" 或 "帮我预览一个门槛跑训练"。
Cursor
把上方相同的 mcpServers.garmin-connect 对象写入工作区 .cursor/mcp.json,并使用 lib/mcp.js 的绝对路径。
Windsurf
打开 Windsurf Settings → Cascade → MCP Servers,或编辑 ~/.codeium/windsurf/mcp_config.json,加入上方相同的 mcpServers.garmin-connect 对象。
WorkBuddy
WorkBuddy 桌面端支持用户级和项目级的本地 MCP。Garmin 属于个人健康数据,推荐使用用户级 ~/.workbuddy/mcp.json。打开 插件 → MCP 服务器 → 配置 MCP,或直接编辑该文件,加入:
{
"mcpServers": {
"garmin-connect": {
"command": "/absolute/path/to/node",
"args": ["/absolute/path/to/garmin-connect-plugin-for-dsh/lib/mcp.js"],
"env": {
"GARMIN_USERNAME": "你的佳明邮箱", "GARMIN_REGION": "cn", "GARMIN_ACCOUNT": "personal-cn", "GARMIN_SESSION_TOKEN_FILE": "/absolute/path/to/personal.session.json", "GARMIN_FIT_DOWNLOAD_DIR": "/absolute/path/to/garmin-fit-parent" } } } }
macOS/Linux 用 command -v node、Windows 用 where node 查找 Node.js 的绝对路径;GUI 应用不一定继承 nvm 的 shell 路径。Windows JSON 路径请使用 C:/.../node.exe 形式,或把每个反斜杠写成 \\。WorkBuddy 的本地命令格式不要添加 type。保存后确认服务器状态变绿,再从只读查询开始测试。参见 WorkBuddy 官方 MCP 指南。
这里的 session 文件必须独立初始化;客户端若未显示 URL elicitation,就使用可信终端 serve 命令。WorkBuddy 与模型不会接收密码/MFA 验证码。每增加一个账号,就新增一个命名的 mcpServers 条目,并使用独立的 session 文件;多个条目可共享同一个 FIT 父目录,“区域+邮箱”账号子目录会自动生成。
随包附带的技能
从 0.1.7 起,npm 包内附带 skills/garmin-connect/。将这个完整目录复制到 ~/.workbuddy/skills/garmin-connect/,保留其中的 references/。如果已安装该技能,也需要同步更新已安装副本;仅升级 npm 包不会自动更新技能。重新加载 WorkBuddy 的技能与 MCP 服务,再新开会话使用。
随包技能已加入 references/recovery-analysis.md,用于 HRV 趋势、训练准备度、压力、Body Battery、负荷与表现查询。按当前会话实际工具及 schema 选择调用;单独更新技能或 SDK 不会给旧插件增加工具。DSH/MCP 的训练建议指导也已接入 get_running_skill_advice,宿主不会自动读取这份 Markdown 技能。
技能可按用户请求调用 create_garmin_workout,先预览训练及可选的 scheduleDate,经用户确认后执行;已有课表使用 schedule_garmin_workout 单独预览和确认日期。
排期能力由 0.1.20 正式提供。
使用 download_garmin_activity_fit 下载指定活动时,需在 MCP 服务的 env 中设置 GARMIN_FIT_DOWNLOAD_DIR,值为可信本地父目录的绝对路径。完整配置步骤见随包附带的 references/workbuddy-setup.md。
ZCode
打开 设置 → MCP 服务器 → 新建 MCP 服务器,选择用户作用域和 stdio,填写同样的 Node.js 绝对路径、lib/mcp.js 参数及 Garmin 环境变量。也可以直接编辑用户级原生配置 ~/.zcode/cli/config.json:
若要直接从 npm 验证本正式版,把 command 设为 npx 的绝对路径,并使用下列参数代替本地 checkout 的 lib/mcp.js:
-y --package dsh-plugin-garmin-connect garmin-connect-mcp
不要配置 GARMIN_PASSWORD;在 session 缺失时,第一次只读工具调用即可验证 ZCode 的 URL elicitation 链路。请保留下方显式的 owner-only GARMIN_SESSION_TOKEN_FILE。
{
"mcp": {
"servers": {
"garmin-connect": {
"command": "/absolute/path/to/node",
"args": ["/absolute/path/to/garmin-connect-plugin-for-dsh/lib/mcp.js"],
"env": {
"GARMIN_USERNAME": "你的佳明邮箱", "GARMIN_REGION": "cn", "GARMIN_ACCOUNT": "personal-cn", "GARMIN_SESSION_TOKEN_FILE": "/absolute/path/to/personal.session.json", "GARMIN_FIT_DOWNLOAD_DIR": "/absolute/path/to/garmin-fit-parent" } } } } }
ZCode 也可以导入已有的 Codex 或 Claude Code MCP 配置。它兼容使用 mcpServers 结构的 ~/.agents/mcp.json,但同一作用域的 .zcode 配置只要包含任意 MCP 服务, ZCode 就会整体跳过该 .agents 文件,而不是合并。参见 ZCode 官方 MCP 指南。
这里的 session 文件必须独立初始化;客户端若未显示 URL elicitation,就使用可信终端 serve 命令。ZCode 与模型不会接收密码/MFA 验证码。每增加一个账号,就新增一个命名服务器,并使用独立的 session 文件;多个服务器可共享同一个 FIT 父目录,“区域+邮箱”账号子目录会自动生成。
以上配置已与两款客户端公布的 schema 核对,但尚未记录使用真实 Garmin 账号完成的 WorkBuddy/ZCode 端到端冒烟测试。
Claude Desktop、Cursor、Windsurf、WorkBuddy 与 ZCode 的 JSON 示例会保存敏感的 session 文件路径,但不会保存 session 内容、密码或 MFA 验证码。请限制配置文件权限,且不要提交它们。上面的 Codex 与 Claude Code 示例只转发路径变量。MCP 结果可能把睡眠、心率、体重、运动及位置数据送入所选模型的上下文;请检查客户端的数据处理设置。运动详情默认使用 full,可能包含精确路线/位置;如需减少输出,可在单次调用中选择 compact,或设置 GARMIN_ACTIVITY_DETAIL=compact。FIT 二进制与完整本地/账号路径仍留在 MCP 主机;只有活动 ID、文件名、大小和 hash 会进入模型上下文。请按自己配置的父目录和文档中的账号目录规则定位文件。
使用 npm 0.1.5 或之后版本时,可以把本地的 node …/lib/mcp.js 替换为:
npx -y --package dsh-plugin-garmin-connect garmin-connect-mcp
手动运行
运行 MCP 服务器(stdio);账号 session 路径会被懒推导。
GARMIN_USERNAME=xxx \
GARMIN_ACCOUNT=personal-cn \
GARMIN_REGION=cn \
GARMIN_FIT_DOWNLOAD_DIR=/absolute/path/to/garmin-fit-parent \
node lib/mcp.js
使用 Connect 网页会话账号时,MCP 服务器通过标准协议暴露与 dsh 插件 相同的 29 个工具及日期语义(0.1.20):原有 10 个工具、4 个课表管理工具、前述 13 个恢复与训练工具,以及 2 个血氧与呼吸单日读取工具。Personal MCP 提供前述 15 个兼容工具,配置方式见 官方 Personal API。独立 MCP 每个进程使用配置的账号, DSH 则支持工具级 account 选择。任何 AI 可调用工具都不接收密码/MFA,也不导出 Session Token;浏览器认证通过对话之外的本机 URL elicitation 完成,完成后由用户重试原工具。
架构概览
┌─────────────────────────────────────────┐
│ DeepSeek Harness (dsh) │
│ │
│ ┌───────────────────────────────────┐ │
│ │ dsh-plugin-garmin-connect │ │
│ │ │ │
│ │ ┌─────────┐ ┌─────────────┐ │ │
│ │ │ 配置 │───▶│ Garmin 客户端│ │ │ │ │ │ (Schema) │ │ (含缓存) │ │ │ │ │ └─────────┘ └──────┬──────┘ │ │ │ │ │ │ │ │ │ ┌─────────────────────▼───────┐ │ │ │ │ │ 工具注册中心 (10) │ │ │ │ │ │ • get_garmin_activities │ │ │ │ │ │ • get_garmin_sleep │ │ │ │ │ │ • get_garmin_steps │ │ │ │ │ │ • get_garmin_heart_rate │ │ │ │ │ │ • get_garmin_weight │ │ │ │ │ │ • get_garmin_workouts │ │ │ │ │ │ • get_garmin_profile │ │ │ │ │ │ • get_running_skill_advice │ │ │ │ │ │ • 下载活动 FIT │ │ │ │ │ │ • create_garmin_workout │ │ │ │ │ └─────────────────────────────┘ │ │ │ └───────────────────────────────────┘ │ │ Cordis 运行时 │ └────────────────┬────────────────────────┘ │ ┌──────────┴──────────┐ ▼ ▼ connect.garmin.com MCP Server (stdio) connect.garmin.cn → Claude Desktop / Claude Code / Codex / Cursor / Windsurf / WorkBuddy / ZCode
两步验证登录目标架构
这套架构让 dsh Web、MCP 客户端和命令行共用同一个本机认证 runtime,同时把 Garmin 凭据与 AI 对话彻底分开:
┌──────────────────┐ ┌──────────────────┐ ┌──────────────────┐
│ Harness 设置页 │ │ MCP 工具调用 │ │ CLI serve │ │ 账号卡片内登录 │ │ URL elicitation │ │ 系统默认浏览器 │ └────────┬─────────┘ └────────┬─────────┘ └────────┬─────────┘ └─────────────────────┼─────────────────────┘ ▼ LocalAuthBroker + EmbeddedAuthController │ ▼ 随机 127.0.0.1 一次性桥页 flowId + CSRF + 严格 CSP + 10 分钟有效期 │ 嵌入与区域严格匹配的页面 ▼ Garmin 官方 GAuth iframe(cn / global) Garmin 登录表单字段留在这里 │ │ 一次性 ticket + 原始精确 service ▼ Host 校验 origin / iframe / CSRF / ticket / service │ ▼ 对应区域 DI 交换 → profile 探测 → 用户确认账号 │ ▼ owner-only DI v2 session 原子落盘绑定账号、区域和 profile;不在进程间共享 │ ▼ GarminClient 热加载 / 安全刷新 │ ▼ 用户显式重试原来的工具调用
关键约束如下:
- 认证期间,dsh 外层页面会收到本机一次性 URL 和粗粒度进度;独立的本机插件配置表单处理用户输入的账号邮箱。MCP 客户端和模型只会收到 URL、完成通知或不含敏感数据的粗粒度状态;ticket、DI token、session 内容和 session 路径不会进入模型上下文或 AI 工具参数/结果。
- bridge 只接受预期 Garmin SSO origin、对应 iframe window、CSRF 和严格匹配的 ticket/service。一次性 ticket 不改写 service、不跟随重定向,也不做后备重试。
- 写入 session 前先探测 Garmin profile,并由用户确认账号;随后以私有权限原子写入。运行中的客户端只热加载内容已变化、账号匹配且验证通过的 session。
- 认证完成后不自动重放原工具,避免 FIT 下载或创建训练等写操作重复执行。失败、取消或超时会结束当前 flow;再次认证必须创建新的 flow。
- refresh 只允许为安全的 GET 请求最多重放一次;刷新后先复核同一 profile 并持久化轮换后的 token,写请求绝不因刷新而自动重放。
[!NOTE]
这是目标架构,也是当前正式支持的实现所遵循的边界。真实中国区 MFA → 精确 ticket/service → DI 交换 → profile 确认 → 私有 session 落盘 → 新客户端只读查询已在本机验证;国际区真实 MFA → DI 交换 → profile 确认 → 私有 session 落盘也已通过。
真实 refresh-token 轮换以及更多 MCP 客户端的完整 URL elicitation 体验仍属于持续兼容性覆盖。它仅支持同机 loopback,不是远程、多用户或托管认证服务。
开发
克隆仓库
git clone https://github.com/Likenttt/garmin-connect-plugin-for-dsh.git
cd garmin-connect-plugin-for-dsh
npm install
编译
npm run build
监听模式
npm run dev
运行测试
npm test
自行维护的 SDK 依赖
插件使用已发布的 @likenttt/garmin-connect@1.7.0,代码位于 Likenttt/garmin-connect。
SDK 已于 2026-10-17 发布到官方 npm。插件依赖清单使用以下精确别名,锁文件记录了官方 registry tarball 与完整性校验值:
{
"dependencies": {
"garmin-connect": "npm:@likenttt/garmin-connect@1.7.0"
}
}
代码继续使用 garmin-connect 导入别名,实际安装包名是 @likenttt/garmin-connect。registry 包包含编译好的代码与 TypeScript 声明,安装 SDK 已不再需要 Git、访问 GitHub 或执行依赖的 prepare 编译。
0.1.14 将这些 API 与预编译 registry SDK 一起提供,去掉此前开发候选遇到的 Git 依赖构建与 Git 子依赖策略错误。0.1.15 进一步支持 DeepSeek Harness 0.2.1-rc.1,并保留此前支持的客户端版本。
0.1.16 将 0.2.1 系列 client 条款扩展为 >=0.2.1-rc.1 <0.2.2-0,保留旧支持项。Harness 使用
semver.satisfies(..., { includePrerelease: true });该边界接受
0.2.1-rc.1、rc.2、rc.99 和稳定版 0.2.1,排除所有 0.2.2 预发布及正式版。
rc.2 API 比较确认 connection 与 Cordis JavaScript 未变,layout 仅有 CSS hash 及构建路径差异,此补丁无运行时代码改动。构建、真实 manifest 回归、官方 npm 发布和本机正式来源安装均已通过,详见兼容验证记录。
发布前,本地 0.1.13 开发候选曾通过 Harness 桌面官方 CLI 安装,使用 --ignore-scripts 与官方 npm registry。当时 SDK 全部 60 个 dist 文件与已发布包逐字节一致,13 个方法均存在,锁文件完整性与 npm 一致;Git 安全策略保持启用,仅为精确的新 SDK 版本追加 minimumReleaseAgeExclude。这是 registry 依赖的历史集成验证,不代表公开旧 0.1.13 包包含新增功能,也不描述当前安装版本。
npm ci --registry=https://registry.npmjs.org/
npm run build
npm run check:sdk
check:sdk 是发布门槛:检查维护版依赖来源、已安装包的名称与仓库,以及其真实原型上的全部 13 个新增方法。存在锁文件时,还校验根依赖别名、安装包名/版本与官方 registry 的精确 tarball URL。该检查不请求 Garmin,也不加载凭证。退回上游包、npm 别名残留旧 Git 锁记录或缺少方法都会失败。prepublishOnly 会执行编译和此检查,pack:smoke 也会在检查 npm 包内容前执行两者。
恢复接口发布检查
npm alias 候选已通过 host、client declarations、client bundle 构建与 check:sdk,
以及插件 42 套、992/992 全量测试。随后新增 8 项 SDK 锁文件校验测试,相关专项 28/28 通过。当时源码共 1,000 个用例;全量测试发生在这 8 项新增之前,因此没有把两次运行写成一次 1,000 项全量通过。维护 SDK 的 59/59 测试与严格对外类型声明检查也已通过。较早 Git 候选的干净安装与真实账号验证在报告中单独保留。
0.1.14 包含 13 个恢复 API、共用的 DSH/MCP 工具契约与随包技能参考。较早的真实 session 验证已通过中国区和国际区共 26 次 DSH API 调用与 26 次 MCP 对照;registry SDK 随后已逐字节核验为同一构建,较早候选安装时没有重复查询,也没有发送模型对话。覆盖范围及历史证据见集成验证报告。
源码中的 scripts/check-health-release.cjs 可以用已有 DI session 检查安装好的开发构建。先编译插件并通过 npm run check:sdk,再创建包含 1 至 5 个账号的私密 JSON manifest;以下邮箱与路径均为占位示例:
[
{
"accountId": "personal",
"username": "runner@example.com",
"region": "global",
"sessionTokenFile": "/private/example/session.json"
}
]
manifest 必须由当前用户持有,权限为 0600;在私密目录中用 umask 077 创建。
accountId 不可重复,region 为 cn 或 global。session 文件仍须通过插件的私密文件、账号和区域校验。运行时先停用其他读取同一 session 的进程;自动刷新可能更新原 session 文件。
npm run build
chmod 600 /private/example/accounts.json
node scripts/check-health-release.cjs \
--plugin-dir "$PWD" \
--accounts-file /private/example/accounts.json \
--date 2026-10-15 \
--start-date 2026-10-09 \
--report /private/example/health-release-report.json
五个参数均必填,路径须为绝对路径,报告目标文件须尚不存在。脚本通过编译后的插件使用真实 DI 认证和 Garmin 只读请求,执行 DSH 注册的工具;随后校验 MCP 共 29 个工具,通过内存 MCP 连接调用 15 个健康与训练工具,检查结果一致性与缓存复用,并回归个人资料、运动记录和睡眠工具。原始响应仅留在内存,终端与报告只输出状态、结构/数量及请求元信息。该检查不覆盖 Harness 桌面 UI,也不会重新发起浏览器登录;任一检查失败时进程以非零状态退出。
目录结构
src/
├── index.ts # 插件入口(Cordis apply 函数) ├── config.ts # 配置 Schema(schemastery),支持环境变量自动解析 ├── client.ts # Garmin API 封装,含缓存层 ├── account-session.ts # 按账号别名推导 session 落盘位置 ├── auth.ts # 私有 SSO 认证流程与本地 MFA 回调 ├── auth-cli.ts # 可信本地 CLI:serve 与旧版诊断命令 ├── browser-auth-canary.ts # 隔离 Chrome DI 初始化/canary 核心 ├── embedded-auth-runtime.ts # Web/CLI/MCP 共用 ticket-to-session runtime ├── local-auth-broker.ts # 一次性 loopback/系统浏览器 broker ├── di-session.ts # DI 运行时校验、刷新与安全 GET 重放 ├── session-store.ts # 严格读取 session 文件并原子私有写入 ├── darwin-private-acl.ts # Darwin 扩展 ACL 校验 ├── windows-private-acl.ts # Windows 当前用户 SID/DACL 私有化 ├── fit-export.ts # 从原始 ZIP 限量、无覆盖地提取 FIT ├── tool-service.ts # dsh 与 MCP 共用的工具行为 ├── health-tools.ts # 恢复与训练工具的共用定义及客户端约定 ├── mcp.ts # 独立 MCP 适配器(用于 Codex/Claude Code 等客户端) ├── mcp-auth.ts # URL elicitation、完成通知与回退说明 ├── mcp-shutdown.ts # MCP 认证的有界 stdio/信号清理 ├── knowledge/ │ ├── running-skills.ts # 8 种课型 + 4 套精简训练理念 │ └── workout-schema.ts # 训练定义 → Garmin JSON 构建器 ├── tools/ │ └── index.ts # 工具定义与注册(29 个工具) └── utils/ ├── errors.ts # 安全错误输出与上游日志脱敏 ├── cache.ts # 内存 TTL/LRU 缓存与 single-flight 刷新 ├── date.ts # 本地日历日期解析 ├── path.ts # FIT 父目录展开与绝对路径解析 └── format.ts # 原始数据 → LLM 友好格式转换器
发布与分发
本包是一个标准的 dsh bundle:package.json 声明了 dsh.bundle.patch → cordis.patch.yml,files 会带上编译后的 lib/、.env.example、中英 README 和 patch 文件。
npm run build
npm run check:sdk # prepublishOnly 会在发布前执行两者
npm publish --registry=https://registry.npmjs.org/ --access public
发布后,用户只需一条命令即可安装:
npx @deepseek-ai/dsh plugin --profile web add dsh-plugin-garmin-connect
分发说明:
- npm registry(推荐) — 包内自带编译好的 lib/,安装时无需任何构建授权。
- 本地源码 — npx @deepseek-ai/dsh plugin --profile web add . 会链接源码目录,先执行 npm install。
- GitHub 安装 — npx @deepseek-ai/dsh plugin --profile web add github:<owner>/<repo> 拉取源码并执行包的 prepare 脚本,使用本地安装的 TypeScript 编译器构建;pnpm ≥ 10 默认拒绝执行构建脚本,dsh 会打印需要在 profile 的 pnpm-workspace.yaml 中填写的 allowBuilds 键。
- 给 GitHub 仓库加上 dsh-plugin topic,方便用户发现。
路线图
- [x] 身体成分 — 体重、BMI、体脂率
- [x] 训练库 — 查询可复用的 Garmin 训练模板
- [x] 创建训练 — 安全预览并创建训练库条目
- [x] 课表排期(0.1.20) — 确认新课表或已有课表的日历日期,等待 Garmin Connect 同步
- [x] MCP 服务器 — 支持 Codex、Claude Code/Desktop、Cursor、Windsurf、WorkBuddy、ZCode
- [x] 跑步教练 — 8 种课型、4 套训练理念与强制个性化问询
- [x] 浏览器 MFA 初始化 — 已通过 dsh 本机网页、系统浏览器 serve 与 MCP URL elicitation 正式支持中国区和国际区账号;两区真实 MFA 均已通过,并持续扩展兼容性测试
- [x] 进程隔离多账号 — 每个 dsh/MCP 进程使用单独初始化的 session 文件;不支持并发共享文件
- [x] FIT 下载 — 从原始归档安全提取一个 FIT 到用户所选父目录下自动生成的“区域+规范化邮箱”子目录
- [ ] 训练状态 — VO2 Max、训练负荷、恢复时间
- [ ] 单进程账号注册表 — 每个账号别名使用独立的客户端、缓存、限流器和已绑定 session
- [ ] list_garmin_accounts — 只列出别名、区域和连接状态,不暴露邮箱、Token 或 session 路径
- [ ] 为所有账号相关工具增加可选 account 参数;没有安全选择时要求显式别名
- [ ] use_garmin_account — 在 dsh 能提供可信对话标识时,为当前对话选择账号
- [ ] 否则由模型在每次工具调用中继续传入别名;永不使用进程全局“当前账号”
- [ ] 在宣称多租户隔离前,增加按用户的账号访问白名单
- [ ] 多账号活动同步 — 在中国区和国际版账号之间按一个明确方向复制活动
- [ ] 上传前预览源账号、目标账号、日期范围、候选活动、重复项及隐私影响
- [ ] 将短期、一次性确认绑定到确切的账号对和不可变活动清单
- [ ] 在私有临时目录中暂存并验证 FIT,只上传一次到显式选择的目标;永不删除源活动
- [ ] 持久化同步 ledger,用于精确去重、重启恢复和上传结果未知处理;超时 POST 永不盲目重试
- [ ] 增加有上限的批量任务及 status、pause、resume
- [ ] 增加显式开启的单向轮询同步;dsh 运行时定期检查,重启后补查
- [ ] 首版不做双向同步、自动删除或 Garmin 全量元数据镜像
- [ ] Webhook 推送 — 活动上传实时通知
- [x] 官方 Personal API(0.1.19) — DSH 与 MCP 支持 API Key/token 接入、别名与 Key 两项设置,以及 15 个兼容的读取/本地工具
许可证
MIT
致谢
- DeepSeek Harness — AI 代理编码运行时
- Cordis — 插件生命周期框架
- Likenttt/garmin-connect — 本插件使用的自行维护 TypeScript SDK,基于原上游客户端
- 感谢 Zhitao 的 DailySync 所带来的启发
产品名称和图标归各自权利人所有,仅用于说明互操作兼容性。预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
Likenttt/garmin-connect-plugin-for-dsh
一个基于 TypeScript、支持官方 Personal API 与安全浏览器 MFA 认证的 Garmin…
相关插件 · 浏览器
智能体插件框架deepseek-ai/deepseek-harness
DeepSeek Harnessdsh是由 DeepSeek AI 开发的开源 agent harness智能体框架。
★ 270,422已汉化DSH
71.9
多设备 Agent 看板YaoApp/yao
✨ 所有 Agent 和工作区集中管理,覆盖你的每一台设备。任务看板追踪进度,桌面端、移动端、浏览器、API…
★ 8,147已汉化DSH
71.2
可扩展侧边栏工作台omdsh-dev/DSH-better-sidebar
DSH 的双工作台:原生右侧栏 + 自绘底部面板,并把 ctx.betterSidebar 服务开放给所有插件
★ 4,761已汉化DSH
71.1
浏览器自动化桥Tencent/BrowserSkill
你的 Agent。你的浏览器。连接,就能协作。
★ 9,928已汉化DSH
71
AI 小说创作工作台EthanYoQ/AI-Novel-Writer
AI 小说作家 / AI Novel Writer
★ 1,591已汉化DSH
70.7
智能体浏览器引擎platonai/Browser4
DeepSeek Harness 集成
★ 1,175已汉化DSH
70.4