mcpField
H
hybridlog

hybridlog

远程服务
github.com健康医疗17 周前更新

关于 hybridlog

hybridlog 是可自托管的 Garmin 数据 MCP 服务和仪表板,面向跑步者、力量训练者及混合训练者。它镜像个人健康数据,计算训练负荷、肌肉恢复度和准备度,并通过只读权限向 LLM 提供数据查询。

主要功能

  1. 01同步并镜像 Garmin 数据
  2. 02计算训练负荷、准备度和肌肉恢复度
  3. 03查看训练及比赛分段分析
  4. 04提供健康数据仪表板
  5. 05限制查询为只读 SELECT
  6. 06按账户控制可供聊天读取的数据

适用场景

  1. 01比较本周与之前的训练负荷
  2. 02查看当天准备度和适合训练的肌群
  3. 03分析比赛中跑步与站点项目的分段
  4. 04记录症状并结合健康数据讨论

MCP 相关

提供 stdio 和带 OAuth 2.1 的 Streamable HTTP MCP 连接,向客户端开放健康摘要、训练分析、数据查询等工具及周报提示词。数据读取受权限开关控制;症状记录是聊天侧唯一写入功能,且写入应用自身的数据。

配置

远程服务无需本地安装。选择你使用的客户端,复制配置或使用一键安装。

服务地址https://{hybridlog_host}/mcp/garmin
一键复制安装命令
Claude CodeTerminal
Cursor.cursor/mcp.json
VS Code.vscode/mcp.json
Claude Desktopclaude_desktop_config.json
Windsurf~/.codeium/windsurf/mcp_config.json

命令在终端中运行;JSON 粘贴到对应客户端的 MCP 配置后重启。需要授权的服务会在首次连接时提示登录。

安装包
ocighcr.io/imgrund/hybridlog:0.1.13

工具

详细介绍

hybridlog

Tests License: MIT Release MCP registry

基于你自己的 Garmin 数据运行的可自托管 MCP 服务。它会将 Garmin 返回的所有数据镜像到由你控制的数据库中,计算手表无法计算的模型(训练负荷、肌肉恢复情况、结合上下文的准备度),并通过标准输入/输出或 HTTP 将所有数据交给大模型,这样,Garmin 无法测量的内容就可以直接口述到聊天中,而不必填写表单。它还附带一个仪表板:身体肌肉图、训练负荷,以及连接器用于身份验证的登录界面。它没有托管实例,而这正是设计初衷:这是一份健康记录,大模型通过只能读取数据的角色访问它。

无论是跑步、力量训练,还是同一天两者兼有,这些模型都不在意。跑步与站点训练交替进行的训练课程会单独获得逐圈分析,这正是 HYROX 比赛的形式。

安装前可以先体验演示:使用 [email protected] 登录,密码为 demo-demo-demo。演示使用生成的数据,并会在每晚重置。

肌肉图显示各区域负荷,旁边列出分析结果,切换一个标签页即可查看训练负荷

同一页面的浅色模式

手机上的同一页面

这三张图中的所有数字均由 fetcher/seed_demo.py 生成。界面为英文,并附带德语翻译;除非个人资料另有设置,否则会根据浏览器语言显示。

依赖之前请先阅读。 数据抓取器使用 Garmin Connect 的非官方 Web API。Garmin 可能会在不另行通知的情况下更改或关闭该 API。本项目与 Garmin 无关联,也未获得 Garmin 背书。项目计算的任何内容都不构成医疗声明:准备度、HRV 区间、负荷比和教练文本都是训练辅助信息,并非诊断结果。这是一个个人项目,发布时希望它能有所帮助,但不承诺提供支持或保持接口稳定。

它是什么

  • MCP server:基于 laravel/mcp 提供 13 个工具和一个提示词,支持两种传输方式。本地方式(stdio)用于 Claude Code 和 Claude Desktop;托管方式(支持流式传输的 HTTP,搭配 OAuth 2.1、PKCE 和动态客户端注册)用于 claude.ai、ChatGPT、Mistral 的 Le Chat(已更名为 Vibe)、LM Studio,以及任何支持该协议的其他产品。
  • 仪表板:使用 Laravel、Alpine 和 Chart.js 构建。它绘制身体地图和训练负荷,同时也是连接器进行身份验证所用的登录入口,也是设置聊天可查看内容的地方。
  • Fetcher:Python 程序(fetcher/),通过 python-garminconnect 拉取每日指标和活动,写入 PostgreSQL 数据库中属于单个运动员的架构。上文提到的 MCP 服务和仪表板都通过只读连接读取该架构,且只能读取该运动员的数据。每个回答也会连同从中提取数据的列一起完整保留,因此,即使某个字段尚未有对应的数据列,也仍然可以查询;即使 Garmin Connect 不再提供某一天的数据,镜像中仍会保留这些数据。

