健康数据服务器

Garmin MCP服务器连接Garmin Connect,通过可流式HTTP传输将用户的健康和健身数据暴露给OpenWebUI、Claude或其他兼容MCP的客户端。

  • by k8sautom8
  • Python
  • 本地部署
  • 7 星标
  • 更新于
在 GitHub 查看 k8sautom8/garmin_mcp

使用说明

Garmin MCP服务器

此模型上下文协议(MCP)服务器连接到Garmin Connect,并通过流式HTTP传输将您的健身和健康数据暴露给OpenWebUI、Claude或任何其他兼容MCP的客户端。

信用:https://github.com/Taxuspt/garmin_mcp

特性

  • 78+MCP工具 涵盖:

    • 活动管理(列表、获取详细信息、分段、天气、装备)
    • 健康与保健指标(步数、心率、睡眠、压力、身体电池)
    • 训练和表现数据(最大摄氧量、心率变异性、训练效果、健身年龄)
    • 设备管理
    • 齿轮跟踪
    • 体重管理
    • 挑战与徽章
    • 锻炼
    • 妇女健康数据
    • 数据管理(添加身体成分、血压、水合作用)
    • 个性化训练和饮食建议
  • 可流式HTTP传输 -用于Kubernetes/容器部署的网络可访问MCP服务器

  • 令牌持久性 -缓存OAuth令牌以避免重复的MFA提示

  • 非交互式MFA -支持基于环境的MFA代码的容器化部署

先决条件

  • Python 3.10+(推荐3.12)
  • Garmin Connect帐户凭据
  • 对于Kubernetes:kubectl访问集群

部署选项

1.独立(地方发展)

安装

# Clone the repository
git clone <repository-url>
cd garmin_mcp

# Install dependencies
uv sync

跑步

使用stdio传输(适用于Claude Desktop等MCP客户端):

export GARMIN_EMAIL="your-email@example.com"
export GARMIN_PASSWORD="your-password"
export GARMIN_MCP_TRANSPORT="stdio"

uv run garmin-mcp

使用流式HTTP传输(用于网络访问):

export GARMIN_EMAIL="your-email@example.com"
export GARMIN_PASSWORD="your-password"
export GARMIN_MCP_TRANSPORT="streamable-http"
export GARMIN_MCP_HOST="0.0.0.0"
export GARMIN_MCP_PORT="8000"

uv run garmin-mcp

服务器将可在以下位置访问 http://localhost:8000/mcp

首次设置(MFA-仅在Garmin Connect上启用时)

如果您在Garmin Connect帐户上启用了MFA,则需要在首次运行时提供2FA代码。您有两个选择:

选项A:互动式(促进当地发展)

  • 服务器将在终端中提示输入MFA代码

选项B:非交互式(用于自动化)

export GARMIN_MFA_CODE="123456"  # Code from email/SMS
export GARMIN_MFA_WAIT_SECONDS="180"  # Optional: wait up to 180s for code to appear

注: 如果您的Garmin Connect帐户未启用MFA,您可以跳过这些环境变量。

成功登录后,OAuth令牌将保存到 ~/.garminconnect 在代币到期之前,未来的运行将不需要MFA。

使用Claude Desktop进行配置

编辑您的Claude Desktop配置:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • 视窗: %APPDATA%\Claude\claude_desktop_config.json
{
  "mcpServers": {
    "garmin": {
      "command": "uv",
      "args": ["run", "garmin-mcp"],
      "env": {
        "GARMIN_EMAIL": "your-email@example.com",
        "GARMIN_PASSWORD": "your-password",
        "GARMIN_MCP_TRANSPORT": "stdio"
      }
    }
  }
}

注: 如果您在Garmin Connect帐户上启用了MFA,请添加 "GARMIN_MFA_CODE": "123456" 到 env 第一轮比赛的部分。

更改后重新启动Claude Desktop。

2.Docker部署

塑造形象

docker build -t garmin-mcp:latest .

运行容器

基本运行(stdio传输):

docker run --rm -it \
  -e GARMIN_EMAIL="your-email@example.com" \
  -e GARMIN_PASSWORD="your-password" \
  -e GARMIN_MCP_TRANSPORT="stdio" \
  -v garmin_tokens:/root/.garminconnect \
  garmin-mcp:latest

网络可访问(流式HTTP):

