CLAUDE CODE MARKETPLACES

Garmin MCP Server

This Model Context Protocol (MCP) server connects to Garmin Connect and exposes your fitness and health data to Claude and other MCP-compatible clients.

claude mcp add garmin_mcp -- npx -y garmin_mcp
README.md

MseeP.ai Security Assessment Badge

Garmin MCP Server

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
  • Manage activity names
  • 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 (15 tools)
  • ✅ 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

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.

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.

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.

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 Claude Desktop

The easiest way to use this MCP server with Claude Desktop 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 to Claude Desktop, authenticate once in your terminal:


# Install and run authentication tool
uvx --python 3.12 --from git+https://github.com/Taxuspt/garmin_mcp garmin-mcp-auth

# You'll be prompted for:
# - Email (or set GARMIN_EMAIL env var)
# - Password (or set GARMIN_PASSWORD env var)
# - MFA code (if enabled on your account)

# OAuth tokens will be saved to ~/.garminconnect

You can verify your credentials at any time with

uv run garmin-mcp-auth --verify

Note: You can also set credentials via environment variables:

GARMIN_EMAIL=your@email.com GARMIN_PASSWORD=secret garmin-mcp-auth

If you don't have MFA enabled you can also skip garmin-mcp-auth and pass GARMIN_EMAIL and GARMIN_PASSWORD as env variables directly to Claude Desktop (or other MCP client, if supported), see below for an example.

Step 2: Configure Claude Desktop

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.

Step 3: Restart Claude Desktop

Your Garmin data is now available in Claude!


Development Setup

  1. Install the required packages on a new environment:
uv sync

Running the Server

Configuration

Your Garmin Connect credentials are read from environment variables:

  • GARMIN_EMAIL: Your Garmin Connect email address
  • GARMIN_EMAIL_FILE: Path to a file containing your Garmin Connect email address
  • GARMIN_PASSWORD: Your Garmin Connect password
  • GARMIN_PASSWORD_FILE: Path to a file containing your Garmin Connect password
  • GARMIN_IS_CN: Set to true to use Garmin Connect China (garmin.cn) instead of the international version (default: false)

File-based secrets are useful in certain environments, such as inside a Docker container. Note that you cannot set both GARMIN_EMAIL and GARMIN_EMAIL_FILE, similarly you cannot set both GARMIN_PASSWORD and GARMIN_PASSWORD_FILE.

Garmin Connect China (garmin.cn)

If you use Garmin Connect China (garmin.cn) instead of the international version, set the GARMIN_IS_CN environment variable to true:

# Pre-authenticate with Garmin Connect China
GARMIN_IS_CN=true garmin-mcp-auth

# Or use the CLI flag
garmin-mcp-auth --is-cn

For Claude Desktop, add GARMIN_IS_CN to the env section:

{
  "mcpServers": {
    "garmin": {
      "command": "uvx",
      "args": [
        "--python",
        "3.12",
        "--from",
        "git+https://github.com/Taxuspt/garmin_mcp",
        "garmin-mcp"
      ],
      "env": {
        "GARMIN_IS_CN": "true"
      }
    }
  }
}

For Docker, add GARMIN_IS_CN=true to your .env file or uncomment it in docker-compose.yml.

Testing the server locally with MCP Inspector

The Inspector runs directly through npx without requiring installation. Run from the project root:

npx @modelcontextprotocol/inspector uv run garmin-mcp

You'll be able to inspect and test the tools.

With Claude Desktop

  1. Create a configuration in Claude Desktop:

Edit your Claude Desktop configuration file:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json
  • Windows: %APPDATA%\Claude\claude_desktop_config.json

You have two options to run the MCP locally with Claude.

Directly from github without cloning the repo:

  1. Add this server configuration:
{
  "mcpServers": {
    "garmin": {
      "command": "uvx",
      "args": [
        "--python",
        "3.12",
        "--from",
        "git+https://github.com/Taxuspt/garmin_mcp",
        "garmin-mcp"
      ],
      "env": {
        "GARMIN_EMAIL": "YOUR_GARMIN_EMAIL",
        "GARMIN_PASSWORD": "YOUR_GARMIN_PASSWORD"
      }
    }
  }
}

You might have to add the full path to uvx you can check the full path with which uvx

  1. Restart Claude Desktop

Directly from your local copy of the repository:

  1. Add this server configuration:
{
  "mcpServers": {
    "garmin-local": {
      "command": "uv",
      "args": [
        "--directory",
        "<full path to your local repository>/garmin_mcp",
        "run",
        "garmin-mcp"
      ]
    }
  }
}
  1. Restart Claude Desktop

With Docker

Docker provides an isolated and consistent environment for running the MCP server.

Quick Start with Docker Compose (Recommended)

  1. Create a .env file with your credentials:
echo "GARMIN_EMAIL=your_email@example.com" > .env
echo "GARMIN_PASSWORD=your_password" >> .env
  1. Start the container:
docker compose up -d
  1. View logs to monitor the server:
docker compose logs -f garmin-mcp

Using Docker Directly

# Build the image
docker build -t garmin-mcp .

# Run the container
docker run -it \
  -e GARMIN_EMAIL="your_email@example.com" \
  -e GARMIN_PASSWORD="your_password" \
  -v garmin-tokens:/root/.garminconnect \
  garmin-mcp

Using File-Based Secrets (More Secure)

For enhanced security, especially in production environments, use file-based secrets instead of environment variables:

  1. Create a secrets directory and add your credentials:
mkdir -p secrets
echo "your_email@example.com" > secrets/garmin_email.txt
echo "your_password" > secrets/garmin_password.txt
chmod 600 secrets/*.txt
  1. Edit docker-compose.yml and uncomment the secrets section:
services:
  garmin-mcp:
    environment:
      - GARMIN_EMAIL_FILE=/run/secrets/garmin_email
      - GARMIN_PASSWORD_FILE=/run/secrets/garmin_password
    secrets:
      - garmin_email
      - garmin_password

secrets:
  garmin_email:
    file: ./secrets/garmin_email.txt
  garmin_password:
    file: ./secrets/garmin_password.txt
  1. Start the container:
docker compose up -d

Handling MFA with Docker

If you have multi-factor authentication (MFA) enabled on your Garmin account:

  1. Run the container in interactive mode:
docker compose run --rm garmin-mcp
  1. When prompted, enter your MFA code:
Garmin Connect MFA required. Please check your email/phone for the code.
Enter MFA code: 123456
  1. The OAuth tokens will be saved to the Docker volume (garmin-tokens), so you won't need to re-authenticate on subsequent runs.

  2. After MFA setup, you can run the container normally:

docker compose up -d

Docker Volume Management

The OAuth tokens are stored in a persistent Docker volume to avoid re-authentication:

# List volumes
docker volume ls

# Inspect the tokens volume
docker volume inspect garmin_mcp_garmin-tokens

# Remove the volume (will require re-authentication)
docker volume rm garmin_mcp_garmin-tokens

Using with Claude Desktop via Docker

To use the Dockerized MCP server with Claude Desktop, you can configure it to communicate with the container. However, note that MCP servers typically communicate via stdio, which works best with direct process execution. For Docker-based deployments, consider using the standard uvx method shown in the With Claude Desktop section instead.

Usage Examples

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?"

Troubleshooting

"Failed to spawn process: No such file or directory"

If Claude Desktop can't find uvx, it's because uvx is not in the PATH that Claude Desktop uses. To fix this:

  1. Find where uvx is installed:
which uvx
  1. Use the full path in your configuration. For example, if uvx is at /Users/username/.cargo/bin/uvx:
{
  "mcpServers": {
    "garmin": {
      "command": "/Users/username/.cargo/bin/uvx",
      "args": [
        "--python",
        "3.12",
        "--from",
        "git+https://github.com/Taxuspt/garmin_mcp",
        "garmin-mcp"
      ]
    }
  }
}

Login Issues

If you encounter login issues:

  1. Verify your credentials are correct
  2. Check if Garmin Connect requires additional verification
  3. Ensure the garminconnect package is up to date

Logs

For other issues, check the Claude Desktop logs at:

  • macOS: ~/Library/Logs/Claude/mcp-server-garmin.log
  • Windows: %APPDATA%\Claude\logs\mcp-server-garmin.log

Garmin Connect Multi-Factor Authentication (MFA)

Understanding MFA with MCP Servers

MCP servers run as background processes without direct terminal access. If your Garmin account has MFA enabled, you must authenticate once using the pre-authentication tool before the server can run.

Recommended: Pre-Authentication Tool

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:

# Use environment variables for credentials
GARMIN_EMAIL=you@example.com GARMIN_PASSWORD=secret garmin-mcp-auth

# Verify existing tokens
garmin-mcp-auth --verify

# Force re-authentication (e.g., when tokens expire)
garmin-mcp-auth --force-reauth

# Use custom token location
garmin-mcp-auth --token-path ~/.garmin_tokens

Alternative: Manual First Run

You can also authenticate by running the server once interactively:

# Store credentials in files for security
echo "your_email@example.com" > ~/.garmin_email
echo "your_password" > ~/.garmin_password
chmod 600 ~/.garmin_email ~/.garmin_password

# Run server interactively to authenticate
GARMIN_EMAIL_FILE=~/.garmin_email GARMIN_PASSWORD_FILE=~/.garmin_password \
  uvx --python 3.12 --from git+https://github.com/Taxuspt/garmin_mcp garmin-mcp

# Enter MFA code when prompted
# Tokens will be saved automatically
# Now add to Claude Desktop config without credentials

After initial authentication, configure Claude Desktop without credentials (tokens are already saved):

{
  "mcpServers": {
    "garmin": {
      "command": "uvx",
      "args": [
        "--python",
        "3.12",
        "--from",
        "git+https://github.com/Taxuspt/garmin_mcp",
        "garmin-mcp"
      ]
    }
  }
}

Using Docker with MFA

If using Docker, follow the Handling MFA with Docker section above for a streamlined experience with persistent token storage.

Troubleshooting MFA

Error: "MFA authentication required but no interactive terminal available"

Solution:

  1. Open terminal
  2. Run: garmin-mcp-auth
  3. Enter credentials and MFA code
  4. Restart Claude Desktop

Token Expired

OAuth tokens expire periodically (approximately every 6 months). Re-authenticate:

garmin-mcp-auth --force-reauth

Verify Tokens Work

garmin-mcp-auth --verify

Testing

This project includes comprehensive tests for all MCP tools. All tests are currently passing (100%).

Running Tests

# Run all integration tests (default - uses mocked Garmin API)
uv run pytest tests/integration/

# Run tests with verbose output
uv run pytest tests/integration/ -v

# Run a specific test module
uv run pytest tests/integration/test_health_wellness_tools.py -v

# Run end-to-end tests (requires real Garmin credentials)
uv run pytest tests/e2e/ -m e2e -v

Test Structure

  • Integration tests (200+ tests): Test all MCP tools using FastMCP integration with mocked Garmin API responses
  • End-to-end tests (4 tests): Test with real MCP server and Garmin API (requires valid credentials)

Reinstalling from local path

If you are working from a local checkout or fork:

uv tool install --python 3.12 --force C:\Users\aresd\Desktop\programacion\garmin_mcp
Stars478
Installs290
Forks139
LanguagePython
AddedMar 8, 2025
UpdatedMay 14, 2026
View on GitHub