“没有托管实例”在实践中意味着:Garmin 会话存放在你自己的数据库架构中,任何读取角色都无法访问,因此模型生成的 SQL 无法查询它,也只有你自己持有该会话。除 Garmin 本身外,只有两项可选服务会向外部发出请求:天气服务会使用你自行填写的一对坐标;通知服务则通过一个空 POST 唤醒推送服务,且绝不会传递通知内容。

这些工具

十三个工具和一个提示词。右侧列是 /connect 中控制各项工具的开关;默认情况下全部启用。

工具能回答什么需要
get-health-summary-tool一次调用即可了解当前状况:准备度、睡眠、负荷、数据新鲜度读取健康数据
get-insights-tool应用针对各身体系统给出的判断、建议和早期疾病模式读取健康数据、读取身体指标
get-muscle-map-tool各区域的新鲜度、每周各区域的训练量、今天该练什么读取健康数据
get-training-load-toolCTL/ATL/TSB、急慢性负荷比、每周训练刺激分布读取健康数据
get-strength-progress-tool按周查看各运动类别:次数、记录过的训练吨位、最高重量,以及哪些方面没有进步读取健康数据
get-race-splits-tool按分段查看一次训练:跑步与站点训练、每段配速、配速变化幅度读取健康数据
get-activity-detail-tool深入查看一次训练:各区间的分钟数和占比与运动员区间下限的对比、分段、组数、心率曲线,以及与此前同类训练的对比读取健康数据
describe-schema-tool镜像数据库中的表和列,以便模型自行编写查询读取健康数据、读取身体指标
query-health-data-tool其他所有查询:执行一条只读 SELECT,最多返回 500 行读取健康数据、读取身体指标
refresh-data-tool从 Garmin 同步今天和昨天的数据(即标题栏按钮的功能,但范围缩小到两天),并等待同步完成启动一次抓取
log-symptom-tool将随口提到的身体不适记录为身体图上的标记记录身体感受
delete-symptom-tool身体不适痊愈后将其移除记录身体感受
give-feedback-tool将一条修正作为连接器的长期指南处理反馈
weekly-report(提示词)驱动周日回顾;报告是对话的回答,不会存储在任何地方读取健康数据

大多数工具都能回答应用围绕其构建的问题。其中有两个例外: describe-schema 会把镜像数据库中的表及说明各列含义的注释交给模型,query-health-data 则会执行模型据此编写的 SELECT。这就是一组报告与一个可供人思考和查询的数据库之间的区别,也正是原始回答值得保留在磁盘上的原因:尚未提升为列的字段,只需一个问题就能查询。

除了一个有明确说明的例外,所有操作都只读。聊天中唯一可以写入的内容是身体不适记录,而且它们会写入应用自身的架构,绝不会写入 Garmin 镜像。自由格式 SQL 通过 app/Garmin/ReadOnlyGarminQuery 执行:仅允许单条 SELECT 或 WITH 语句,并设有关键字阻止列表、只读事务和行数上限;连接会切换到一个角色,该角色只对一名运动员的架构拥有 SELECT 权限,不具备其他权限。

快速开始(Docker、演示数据、无需 Garmin 账号)

git clone https://github.com/Imgrund/hybridlog.git
cd hybridlog
cp .env.example .env
docker compose up -d

这会启动 PostgreSQL、仪表板、队列工作进程和调度器。 发布的镜像支持 amd64 和 arm64,因此首次启动会下载镜像,而不是编译。 执行 git pull 后,直接运行 up -d 仍会使用已有镜像:只有加上 --build 才会载入新代码。

接下来,用 120 天看似真实的数据填充镜像,创建用于登录的账号,然后打开仪表板:

docker compose exec app /opt/fetcher/bin/python fetcher/seed_demo.py
docker compose exec app php artisan app:create-user [email protected] --admin
open http://localhost:8080

我们刻意不提供注册页面:没有人能注册的登录入口,就没有可供攻击的入口。如果是给自己以外的人使用,请交给他们一个链接,而不是密码:

docker compose exec app php artisan app:invite [email protected] --name="Them"

它会生成一个一次性链接,有效期为七天(--days),对方可通过该链接设置自己的密码。--admin 会将安装所有者标记为管理员;本地 stdio 传输代表的就是这个账号。每个账号都有自己的个人资料、权限、症状日志、Garmin 登录、通知和镜像,也看不到其他人的任何信息。

DEMO_MODE=true 会将安装转为展示窗口:所有人共用一个账号,所有会向外部发起连接的功能都会关闭(尤其是 Garmin 登录),并由 php artisan demo:reset 每晚将其重置。