docker run --rm -it \
  -e GARMIN_EMAIL="your-email@example.com" \
  -e GARMIN_PASSWORD="your-password" \
  -e GARMIN_MCP_TRANSPORT="streamable-http" \
  -e GARMIN_MCP_HOST="0.0.0.0" \
  -e GARMIN_MCP_PORT="8000" \
  -e GARMIN_MFA_CODE="123456" \
  -e GARMIN_MFA_WAIT_SECONDS="180" \
  -p 8000:8000 \
  -v garmin_tokens:/root/.garminconnect \
  garmin-mcp:latest

注: 仅包括 GARMIN_MFA_CODE 和 GARMIN_MFA_WAIT_SECONDS 如果您在Garmin Connect帐户上启用了MFA。

服务器将可在以下位置访问 http://localhost:8000/mcp

使用Docker Compose:

创建 docker-compose.yml:

version: '3.8'

services:
  garmin-mcp:
    build: .
    image: garmin-mcp:latest
    container_name: garmin-mcp
    restart: unless-stopped
    ports:
      - "8000:8000"
    environment:
      - GARMIN_EMAIL=${GARMIN_EMAIL}
      - GARMIN_PASSWORD=${GARMIN_PASSWORD}
      - GARMIN_MCP_TRANSPORT=streamable-http
      - GARMIN_MCP_HOST=0.0.0.0
      - GARMIN_MCP_PORT=8000
      # Only include MFA variables if MFA is enabled on your Garmin Connect account
      - GARMIN_MFA_CODE=${GARMIN_MFA_CODE}
      - GARMIN_MFA_WAIT_SECONDS=180
    volumes:
      - garmin_tokens:/root/.garminconnect

volumes:
  garmin_tokens:

运行方式:

docker-compose up -d

3.Kubernetes部署

先决条件

  • 配置了kubectl的Kubernetes集群
  • 持久卷支持(用于令牌存储)

第一步:创造秘密

使用您的Garmin凭据创建Kubernetes密钥:

kubectl create namespace mcpo  # or your preferred namespace

kubectl create secret generic garmin-secrets \
  --from-literal=email='your-email@example.com' \
  --from-literal=password='your-password' \
  --from-literal=mfa='123456' \
  -n mcpo

注: 这 mfa 仅当您的Garmin Connect帐户启用了MFA时,才需要密钥。如果未启用MFA,则省略 --from-literal=mfa 线。这 mfa 密钥仅在第一次运行或令牌过期时需要。您可以在建立令牌后将其删除。

步骤2:创建持久卷索赔

创建 pvc.yaml:

apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: garmin-tokens
  namespace: mcpo
spec:
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 1Gi

应用它:

kubectl apply -f pvc.yaml

步骤3:部署应用程序

创建 deployment.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: garmin-mcp
  namespace: mcpo
spec:
  replicas: 1
  selector:
    matchLabels:
      app: garmin-mcp
  template:
    metadata:
      labels:
        app: garmin-mcp
    spec:
      containers:
        - name: garmin-mcp
          image: garmin-mcp:latest  # Replace with your image registry
          imagePullPolicy: Always
          ports:
            - containerPort: 8000
              name: http
          env:
            - name: GARMIN_EMAIL
              valueFrom:
                secretKeyRef:
                  name: garmin-secrets
                  key: email
            - name: GARMIN_PASSWORD
              valueFrom:
                secretKeyRef:
                  name: garmin-secrets
                  key: password
            - name: GARMIN_MCP_TRANSPORT
              value: "streamable-http"
            - name: GARMIN_MCP_HOST
              value: "0.0.0.0"
            - name: GARMIN_MCP_PORT
              value: "8000"
            # Only include MFA variables if MFA is enabled on your Garmin Connect account
            - name: GARMIN_MFA_CODE
              valueFrom:
                secretKeyRef:
                  name: garmin-secrets
                  key: mfa
            - name: GARMIN_MFA_WAIT_SECONDS
              value: "180"
          volumeMounts:
            - name: tokens
              mountPath: /root/.garminconnect
          readinessProbe:
            tcpSocket:
              port: 8000
            initialDelaySeconds: 5
            periodSeconds: 5
          livenessProbe:
            tcpSocket:
              port: 8000
            initialDelaySeconds: 10
            periodSeconds: 10
      volumes:
        - name: tokens
          persistentVolumeClaim:
            claimName: garmin-tokens

应用它:

kubectl apply -f deployment.yaml

步骤4:创建服务

创建 service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: garmin-mcp
  namespace: mcpo
spec:
  selector:
    app: garmin-mcp
  ports:
    - name: http
      port: 80
      targetPort: 8000
  type: ClusterIP

应用它:

kubectl apply -f service.yaml

