Garmin Mcp
About
Connects to Garmin Connect to expose your fitness and health data to MCP-compatible clients.
Details
- Transport
- SSE
- License
- MIT
Explore
- List recent activities with pagination support
- Get detailed activity information
- Edit activities: name, type, description/notes, event type, perceived effort (RPE), and feel
- Access health metrics (steps, heart rate, sleep, stress, respiration)
- View body composition data
- Track training status and readiness
- Access cycling FTP and lactate threshold metrics
- Manage gear and equipment
- Access workouts and training plans
- Inspect detailed workout step structures, including repeat groups and swim pace targets
- Weekly health aggregates (steps, stress, intensity minutes)
- Advanced cycling analytics: power zones, FIT file analysis, DI2 electronic shift intelligence
- Training load trend (CTL/ATL/TSB), HRV trend, VO2 max trend, respiration rate trend
- Power Duration Curve, climb detection with VAM, cardiac drift (aerobic decoupling), W/kg calculations
Setting up with Highlight
This MCP is not yet compatible with Highlight’s one-click setup. However, you can still use it with Highlight by following these steps:
- Download and install Highlight from highlightai.com/download
- Navigate to the plugins tab and select "Add Custom Plugin"
-
Configure the plugin with the settings below
Plugin Name
Garmin McpCommand (node, npx, python, etc.)Please refer to the README for specific instructions on how to obtain API keys or other required environment variables.
- Enable "Start Automatically" if you want the plugin to start when Highlight launches
From the repository
- Python 3.12+
- Garmin Connect account
- MFA may be required if enabled on your account
The easiest way to add this server to Claude Desktop is via the .dxt Desktop Extension file — no JSON editing required.
1. Download the latest garmin-mcp.dxt from the Releases page.
2. Drag the .dxt file into the Claude Desktop window, or double-click it, or go to Settings → Extensions → Install Extension and select the file.
3. Claude Desktop will prompt you for optional configuration (token path, email, password).
The extension installs and runs the server automatically, but you must authenticate with Garmin once before data can be fetched:
uvx --python 3.12 --from git+https://github.com/Taxuspt/garmin_mcp garmin-mcp-auth
This saves OAuth tokens to ~/.garminconnect. After that the server works without any credentials in the config.
> Note: Tokens are valid for approximately 6 months. Re-run garmin-mcp-auth when they expire.
The easiest way to use this MCP server with Claude Desktop, Codex, or another MCP client is to authenticate once before adding the server to your configuration.
uvx --python 3.12 --from git+https://github.com/Taxuspt/garmin_mcp garmin-mcp-auth
Add to your Claude Desktop MCP settings WITHOUT credentials:
macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
Windows: %APPDATA%\Claude\claude_desktop_config.json
{
"mcpServers": {
"garmin": {
"command": "uvx",
"args": [
"--python",
"3.12",
"--from",
"git+https://github.com/Taxuspt/garmin_mcp",
"garmin-mcp"
]
}
}
}
Important: No GARMIN_EMAIL or GARMIN_PASSWORD needed in config! The server uses your saved tokens.
1. Install the required packages on a new environment:
uv sync
Add the server to your global opencode config at ~/.config/opencode/opencode.json after running garmin-mcp-auth:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"garmin": {
"type": "local",
"command": [
"uvx",
"--python",
"3.12",
"--from",
"git+https://github.com/Taxuspt/garmin_mcp",
"garmin-mcp"
],
"enabled": true,
"timeout": 30000
}
}
}
Restart opencode after saving the file. The first uvx invocation downloads and caches the package, so the initial startup may take a few seconds.
1. Create a .env file with your credentials:
echo "[email protected]" > .env
echo "GARMIN_PASSWORD=your_password" >> .env
2. Start the container:
docker compose up -d
3. View logs to monitor the server:
docker compose logs -f garmin-mcp
docker volume rm garmin_mcp_garmin-tokens
Once connected in Claude, you can ask questions like:
- "Show me my recent activities"
- "What was my sleep like last night?"
- "How many steps did I take yesterday?"
- "Show me the details of my latest run"
- "Analyze my last ride's power zones and compare to my training zones"
- "Show me my CTL, ATL, and TSB trend for the last 6 weeks"
- "What was my power duration curve from yesterday's ride? Estimate my FTP."
- "Analyze the FIT data from my last cycling activity — how was my shifting quality on the climbs?"
- "Show me my HRV trend for the last 2 weeks and flag any recovery concerns"
- "What's my season best 20-minute power and when did I set it?"
The easiest way to handle MFA is using the dedicated authentication tool:
bashgarmin-mcp-auth
This saves OAuth tokens to ~/.garminconnect for future use. The server will automatically use these tokens when running in Claude Desktop or other MCP clients.
Additional Options:
bash
[email protected] GARMIN_PASSWORD=secret garmin-mcp-auth
garmin-mcp-auth --force-reauth
After initial authentication, configure Claude Desktop without credentials (tokens are already saved):
json{
"mcpServers": {
"garmin": {
"command": "uvx",
"args": [
"--python",
"3.12",
"--from",
"git+https://github.com/Taxuspt/garmin_mcp",
"garmin-mcp"
]
}
}
}
bash
If you are working from a local checkout or fork:
uv tool install --python 3.12 --force C:\Users\aresd\Desktop\programacion\garmin_mcp
GARMIN_ENABLED_TOOLS
Comma-separated **allowlist** — if set, *only* these tools are registered.
GARMIN_DISABLED_TOOLS
Comma-separated **denylist** — listed tools are skipped. Ignored if an allowlist is set.
This MCP server implements 110+ tools covering ~90% of the python-garminconnect library (v0.3.2):
- ✅ Activity Management (20 tools) - includes write tools for type, description, event type, perceived effort, and feel
- ✅ Health & Wellness (31 tools) - includes custom lightweight summary tools
- ✅ Training & Performance (13 tools) - includes CTL/ATL/TSB, HRV, VO2 max, and respiration trends
- ✅ Workouts (8 tools)
- ✅ Devices (7 tools)
- ✅ Gear Management (5 tools)
- ✅ Weight Tracking (5 tools)
- ✅ Challenges & Badges (10 tools)
- ✅ Nutrition (8 tools) - food logs, meals, custom foods, and food logging
- ✅ Women's Health (3 tools)
- ✅ User Profile (3 tools)
- ✅ High-Level Workout Builders (4 tools) - create and schedule workouts without writing JSON
- ✅ Courses (3 tools) - list / upload GPX as course / delete course
- ✅ Activity Analysis (2 tools) - FIT file parsing, Power Duration Curve; requires power meter and/or Di2
- ✅ Activity File Downloads (2 tools) - download activity files in FIT, GPX, TCX, or CSV format
> Note: Activity Analysis tools require a compatible power meter (e.g., Garmin Rally, Favero Assioma, PowerTap P1) and/or Shimano Di2 / SRAM eTap electronic shifting. The fitparse dependency is installed automatically.
This server registers 110+ tools by default, which can be a lot of context for
an LLM to carry in every session. You can expose only the tools you need with
two optional environment variables:
| Env var | Effect |
|---|---|
| GARMIN_ENABLED_TOOLS | Comma-separated allowlist — if set, only these tools are registered. |
| GARMIN_DISABLED_TOOLS | Comma-separated denylist — listed tools are skipped. Ignored if an allowlist is set. |
Tool names are case-insensitive. With neither variable set, all tools register
(unchanged default behaviour). Names that match no tool are ignored with a
warning on stderr, which makes typos easy to spot.
Example — expose only sleep, stress, and recent activities:
"env": {
"GARMIN_ENABLED_TOOLS": "get_sleep_data,get_stress_summary,get_activities"
}
These builder tools let an LLM create and schedule workouts without writing raw Garmin JSON.
uvx --python 3.12 --from git+https://github.com/Taxuspt/garmin_mcp garmin-mcp-auth
The easiest way to handle MFA is using the dedicated authentication tool:
garmin-mcp-auth
This saves OAuth tokens to ~/.garminconnect for future use. The server will automatically use these tokens when running in Claude Desktop or other MCP clients.
Additional Options:
```bash
Claude Desktop / Cursor
Paste into your MCP client config file to install this server.
{
"mcpServers": {
"garmin mcp": {
"garmin_mcp": {
"command": "uvx",
"args": [
"--python",
"3.12",
"--from",
"git+https://github.com/Taxuspt/garmin_mcp",
"garmin-mcp-auth"
]
}
}
}
}
McpServers
{
"garmin_mcp": {
"command": "uvx",
"args": [
"--python",
"3.12",
"--from",
"git+https://github.com/Taxuspt/garmin_mcp",
"garmin-mcp-auth"
]
}
}
This Model Context Protocol (MCP) server connects to Garmin Connect and exposes your fitness and health data to Claude and other MCP-compatible clients.
Garmin's API is accessed via the awesome python-garminconnect library.
Features
- List recent activities with pagination support
- Get detailed activity information
- Edit activities: name, type, description/notes, event type, perceived effort (RPE), and feel
- Access health metrics (steps, heart rate, sleep, stress, respiration)
- View body composition data
- Track training status and readiness
- Access cycling FTP and lactate threshold metrics
- Manage gear and equipment
- Access workouts and training plans
- Inspect detailed workout step structures, including repeat groups and swim pace targets
- Weekly health aggregates (steps, stress, intensity minutes)
- Advanced cycling analytics: power zones, FIT file analysis, DI2 electronic shift intelligence
- Training load trend (CTL/ATL/TSB), HRV trend, VO2 max trend, respiration rate trend
- Power Duration Curve, climb detection with VAM, cardiac drift (aerobic decoupling), W/kg calculations
Tool Coverage
This MCP server implements 110+ tools covering ~90% of the python-garminconnect library (v0.3.2):
- ✅ Activity Management (20 tools) - includes write tools for type, description, event type, perceived effort, and feel
- ✅ Health & Wellness (31 tools) - includes custom lightweight summary tools
- ✅ Training & Performance (13 tools) - includes CTL/ATL/TSB, HRV, VO2 max, and respiration trends
- ✅ Workouts (8 tools)
- ✅ Devices (7 tools)
- ✅ Gear Management (5 tools)
- ✅ Weight Tracking (5 tools)
- ✅ Challenges & Badges (10 tools)
- ✅ Nutrition (8 tools) - food logs, meals, custom foods, and food logging
- ✅ Women's Health (3 tools)
- ✅ User Profile (3 tools)
- ✅ High-Level Workout Builders (4 tools) - create and schedule workouts without writing JSON
- ✅ Courses (3 tools) - list / upload GPX as course / delete course
- ✅ Activity Analysis (2 tools) - FIT file parsing, Power Duration Curve; requires power meter and/or Di2
- ✅ Activity File Downloads (2 tools) - download activity files in FIT, GPX, TCX, or CSV format
> Note: Activity Analysis tools require a compatible power meter (e.g., Garmin Rally, Favero Assioma, PowerTap P1) and/or Shimano Di2 / SRAM eTap electronic shifting. The fitparse dependency is installed automatically.
Activity File Downloads
Two tools let you download a raw activity file to disk:
- download_activity_file(activity_id, format="fit", output_dir=None) — downloads the activity and saves it to the configured directory. format accepts fit (default), gpx, tcx, or csv.
- set_fit_download_dir(path) — sets and persists the default download directory (written to the config file).
Where files are saved (precedence):
1. output_dir argument — one-off override, not persisted.
2. GARMIN_FIT_DOWNLOAD_DIR environment variable.
3. Persisted config set via set_fit_download_dir.
First-run behavior: if no directory is configured, download_activity_file returns status: "needs_setup". The assistant will ask where you want to save files (suggesting the current directory as default), call set_fit_download_dir to persist your choice, and then retry the download automatically.
Intentionally Skipped Endpoints
Some endpoints are not implemented due to performance or complexity considerations:
High Data Volume:
- get_activity_details() - Returns large GPS tracks and chart data (50KB-500KB). Use get_activity() for summaries instead.
Specialized Workout Formats:
- upload_running_workout(), upload_cycling_workout(), upload_swimming_workout() - Sport-specific workout uploads. Use upload_workout() for general workouts.
Maintenance & Destructive Operations:
- delete_activity(), delete_blood_pressure() - Destructive operations require careful consideration.
- Internal/Auth methods: login(), resume_login(), connectapi(), download() - Handled automatically by the library.
If you need any of these endpoints, please open an issue.
Tool Filtering
This server registers 110+ tools by default, which can be a lot of context for
an LLM to carry in every session. You can expose only the tools you need with
two optional environment variables:
| Env var | Effect |
|---|---|
| GARMIN_ENABLED_TOOLS | Comma-separated allowlist — if set, only these tools are registered. |
| GARMIN_DISABLED_TOOLS | Comma-separated denylist — listed tools are skipped. Ignored if an allowlist is set. |
Tool names are case-insensitive. With neither variable set, all tools register
(unchanged default behaviour). Names that match no tool are ignored with a
warning on stderr, which makes typos easy to spot.
Example — expose only sleep, stress, and recent activities:
"env": {
"GARMIN_ENABLED_TOOLS": "get_sleep_data,get_stress_summary,get_activities"
}
High-level workout tools
These builder tools let an LLM create and schedule workouts without writing raw Garmin JSON.
create_walk_run_workout
Creates a walk/run interval workout with optional heart-rate zone target.
{
"name": "W3 Mié 2:2",
"run_seconds": 120,
"walk_seconds": 120,
"repeats": 9,
"warmup_min": 10,
"cooldown_min": 8,
"hr_zone": "Z3"
}
Returns: {"status": "success", "workout_id": 1234567890, ...}
create_z2_walk_workout
Creates a steady Z2 walking workout.
{
"name": "Z2 Walk 45m",
"duration_min": 45,
"hr_min": 110,
"hr_max": 130
}
Returns: {"status": "success", "workout_id": 1234567890, ...}
create_strength_workout
Creates a strength workout from a list of exercises. Unknown names fall back to a generic step with the original name preserved.
{
"name": "Full Body A",
"exercises": [
{"name": "Sentadillas", "sets": 3, "reps": 12, "rest_seconds": 90},
{"name": "Flexiones", "sets": 3, "reps": 15, "rest_seconds": 60},
{"name": "Peso muerto", "sets": 3, "reps": 10, "rest_seconds": 90}
]
}
Returns: {"status": "success", "workout_id": 1234567890, ...}
schedule_week
Schedules multiple workouts in one call.
{
"week": [
{"date": "2026-05-12", "workout_id": 1234567890},
{"date": "2026-05-14", "workout_id": 1234567891}
]
}
Returns: {"status": "complete", "scheduled": [...]}
Full flow example
create_walk_run_workout(name="W3 Mié 2:2", run_seconds=120, walk_seconds=120,
repeats=9, warmup_min=10, cooldown_min=8)
→ workout_id = 1560092011
schedule_workout(workout_id=1560092011, date="2026-05-06")
→ OK
After syncing your watch, the workout appears on the Forerunner 965 calendar.
Raw upload_workout end conditions
When building custom workout JSON for upload_workout or upload_workouts, the
endCondition.conditionTypeId and endCondition.conditionTypeKey must match
Garmin's canonical mapping. Garmin treats the numeric conditionTypeId as the
source of truth; if the key and ID conflict, Garmin stores the condition that
matches the ID.
For example, this is invalid for a heart-rate end condition because ID 4 is
calories, not heart.rate:
{
"endCondition": {
"conditionTypeId": 4,
"conditionTypeKey": "heart.rate"
},
"endConditionValue": 145
}
Use ID 6 for heart rate:
{
"endCondition": {
"conditionTypeId": 6,
"conditionTypeKey": "heart.rate"
},
"endConditionValue": 145
}
Common end-condition IDs:
| ID | Key |
|---:|---|
| 1 | lap.button |
| 2 | time |
| 3 | distance |
| 4 | calories |
| 5 | power |
| 6 | heart.rate |
| 7 | iterations |
| 8 | fixed.rest |
| 9 | fixed.repetition |
| 10 | reps |
| 11 | training.peaks.tss |
Raw upload_workout target types
When building raw Garmin workout JSON, targetType.workoutTargetTypeId and
targetType.workoutTargetTypeKey must use Garmin's canonical mapping. Garmin
treats the numeric ID as authoritative: a mismatched payload such as
{"workoutTargetTypeId": 6, "workoutTargetTypeKey": "heart.rate"} is stored as
pace.zone, because ID 6 means pace.zone.
For a custom heart-rate range, use target type ID 4 with heart.rate.zone and
put the bpm range in targetValueOne / targetValueTwo:
{
"targetType": {
"workoutTargetTypeId": 4,
"workoutTargetTypeKey": "heart.rate.zone"
},
"targetValueOne": 143,
"targetValueTwo": 157
}
For a named Garmin HR zone, use the same target type with zoneNumber instead:
{
"targetType": {
"workoutTargetTypeId": 4,
"workoutTargetTypeKey": "heart.rate.zone"
},
"zoneNumber": 3
}
One-click Install (Claude Desktop)
The easiest way to add this server to Claude Desktop is via the .dxt Desktop Extension file — no JSON editing required.
Download and install
1. Download the latest garmin-mcp.dxt from the Releases page.
2. Drag the .dxt file into the Claude Desktop window, or double-click it, or go to Settings → Extensions → Install Extension and select the file.
3. Claude Desktop will prompt you for optional configuration (token path, email, password).
First-time authentication
The extension installs and runs the server automatically, but you must authenticate with Garmin once before data can be fetched:
uvx --python 3.12 --from git+https://github.com/Taxuspt/garmin_mcp garmin-mcp-auth
This saves OAuth tokens to ~/.garminconnect. After that the server works without any credentials in the config.
> Note: Tokens are valid for approximately 6 months. Re-run garmin-mcp-auth when they expire.
Build the .dxt yourself
bash scripts/build_dxt.sh # produces garmin-mcp.dxt in the repo root
---
Setup
Quick Start for MCP Clients
The easiest way to use this MCP server with Claude Desktop, Codex, or another MCP client is to authenticate once before adding the server to your configuration.
Prerequisites
- Python 3.12+
- Garmin Connect account
- MFA may be required if enabled on your account
Step 1: Pre-authenticate (One-time)
Before adding the server to your MCP client, authenticate once in your terminal:
```bash
Sign in to leave a review
Use Google, GitHub, or an email account so ratings stay tied to real people.
No reviews posted yet.



