Garmin MCP Lite
[For AI Assistants & LLMs] You are interfacing with a Garmin MCP (Model Context Protocol) server.
- Data Freshness: Always query the data if the user asks about their recent workouts or health metrics.
- Parameter Tuning: Use the
fieldsparameter in tools likegarmin_activity_detailto limit the response payload and save context window (e.g.,["splits", "hrZones"]).- Read-Only: This server provides read-only access to Garmin Connect. You cannot modify user data.
- No Password Request: Never ask the user for their Garmin password. Authentication is handled out-of-band via a local token.
- Health Tip:
garmin_healthnow supports ametricparameter — use"steps","sleep","hrv","spo2","body_battery", etc., to query specific data and save context window.- Zone Context:
garmin_activity_detailreturns seconds per heart rate zone but no boundaries. Callgarmin_zonesfirst to get the bpm ranges before judging intensity.
Read this in other languages: English, 简体中文.
A lightweight Garmin Model Context Protocol (MCP) server, designed specifically for endurance athletes.
It exposes 15 precisely-curated endpoints for deep analysis of running, cycling, swimming, and health data — replacing bulky 80+ endpoint alternatives with a clean, focused toolset.
Core Tools (15)
🏃 Activity & Training
| Tool | Functionality |
|---|---|
garmin_activities |
List running/cycling/swimming/diving records with date & type filters. |
garmin_activity_detail |
Get single activity details (pace, heart rate zones, splits, GPS, etc.). |
garmin_training_plan |
Get today's or a specific date's scheduled training workout. |
garmin_training_status |
Get training status, VO2Max, acute load, load focus distribution (aerobic/anaerobic), recovery time, and training readiness score. |
garmin_weekly_stats |
Get weekly/monthly/yearly training volume statistics. |
garmin_coach |
Overview of current Garmin Coach training plans. |
garmin_race_prediction |
Predicted 5K/10K/half/marathon finish times with pace, plus the change over a 90-day or 1-year window. |
garmin_personal_records |
Personal bests (1K → marathon, longest run/ride, swim times, step records) with the activity that set each one. |
💚 Health & Wellness
| Tool | Functionality |
|---|---|
garmin_health |
Get comprehensive health metrics: sleep quality, HRV status, stress, body battery, SpO2, respiration rate, intensity minutes, daily steps, floors climbed, and resting heart rate. Supports metric parameter for targeted queries. |
garmin_hr_trend |
Get resting heart rate trends for the last 7/30/90 days. |
garmin_zones |
Heart rate zone boundaries (bpm ranges) per sport, plus lactate threshold and FTP. Use it to interpret the hrZones durations returned by garmin_activity_detail. |
🎯 Goals & Challenges
| Tool | Functionality |
|---|---|
garmin_events |
Get your race calendar: upcoming race dates, target distances, and goal finish times. |
garmin_challenges |
Get in-progress challenges: virtual climbs, monthly badge challenges, and their completion percentages. |
⌚ Device & Gear
| Tool | Functionality |
|---|---|
garmin_gear |
Get your shoe/bike gear list and their real cumulative mileage. |
garmin_device |
Get connected device info: firmware version, update availability, primary device status, and registration date. |
Quickstart
There are two ways to run the server. Installing it as a command is the safer default — it starts in well under a second, needs no network at launch, and GUI clients can find it. uvx works too, but it downloads on first run and is invisible to clients that do not inherit your shell PATH.
1. Install
uv tool install garmin-mcp-lite
which garmin-mcp-lite # → ~/.local/bin/garmin-mcp-lite
Alternative: run via uvx without installing
uvx garmin-mcp-lite
Fine for terminal clients such as Claude Code or Codex CLI. See Troubleshooting for why GUI clients usually need the installed path instead.
2. Authenticate (First Time Only)
Why not just put the password in the AI config? Garmin has strict security measures. Logging in from a new location/MCP server often triggers Cloudflare CAPTCHAs or MFA email codes. If the password sits in a client's background config, the AI assistant silently freezes when challenged, with no way for you to type the code in.
So this project uses a two-step strategy: run the login script in your terminal first. If Garmin challenges you, you can type the MFA code interactively. On success the session token is cached locally and stays valid for roughly a year.
GARMIN_EMAIL="your@email.com" GARMIN_PASSWORD="your_password" garmin-mcp-lite-login
(💡 China Region Users: if your account is registered with Garmin China (garmin.cn), prefix the command with GARMIN_IS_CN=true.)
The token is written to ~/.garmin-mcp-lite/garmin_tokens.json. Set GARMIN_TOKEN_DIR to keep several clients or accounts on separate sessions.
3. Configure Your AI Assistant
Claude Desktop
Add this to ~/Library/Application Support/Claude/claude_desktop_config.json:
{
"mcpServers": {
"garmin-lite": {
"command": "/Users/you/.local/bin/garmin-mcp-lite",
"args": []
}
}
}
Prefer uvx? Use "command": "uvx" with "args": ["garmin-mcp-lite"].
Cursor / Windsurf / Gemini CLI
Use the same command and args as above.
Chatbox / opencode / Other GUI Clients
GUI clients such as Chatbox are launched from Finder and do not inherit your shell PATH, so a bare uvx fails with spawn uvx ENOENT. Point them at the absolute path from step 1.
Chatbox (Settings → MCP → Add custom):
{
"mcpServers": {
"garmin": {
"command": "/Users/you/.local/bin/garmin-mcp-lite",
"args": []
}
}
}
opencode (opencode.json) uses a different schema — the key is mcp, type is required, and command is an array:
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"garmin": {
"type": "local",
"command": ["/Users/you/.local/bin/garmin-mcp-lite"],
"enabled": true,
"timeout": 30000
}
}
}
opencode's
timeoutdefaults to 5000 ms. Raise it if you insist onuvxinstead of an installed command.
Environment Variables
| Variable | Default | Purpose |
|---|---|---|
GARMIN_IS_CN |
unset | Set to true for accounts registered with Garmin China (garmin.cn). Must match the region used at login. |
GARMIN_TOKEN_DIR |
~/.garmin-mcp-lite |
Where the session token lives. Change it to isolate multiple accounts. |
GARMIN_EMAIL / GARMIN_PASSWORD |
unset | Login script only. Never needed by the server itself. |
Troubleshooting
| Symptom | Cause | Fix |
|---|---|---|
spawn uvx ENOENT, MCP error -32000: Connection closed |
client cannot find uvx on PATH |
use the absolute path of the installed command |
| Server never connects, no error shown | first-run download exceeded the client timeout | uv tool install first, or raise timeout |
ModuleNotFoundError: No module named 'mcp.server.fastmcp' |
mcp 2.x was resolved by a lock-ignoring install |
uv tool install --with "mcp<2" garmin-mcp-lite, or upgrade to ≥ 0.1.4 |
Tools list loads, calls fail with Garmin token not found |
no cached session on this machine | run garmin-mcp-lite-login |
Authentication failed on a garmin.cn account |
GARMIN_IS_CN missing from the client's env |
add "env": {"GARMIN_IS_CN": "true"} |
| Zones look too high, "easy" runs land in Z3 | max heart rate set above your real one | check garmin_zones, then fix MaxHR in Garmin Connect |
Verify the server independently of any client:
printf '%s\n' \
'{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"t","version":"1"}}}' \
'{"jsonrpc":"2.0","method":"notifications/initialized"}' \
'{"jsonrpc":"2.0","id":2,"method":"tools/list"}' | garmin-mcp-lite
Expect a serverInfo line reporting this package's version, followed by all 15 tools.
Example Queries
Once connected, you can ask your AI assistant natural-language questions like:
Training
- "What's my training load focus this week?"
- "Show me my race goal for June and what my current predicted finish time is."
- "Compare my marathon PB against the current prediction."
Health
- "How many steps have I taken today? Am I on track for my daily goal?"
- "Analyze my sleep quality from last night."
- "What are my heart rate zones for running, and where does my lactate threshold sit?"
Gear & Goals
- "How's my Grossglockner virtual climb challenge going?"
- "Is my Descent G1 firmware up to date?"
Manual Installation (for Developers)
If you want to modify the code:
git clone https://github.com/Golden0Voyager/garmin-mcp-lite.git
cd garmin-mcp-lite
uv sync
# Login
GARMIN_EMAIL="your@email.com" GARMIN_PASSWORD="your_password" python -m garmin_mcp_lite.login
# Run server
python -m garmin_mcp_lite.server
Run the same gates CI runs before opening a PR:
uv run ruff check garmin_mcp_lite/ tests/ scripts/
uv run mypy garmin_mcp_lite/
uv run pytest --cov tests/
python3 scripts/smoke_wheel_install.py
The suite is at 100% statement coverage across every module, including the
15-tool registry in server.py. tests/test_server.py pins the exact tool
names, so a rename or a dropped add_tool() call fails a test instead of
silently disappearing from a client's tools/list.
There is also a live end-to-end script that walks all 15 tools against your own account (needs a login token):
python test_e2e.py
Comparison with Other Garmin MCPs
| Taxuspt/garmin_mcp | garmin_mcp_lite | |
|---|---|---|
| Tool Count | 80+ | 15 |
| Naming | mcp_garmin_get_activities_by_date |
garmin_activities |
| Deep Queries | No | fields parameter controls detail granularity |
| Training Load | Basic | Acute load + load focus distribution |
| Performance | No | Race predictions + personal records |
| Zones | No | HR zone boundaries + lactate threshold + FTP |
| Health Depth | Basic | SpO2, respiration, intensity minutes, steps |
| Race/Challenge | No | Events calendar + challenge progress |
| Write Ops | Heavy (weight/nutrition/gear) | Read-only |
| Schema cost | High | ~2.3k tokens for all 15 tools |
Changelog
0.1.6
- Fix:
garmin_eventscrashed with'NoneType' object has no attribute 'get'on any event without a custom goal — Garmin sendscustomGoal: nullrather than omitting the key, so.get(key, {})never applied. Affected most real calendars. - Fix:
garmin_zonescrashed with'Garmin' object has no attribute 'get_heart_rate_zones'. That method is absent ingarminconnect0.3.3 (still within the supported range); the tool now reads/biometric-service/heartRateZonesdirectly, which is stable across versions. - Fix: a missing intermediate zone floor no longer makes the zone below it extend all the way to max HR and overlap every zone above it.
- Fix: nested payloads that Garmin sends as
null(summaryDTO,metadataDTO,dailySleepDTO,sleepScores,hrvSummary,userData,workoutSteps,acuteTrainingLoadDTO, training load balance map) are now coerced to empty containers instead of raising. - Test: statement coverage 90% → 100% (171 tests).
server.pyis measured now instead of omitted, so the 15 tool registrations are actually asserted. - Test:
tests/test_client.pyno longer reloads the client module, which is why CI had to skip it with-k 'not test_get_client'; that filter is gone. - Test:
test_e2e.pycovers all 15 tools (was 9) and keeps going after a failure so one broken tool does not hide the rest. - Repackage: the 0.1.5 sdist accidentally shipped a local notes file.
0.1.5
- New:
garmin_race_prediction— predicted 5K/10K/half/marathon times, with 90-day and 1-year trends. - New:
garmin_personal_records— personal bests with the activity that set each one. - New:
garmin_zones— per-sport heart rate zone boundaries, lactate threshold, and FTP. - Fix:
serverInfo.versionreported themcpdependency's version instead of this package's. - Docs: client setup for Chatbox and opencode, troubleshooting table, environment variables.
0.1.4
- Cap
mcp<2.0so lock-ignoring installers (uvx,pip) stop resolvingmcp2.x.
License
MIT © 2026 Haining Yu
This project is built on top of the excellent garminconnect library. It is not an official Garmin product. Please adhere to Garmin Connect's terms of service when using this tool.
Metadata
Release files for garmin-mcp-lite 0.1.6
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| garmin_mcp_lite-0.1.6.tar.gz | 139.2 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| garmin_mcp_lite-0.1.6-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 171.5 kB
Release files / garmin_mcp_lite-0.1.6.tar.gz
| Download URL | garmin_mcp_lite-0.1.6.tar.gz |
|---|---|
| Size | 139.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a2eea719d4d25adce9ccacc43c19bf279e80cbf230a2318e65e2161d805c618b
|
|
BLAKE2b-256 checksum How to use checksums |
71cf68c92f55c2d86dc0895e0200b60ce102e0bb59c5af2cbe3941d831537f43
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / garmin_mcp_lite-0.1.6-py3-none-any.whl
| Download URL | garmin_mcp_lite-0.1.6-py3-none-any.whl |
|---|---|
| Size | 32.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
3504f4360c522effeb2b1561b9657c526c936fc0d1fba9294594db4693b6501c
|
|
BLAKE2b-256 checksum How to use checksums |
2dede66f1d07b6b75f661b91f1f683a96f93c7325dcfa0770c8368be75c5631b
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.13.5 {"installer":{"name":"uv","version":"0.13.5","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Security for garmin-mcp-lite 0.1.6
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.