步骤5:(可选)创建Istio HTTPRoute

如果使用Istio,请创建 httproute.yaml:

apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
  name: garmin-mcp
  namespace: mcpo
spec:
  parentRefs:
    - name: your-gateway
      namespace: istio-system
  hostnames:
    - garmin-mcp.example.com
  rules:
    - matches:
        - path:
            type: PathPrefix
            value: /mcp
      backendRefs:
        - name: garmin-mcp
          port: 80

应用它:

kubectl apply -f httproute.yaml

环境变量

变量 描述 默认值 必填
GARMIN_EMAIL Garmin Connect电子邮件地址 - 是
GARMIN_PASSWORD Garmin Connect密码 - 是
GARMIN_MFA_CODE 2FA代码(仅当启用MFA时) - 否*
GARMIN_MFA_WAIT_SECONDS 等待MFA代码的秒数 0 没有
GARMINTOKENS 令牌存储目录的路径 ~/.garminconnect 没有
GARMIN_MCP_TRANSPORT 运输类型: stdio 或 streamable-http http 没有
GARMIN_MCP_HOST 为HTTP传输绑定主机 0.0.0.0 没有
GARMIN_MCP_PORT HTTP传输端口 8000 没有

*仅当您的Garmin Connect帐户启用MFA时才需要,并且仅在首次运行或令牌到期时才需要

许可证管理

OAuth令牌会自动保存到 ~/.garminconnect (或指定的路径 GARMINTOKENS)成功登录后。这些令牌在重启过程中持续存在,从而消除了后续运行中对MFA的需求,直到它们过期。

对于Kubernetes: 令牌存储在PersistentVolumeClaim中,因此它们在pod重启和部署过程中会持续存在。

故障排除

登录问题

  1. 无效凭证:验证您的电子邮件和密码是否正确
  2. 需要MFA:如果您启用了MFA,请确保 GARMIN_MFA_CODE 设置为首次运行
  3. 令牌已过期:删除令牌目录并重新进行身份验证

网络问题

  1. 无法连接到服务器:验证服务器是否绑定到 0.0.0.0 (不是 127.0.0.1)
  2. 连接被拒绝:检查防火墙规则和端口暴露
  3. 404错误:确保使用正确的传输类型(用于网络访问的流式HTTP)

Kubernetes问题

  1. 吊舱碰撞循环:检查日志 kubectl logs -n mcpo deployment/garmin-mcp
  2. 服务无法访问:验证服务选择器是否与部署标签匹配
  3. 令牌持久性:确保PVC安装正确,并有可用的存储空间

查看日志

Docker:

docker logs <container-id>

库贝内特斯:

kubectl logs -n mcpo deployment/garmin-mcp -f

可用工具

该服务器提供78多种MCP工具。看 TOOLS.md 查看按类别组织的完整列表。

查询示例

一旦连接到MCP服务器,您就可以使用自然语言查询您的Garmin健身数据。以下是您可以进行的一些示例查询:

活动查询

  • “显示我最近的活动”

    • 使用: list_activities
  • “9月1日至11月6日期间,我做了哪些跑步活动?”

    • 使用: get_activities_by_date activity_type=“正在运行”
  • “获取活动ID 204592654的详细信息”

    • 使用: get_activity
  • “给我看看我最后一次跑步的成绩”

    • 使用: get_activity_splits
  • “我活动204592654期间的天气怎么样?”

    • 使用: get_activity_weather

健康与保健查询

  • “11月6日我走了多少步?”

    • 使用: get_steps_data
  • “显示我11月5日的睡眠数据”

    • 使用: get_sleep_data
  • “11月6日我的心率是多少?”

    • 使用: get_heart_rates
  • “获取11月1日至11月6日的身体电池数据”

    • 使用: get_body_battery
  • “11月5日我的压力水平是多少?”

    • 使用: get_stress_data 或 get_all_day_stress
  • “显示我11月6日的静息心率”

    • 使用: get_rhr_day
  • “获取11月6日的身体成分数据”

    • 使用: get_body_composition
  • “11月6日我的训练准备情况如何?”

    • 使用: get_training_readiness
  • “显示我11月6日的水分数据”

    • 使用: get_hydration_data
  • “获取我11月6日的SpO2(血氧)数据”

    • 使用: get_spo2_data
  • “11月6日我的呼吸频率是多少?”

    • 使用: get_respiration_data

