Garmin MCP Server
Connects to Garmin Connect and exposes your fitness and health data to OpenWebUI, Claude, or any MCP-compatible client via Streamable HTTP transport.
README
Garmin MCP Server
This Model Context Protocol (MCP) server connects to Garmin Connect and exposes your fitness and health data to OpenWebUI, Claude or any other MCP-compatible clients via Streamable HTTP transport.
Credits: https://github.com/Taxuspt/garmin_mcp
Features
-
78+ MCP Tools covering:
- Activity management (list, get details, splits, weather, gear)
- Health & wellness metrics (steps, heart rate, sleep, stress, body battery)
- Training & performance data (VO2 Max, HRV, training effect, fitness age)
- Device management
- Gear tracking
- Weight management
- Challenges & badges
- Workouts
- Women's health data
- Data management (add body composition, blood pressure, hydration)
- Personalised training and diet recommedations
-
Streamable HTTP Transport - Network-accessible MCP server for Kubernetes/container deployments
-
Token Persistence - OAuth tokens cached to avoid repeated MFA prompts
-
Non-interactive MFA - Supports containerised deployments with environment-based MFA codes
Prerequisites
- Python 3.10+ (3.12 recommended)
- Garmin Connect account credentials
- For Kubernetes: kubectl access to your cluster
Deployment Options
1. Standalone (Local Development)
Installation
# Clone the repository
git clone <repository-url>
cd garmin_mcp
# Install dependencies
uv sync
Running
With stdio transport (for MCP clients like Claude Desktop):
export GARMIN_EMAIL="your-email@example.com"
export GARMIN_PASSWORD="your-password"
export GARMIN_MCP_TRANSPORT="stdio"
uv run garmin-mcp
With Streamable HTTP transport (for network access):
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
The server will be accessible at http://localhost:8000/mcp
First-Time Setup (MFA - Only if enabled on Garmin Connect)
If you have MFA enabled on your Garmin Connect account, you'll need to provide the 2FA code on first run. You have two options:
Option A: Interactive (for local development)
- The server will prompt for the MFA code in the terminal
Option B: Non-interactive (for automation)
export GARMIN_MFA_CODE="123456" # Code from email/SMS
export GARMIN_MFA_WAIT_SECONDS="180" # Optional: wait up to 180s for code to appear
Note: If MFA is not enabled on your Garmin Connect account, you can skip these environment variables.
After successful login, OAuth tokens are saved to ~/.garminconnect and future runs won't require MFA until tokens expire.
Configuration with Claude Desktop
Edit your Claude Desktop configuration:
- macOS:
~/Library/Application Support/Claude/claude_desktop_config.json - Windows:
%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"
}
}
}
}
Note: If you have MFA enabled on your Garmin Connect account, add "GARMIN_MFA_CODE": "123456" to the env section for the first run.
Restart Claude Desktop after making changes.
2. Docker Deployment
Build the Image
docker build -t garmin-mcp:latest .
Run the Container
Basic run (stdio transport):
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
Network-accessible (Streamable 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
Note: Only include GARMIN_MFA_CODE and GARMIN_MFA_WAIT_SECONDS if you have MFA enabled on your Garmin Connect account.
The server will be accessible at http://localhost:8000/mcp
Using Docker Compose:
Create 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:
Run with:
docker-compose up -d
3. Kubernetes Deployment
Prerequisites
- Kubernetes cluster with kubectl configured
- PersistentVolume support (for token storage)
Step 1: Create Secrets
Create a Kubernetes Secret with your Garmin credentials:
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
Note: The mfa key is only needed if you have MFA enabled on your Garmin Connect account. If MFA is not enabled, omit the --from-literal=mfa line. The mfa key is only needed for the first run or when tokens expire. You can remove it after tokens are established.
Step 2: Create PersistentVolumeClaim
Create pvc.yaml:
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: garmin-tokens
namespace: mcpo
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 1Gi
Apply it:
kubectl apply -f pvc.yaml
Step 3: Deploy the Application
Create 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
Apply it:
kubectl apply -f deployment.yaml
Step 4: Create Service
Create 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
Apply it:
kubectl apply -f service.yaml
Step 5: (Optional) Create Istio HTTPRoute
If using Istio, create 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
Apply it:
kubectl apply -f httproute.yaml
Environment Variables
| Variable | Description | Default | Required |
|---|---|---|---|
GARMIN_EMAIL |
Garmin Connect email address | - | Yes |
GARMIN_PASSWORD |
Garmin Connect password | - | Yes |
GARMIN_MFA_CODE |
2FA code (only if MFA is enabled) | - | No* |
GARMIN_MFA_WAIT_SECONDS |
Seconds to wait for MFA code | 0 |
No |
GARMINTOKENS |
Path to token storage directory | ~/.garminconnect |
No |
GARMIN_MCP_TRANSPORT |
Transport type: stdio or streamable-http |
http |
No |
GARMIN_MCP_HOST |
Bind host for HTTP transport | 0.0.0.0 |
No |
GARMIN_MCP_PORT |
Port for HTTP transport | 8000 |
No |
*Required only if MFA is enabled on your Garmin Connect account, and only on first run or when tokens expire
Token Management
OAuth tokens are automatically saved to ~/.garminconnect (or path specified by GARMINTOKENS) after successful login. These tokens persist across restarts, eliminating the need for MFA on subsequent runs until they expire.
For Kubernetes: Tokens are stored in the PersistentVolumeClaim, so they persist across pod restarts and deployments.
Troubleshooting
Login Issues
- Invalid credentials: Verify your email and password are correct
- MFA required: If you have MFA enabled, ensure
GARMIN_MFA_CODEis set for first run - Token expired: Delete the token directory and re-authenticate
Network Issues
- Can't connect to server: Verify the server is binding to
0.0.0.0(not127.0.0.1) - Connection refused: Check firewall rules and port exposure
- 404 errors: Ensure you're using the correct transport type (Streamable HTTP for network access)
Kubernetes Issues
- Pod crash loops: Check logs with
kubectl logs -n mcpo deployment/garmin-mcp - Service not accessible: Verify Service selector matches Deployment labels
- Token persistence: Ensure PVC is properly mounted and has storage available
Viewing Logs
Docker:
docker logs <container-id>
Kubernetes:
kubectl logs -n mcpo deployment/garmin-mcp -f
Available Tools
This server provides 78+ MCP tools. See TOOLS.md for a complete list organised by category.
Example Queries
Once connected to the MCP server, you can query your Garmin fitness data using natural language. Here are some example queries you can make:
Activity Queries
-
"Show me my recent activities"
- Uses:
list_activities
- Uses:
-
"What running activities did I do between September 1st and November 6th?"
- Uses:
get_activities_by_datewith activity_type="running"
- Uses:
-
"Get details for activity ID 204592654"
- Uses:
get_activity
- Uses:
-
"Show me the splits for my last run"
- Uses:
get_activity_splits
- Uses:
-
"What was the weather during my activity 204592654?"
- Uses:
get_activity_weather
- Uses:
Health & Wellness Queries
-
"How many steps did I take on November 6th?"
- Uses:
get_steps_data
- Uses:
-
"Show me my sleep data for November 5th"
- Uses:
get_sleep_data
- Uses:
-
"What was my heart rate on November 6th?"
- Uses:
get_heart_rates
- Uses:
-
"Get my body battery data from November 1st to November 6th"
- Uses:
get_body_battery
- Uses:
-
"What was my stress level on November 5th?"
- Uses:
get_stress_dataorget_all_day_stress
- Uses:
-
"Show me my resting heart rate for November 6th"
- Uses:
get_rhr_day
- Uses:
-
"Get my body composition data for November 6th"
- Uses:
get_body_composition
- Uses:
-
"What was my training readiness on November 6th?"
- Uses:
get_training_readiness
- Uses:
-
"Show me my hydration data for November 6th"
- Uses:
get_hydration_data
- Uses:
-
"Get my SpO2 (blood oxygen) data for November 6th"
- Uses:
get_spo2_data
- Uses:
-
"What was my respiration rate on November 6th?"
- Uses:
get_respiration_data
- Uses:
Training & Performance Queries
-
"What's my VO2 Max and fitness age for November 6th?"
- Uses:
get_max_metrics
- Uses:
-
"Get my HRV (Heart Rate Variability) data for November 6th"
- Uses:
get_hrv_data
- Uses:
-
"Show me my fitness age data for November 6th"
- Uses:
get_fitnessage_data
- Uses:
-
"What was my training effect for activity 204592654?"
- Uses:
get_training_effect
- Uses:
-
"Get my hill score from September 1st to November 6th"
- Uses:
get_hill_score
- Uses:
-
"Show me my endurance score between September 1st and November 6th"
- Uses:
get_endurance_score
- Uses:
Device & Gear Queries
-
"List all my Garmin devices"
- Uses:
get_devices
- Uses:
-
"What's my primary training device?"
- Uses:
get_primary_training_device
- Uses:
-
"Show me the gear I used for activity 204592654"
- Uses:
get_activity_gear
- Uses:
Challenges & Goals Queries
-
"What are my active goals?"
- Uses:
get_goalswith goal_type="active"
- Uses:
-
"Show me my personal records"
- Uses:
get_personal_record
- Uses:
-
"What badges have I earned?"
- Uses:
get_earned_badges
- Uses:
-
"Get my race predictions"
- Uses:
get_race_predictions
- Uses:
User Profile Queries
-
"What's my full name?"
- Uses:
get_full_name
- Uses:
-
"What unit system do I use?"
- Uses:
get_unit_system
- Uses:
-
"Show me my user profile"
- Uses:
get_user_profile
- Uses:
Data Management Queries
-
"Add a weight measurement: 75.5 kg"
- Uses:
add_weigh_in
- Uses:
-
"Get my weight measurements from November 1st to November 6th"
- Uses:
get_weigh_ins
- Uses:
-
"Add body composition data for November 6th"
- Uses:
add_body_composition
- Uses:
Training and Diet Recommedations
-
"Prepare me for a marathon with training and diet recommendations"
- Uses:
get_training_and_diet_recommendations
- Uses:
-
"I want to improve my running performance, give me training and diet recommendations"
- Uses:
get_training_and_diet_recommendations
- Uses:
-
"I want to lose weight - what should I do?"
- Uses:
get_training_and_diet_recommendations
- Uses:
Complex Queries
The MCP server can handle complex, multi-step queries:
-
"Analyze my training week: show me my activities, sleep quality, and body battery from November 1st to November 6th"
- Combines:
get_activities_by_date,get_sleep_data,get_body_battery
- Combines:
-
"Compare my running performance: get my activities, training effect, and heart rate zones for my last 5 runs"
- Combines:
list_activities,get_training_effect,get_activity_hr_in_timezones
- Combines:
-
"Give me a complete health summary for November 6th: steps, sleep, stress, heart rate, and body battery"
- Combines:
get_steps_data,get_sleep_data,get_stress_data,get_heart_rates,get_body_battery
- Combines:
One‑Pane Summaries and Insights
-
"Show my weekly single-pane summary for last week"
- Uses:
get_period_summarywith period="weekly", anchor_date="last week"
- Uses:
-
"Fetch a monthly dashboard summary including activities and readiness"
- Uses:
get_period_summarywith period="monthly"
- Uses:
-
"What are my trends over the last 4 weeks?"
- Uses:
get_trendswith start_date, end_date, include=["rhr","hrv","sleep","steps","body_battery"]
- Uses:
-
"Detect any recovery red flags this week"
- Uses:
detect_anomalieswith heuristic thresholds (defaults sensible)
- Uses:
-
"Give me a readiness breakdown for today"
- Uses:
get_readiness_breakdown
- Uses:
-
"How complete is my data this month?"
- Uses:
get_data_completeness
- Uses:
-
"Hydration target for a 60‑minute run at 28°C, weight 75 kg"
- Uses:
get_hydration_guidancewith weight_kg=75, training_minutes=60, temperature_c=28
- Uses:
-
"Coach cues for this week"
- Uses:
get_coach_cueswith period="weekly"
- Uses:
Tip: These tools accept natural timeframe phrases like
today,yesterday,last week,this week,last month,last 28 days. Ranges automatically clamp to today so mid-week requests never reach into the future.
Accessing the Server
When deployed with Streamable HTTP transport, the MCP server is accessible at:
- Local:
http://localhost:8000/mcp - Kubernetes with Istio:
https://garmin-mcp.example.com/mcp - Docker:
http://<container-ip>:8000/mcp
Configure your MCP client (OpenWebUI, Claude, etc.) to connect to the /mcp endpoint for Streamable HTTP transport.
Security Notes
- Never commit credentials: Use environment variables or Kubernetes Secrets
- Token storage: Tokens are stored locally/on PVC - ensure proper access controls
- Network security: For production, use TLS/HTTPS (terminate at Ingress/Gateway)
- Secret rotation: Rotate Garmin password regularly and update secrets accordingly
License
See LICENSE file for details.
Contributing
Contributions are welcome! Please open an issue or submit a pull request.
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。