展示窗口也是唯一值得统计访客数量的地方;设置 UMAMI_SCRIPT_URL 和 UMAMI_WEBSITE_ID 后,就会渲染你自行托管的 Umami 实例的脚本标签:统计页面浏览量,不使用 cookie,也不使用会让任何人离开网站后仍被追踪的标识符。必须同时设置这两个值;默认情况下,只要其中任意一个为空,就不会渲染任何内容,也不会向除此以外的主机发送页面请求。它不依赖于 DEMO_MODE,因此只需保持默认设置,私有安装就不会加载外部脚本。

连接 AI

服务读取的镜像与仪表板使用的相同,因此聊天和页面上的数据始终一致。但页面无法回答它未被设计来回答的问题:本周与上周相比表现如何、今天是否该休息、身体的不适对明天有什么影响。

重要

这会将你的健康记录交给一个语言模型。它通过只能读取数据且只能访问你自己的架构的角色来读取,但会读取其中的全部内容。 你可以在 /connect 中逐项设置允许读取的内容;开关将在下一次工具调用时生效,而不是等到重新连接后才生效。

所有客户端使用同一个地址:

https://<your-domain>/mcp/garmin

Claude、ChatGPT、Langdock、Le Chat 和 LM Studio 都支持该地址,并通过仪表板自己的登录流程进行 OAuth 身份验证,因此客户端永远看不到密码;你也可以随时在 /connect 中切断它们的访问。Claude Code 和 Claude Desktop 则可以跳过部署,直接通过 stdio 与代码库通信。docs/connect-ai.md 介绍了各客户端的操作步骤。

无论使用哪种连接方式,它都能使用相同的 13 个工具和相同的开关。

连接后,不妨试着问:

我的训练周与前一周相比如何?

我准备好进行高强度训练了吗,还是需要休息一天?

哪些肌肉状态良好,今天该练什么?

周六比赛时我的配速哪里出了问题,计时中有多少时间花在了站点项目上?

箱式跳跃时我的左膝疼了。

使用自己的 Garmin 账户进行设置

在账户菜单中的 Garmin 下登录,或访问 /connect/garmin: 输入邮箱、密码,以及 Garmin 要求时提供的 MFA 验证码。系统存储的是一对 OAuth 令牌,而非密码。登录由队列工作进程执行,因此必须有一个工作进程处于运行状态。

首次登录会自动填充镜像:队列会回填九十天的数据,大约需要一刻钟,历史数据到达时页面会逐步填充。九十天大致是模型能够给出结果所需的最短时长,因为 HRV 基线需要三周的夜间数据,负荷比则需要滚动六周的数据。此后,调度器每天抓取三次,Fetch from Garmin 按钮则可按需抓取。

每条命令只对一名运动员执行(--tenant <user id>;省略时使用所有者)。详情、回填和手动登录说明见 docs/install.md;关于如何记录才能获得值得分析的数据,请参阅 docs/recording.md。

文档

  • docs/install.md:不使用 Docker 进行安装、部署到平台以及备份。
  • docs/connect-ai.md:各客户端的操作步骤、OAuth 和服务发现,以及如何在公共主机上运行 MCP 服务。
  • docs/recording.md:记录规则、天气和通知。

架构说明

  • 派生指标(CTL/ATL/TSB、ACWR 回退值、以约 28 小时半衰期计算并根据 90 天历史自校准的肌肉恢复度)会在 app/Garmin/ 中即时计算。
  • garmin 连接与 Laravel 的默认连接分开。它们指向同一个数据库,但每个查询都针对一名运动员的架构:App\Garmin\Mirror 会将 search_path 设为 garmin_t{id},并在执行第一条语句前切换到该租户的只读角色。
  • 运动员仍需输入的只有界面语言,在 /profile 中设置并存储在数据库中,而非 .env 中:语言属于运动员,而非部署。
  • 颜色遵循经过验证的数据可视化调色板(通过 prefers-color-scheme 支持浅色和深色模式),角色定义在 resources/css/app.css 中。

贡献

发布版本均带有标签,CHANGELOG.md 说明了每个版本的变更内容。CONTRIBUTING.md 说明了如何运行测试套件、测试对代码的要求,以及哪些变更明确不在范围内。行为规范见 CODE_OF_CONDUCT.md。安全问题不应通过 issue 提交:SECURITY.md 说明了私密报告渠道。

许可证

MIT,详见 LICENSE。resources/data/body-polygons.json 中的肌肉多边形来自 body-highlighter 项目系列,同样采用 MIT 许可证。

两个捆绑资源各自适用独立条款。3D 人体模型 resources/models/body-zones.glb 改编自 BodyParts3D(© The Database Center for Life Science),并继续遵循 CC Attribution-Share Alike 2.1 Japan 许可证;resources/models/CREDITS.md 列出了完整署名信息及许可证约束。resources/fonts/ 中的 Mulish 和 Oswald 字体采用 SIL Open Font License 1.1 许可证,许可证文本随字体一同提供。

评论

支持 Markdown

第一次接触 MCP?

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

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