培训和绩效查询

  • “我11月6日的最大摄氧量和健身年龄是多少?”

    • 使用: get_max_metrics
  • “获取11月6日的心率变异性(HRV)数据”

    • 使用: get_hrv_data
  • “显示我11月6日的健身年龄数据”

    • 使用: get_fitnessage_data
  • “我对204592654活动的训练效果如何?”

    • 使用: get_training_effect
  • “获取9月1日至11月6日的山丘分数”

    • 使用: get_hill_score
  • “显示我在9月1日至11月6日之间的耐力得分”

    • 使用: get_endurance_score

设备和装备查询

  • “列出我的所有Garmin设备”

    • 使用: get_devices
  • “我的主要训练设备是什么?”

    • 使用: get_primary_training_device
  • “显示我用于活动204592654的装备”

    • 使用: get_activity_gear

挑战和目标查询

  • “我的积极目标是什么?”

    • 使用: get_goals goal_type=“活动”
  • “显示我的个人记录”

    • 使用: get_personal_record
  • “我获得了什么徽章?”

    • 使用: get_earned_badges
  • “获取我的比赛预测”

    • 使用: get_race_predictions

用户配置文件查询

  • “我的全名是什么?”

    • 使用: get_full_name
  • “我使用什么单位制?”

    • 使用: get_unit_system
  • “显示我的用户配置文件”

    • 使用: get_user_profile

数据管理查询

  • “添加重量测量值:75.5公斤”

    • 使用: add_weigh_in
  • “获取11月1日至11月6日的体重测量值”

    • 使用: get_weigh_ins
  • “添加11月6日的身体成分数据”

    • 使用: add_body_composition

训练和饮食建议

  • “通过训练和饮食建议让我为马拉松做好准备”

    • 使用: get_training_and_diet_recommendations
  • “我想提高我的跑步成绩,给我训练和饮食建议”

    • 使用: get_training_and_diet_recommendations
  • “我想减肥,我该怎么办?”

    • 使用: get_training_and_diet_recommendations

复杂查询

MCP服务器可以处理复杂的多步骤查询:

  • “分析我的训练周:向我展示11月1日至11月6日的活动、睡眠质量和身体电池”

    • 联合 get_activities_by_date, get_sleep_data, get_body_battery
  • “比较我的跑步表现:获取我最近5次跑步的活动、训练效果和心率区域”

    • 联合 list_activities, get_training_effect, get_activity_hr_in_timezones
  • “给我一份11月6日的完整健康总结:步数、睡眠、压力、心率和身体电池”

    • 联合 get_steps_data, get_sleep_data, get_stress_data, get_heart_rates, get_body_battery

单窗格摘要和见解

  • “显示我上周的每周单窗格摘要”

    • 使用: get_period_summary period=“week”,anchor_date=“上周”
  • “获取每月的仪表板摘要,包括活动和准备情况”

    • 使用: get_period_summary 周期=“每月”
  • “过去4周我的趋势是什么?”

    • 使用: get_trends 具有start_date、end_date、include=[“rhr”、“hrv”、“sleep”、“steps”、“body_battery”]
  • “本周检测到任何恢复危险信号”

    • 使用: detect_anomalies 具有启发式阈值(默认值合理)
  • “给我一份今天的准备情况明细”

    • 使用: get_readiness_breakdown
  • “我这个月的数据有多完整?”

    • 使用: get_data_completeness
  • “28°C下60分钟跑步的水合目标,重量75公斤”

    • 使用: get_hydration_guidance 重量kg=75,训练分钟=60,温度c=28
  • “本周教练提示”

    • 使用: get_coach_cues 周期=“每周”

提示:这些工具接受自然时间框架短语,如 today, yesterday, last week, this week, last month, last 28 days.Ranges会自动锁定到今天,因此周中的请求永远不会到达未来。

访问服务器

当部署了Streamable HTTP传输时,MCP服务器可以在以下位置访问:

  • 本地: http://localhost:8000/mcp
  • Kubernetes与Istio: https://garmin-mcp.example.com/mcp
  • 码头工人: http://<container-ip>:8000/mcp

配置您的MCP客户端(OpenWebUI、Claude等)以连接到 /mcp 流式HTTP传输的端点。

安全说明

  • 从不提交凭据:使用环境变量或Kubernetes Secrets
  • 令牌存储:令牌存储在本地/PVC上-确保适当的访问控制
  • 网络安全:对于生产,使用TLS/HTTPS(在入口/网关处终止)
  • 秘密轮换:定期旋转Garmin密码并相应地更新密码

许可证

看 许可证 文件以获取详细信息。

贡献

欢迎投稿!请打开问题或提交拉取请求。