Garmin MCP Server
Provides tools to access and manage Garmin Connect data, including activities, health metrics, training performance, devices, workouts, and more.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Garmin MCP Servershow my last 5 runs"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
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
Related MCP server: Garmin Connect MCP Server
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 syncRunning
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-mcpWith 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-mcpThe 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 appearNote: 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.jsonWindows:
%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:latestNetwork-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:latestNote: 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 -d3. 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 mcpoNote: 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: 1GiApply it:
kubectl apply -f pvc.yamlStep 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-tokensApply it:
kubectl apply -f deployment.yamlStep 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: ClusterIPApply it:
kubectl apply -f service.yamlStep 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: 80Apply it:
kubectl apply -f httproute.yamlEnvironment Variables
Variable | Description | Default | Required |
| Garmin Connect email address | - | Yes |
| Garmin Connect password | - | Yes |
| 2FA code (only if MFA is enabled) | - | No* |
| Seconds to wait for MFA code |
| No |
| Path to token storage directory |
| No |
| Transport type: |
| No |
| Bind host for HTTP transport |
| No |
| Port for HTTP transport |
| 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 runToken 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-mcpService 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 -fAvailable 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
"What running activities did I do between September 1st and November 6th?"
Uses:
get_activities_by_datewith activity_type="running"
"Get details for activity ID 204592654"
Uses:
get_activity
"Show me the splits for my last run"
Uses:
get_activity_splits
"What was the weather during my activity 204592654?"
Uses:
get_activity_weather
Health & Wellness Queries
"How many steps did I take on November 6th?"
Uses:
get_steps_data
"Show me my sleep data for November 5th"
Uses:
get_sleep_data
"What was my heart rate on November 6th?"
Uses:
get_heart_rates
"Get my body battery data from November 1st to November 6th"
Uses:
get_body_battery
"What was my stress level on November 5th?"
Uses:
get_stress_dataorget_all_day_stress
"Show me my resting heart rate for November 6th"
Uses:
get_rhr_day
"Get my body composition data for November 6th"
Uses:
get_body_composition
"What was my training readiness on November 6th?"
Uses:
get_training_readiness
"Show me my hydration data for November 6th"
Uses:
get_hydration_data
"Get my SpO2 (blood oxygen) data for November 6th"
Uses:
get_spo2_data
"What was my respiration rate on November 6th?"
Uses:
get_respiration_data
Training & Performance Queries
"What's my VO2 Max and fitness age for November 6th?"
Uses:
get_max_metrics
"Get my HRV (Heart Rate Variability) data for November 6th"
Uses:
get_hrv_data
"Show me my fitness age data for November 6th"
Uses:
get_fitnessage_data
"What was my training effect for activity 204592654?"
Uses:
get_training_effect
"Get my hill score from September 1st to November 6th"
Uses:
get_hill_score
"Show me my endurance score between September 1st and November 6th"
Uses:
get_endurance_score
Device & Gear Queries
"List all my Garmin devices"
Uses:
get_devices
"What's my primary training device?"
Uses:
get_primary_training_device
"Show me the gear I used for activity 204592654"
Uses:
get_activity_gear
Challenges & Goals Queries
"What are my active goals?"
Uses:
get_goalswith goal_type="active"
"Show me my personal records"
Uses:
get_personal_record
"What badges have I earned?"
Uses:
get_earned_badges
"Get my race predictions"
Uses:
get_race_predictions
User Profile Queries
"What's my full name?"
Uses:
get_full_name
"What unit system do I use?"
Uses:
get_unit_system
"Show me my user profile"
Uses:
get_user_profile
Data Management Queries
"Add a weight measurement: 75.5 kg"
Uses:
add_weigh_in
"Get my weight measurements from November 1st to November 6th"
Uses:
get_weigh_ins
"Add body composition data for November 6th"
Uses:
add_body_composition
Training and Diet Recommedations
"Prepare me for a marathon with training and diet recommendations"
Uses:
get_training_and_diet_recommendations
"I want to improve my running performance, give me training and diet recommendations"
Uses:
get_training_and_diet_recommendations
"I want to lose weight - what should I do?"
Uses:
get_training_and_diet_recommendations
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
"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
"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
One‑Pane Summaries and Insights
"Show my weekly single-pane summary for last week"
Uses:
get_period_summarywith period="weekly", anchor_date="last week"
"Fetch a monthly dashboard summary including activities and readiness"
Uses:
get_period_summarywith period="monthly"
"What are my trends over the last 4 weeks?"
Uses:
get_trendswith start_date, end_date, include=["rhr","hrv","sleep","steps","body_battery"]
"Detect any recovery red flags this week"
Uses:
detect_anomalieswith heuristic thresholds (defaults sensible)
"Give me a readiness breakdown for today"
Uses:
get_readiness_breakdown
"How complete is my data this month?"
Uses:
get_data_completeness
"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
"Coach cues for this week"
Uses:
get_coach_cueswith period="weekly"
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/mcpKubernetes with Istio:
https://garmin-mcp.example.com/mcpDocker:
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.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/k8sautom8/garmin_mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server