Garmin MCP
Ask your AI about your Garmin data, on Garmin's official API.
Quickstart · Tools · Authentication · Changelog
Connect Garmin Connect to Claude or any MCP client. Ask about last night'ssleep, HRV trends, Body Battery, training load, or a specific run, all fromyour real Garmin account.
Published on PyPI as garmin-personal-mcp.
Unofficial project, official API. This isn't made by Garmin, but it onlytalks to Garmin's documentedPersonal APIthrough Garmin's own Python client.
Why this one?
Most Garmin MCP servers sign in with your Garmin password through theunofficial garminconnect library, which breaks whenever Garmin changes itslogin. In October 2026 Garmin opened a PersonalAPI for individuals. This server uses it:
- No password, no scraping: a revocable Personal API key you create inGarmin Connect, exchanged for short-lived tokens
- The whole Personal API: every working endpoint in Garmin's referencehas a tool, with every documented filter
- Any date range: ranges longer than an endpoint allows (28 days forsteps, 31 for sleep, and so on) are split into requests for you
- Model-sized responses: all-day sample arrays are left out unless you askfor them
- Read-only: the Personal API can't change your account, and neither canthis server
Quickstart
Save your Personal API key (one-time; see Authentication):
uvx garmin-personal-mcp authAdd the server to your client. The install buttons at the top do this inone click for Cursor and VS Code.
Claude Code
claude mcp add garmin -- uvx garmin-personal-mcpOr install it as a plugin, which asks for your key in place of step 1:
/plugin install garmin-personal-mcp --marketplace Mason-Levyy/garmin-personal-mcpClaude Desktop (
claude_desktop_config.json), Cursor(~/.cursor/mcp.json), Windsurf (~/.codeium/windsurf/mcp_config.json),and Cline (cline_mcp_settings.json) all take the same entry:
VS Code, Codex CLI, Gemini CLI{ "mcpServers": { "garmin": { "command": "uvx", "args": ["garmin-personal-mcp"] } } }VS Code (or use the button above):
code --add-mcp '{"name":"garmin","command":"uvx","args":["garmin-personal-mcp"]}'Codex CLI:
codex mcp add garmin -- uvx garmin-personal-mcpGemini CLI:
gemini mcp add garmin uvx garmin-personal-mcpAsk it something: "how did I sleep last night?", "is my HRV trendingdown this month?", "compare my last three long runs".
Requires uv. Any MCP client that speaks stdio orstreamable HTTP works, not just Claude.
Finding this useful? A ⭐ onGitHub helps otherGarmin users find it.
Authentication
- Sign in to Garmin Connect on the web and openSettings → Personal API.
- Create a key and choose how long it lasts (30 days to a year). Garmin showsit once.
- Run
garmin-personal-mcp authand paste it at the hidden prompt. Theserver checks it with Garmin before saving it to~/.config/garmin/connect-personal-api-keywith owner-only permissions.
Where there's no terminal to prompt in (a script, or a shell an agent runs),pipe the key in instead, e.g. pbpaste | garmin-personal-mcp auth.
garmin-personal-mcp auth --check reports whether the saved key still works,without prompting. Garmin emails you about a week before a key expires: createa new one and run auth again. No restart is needed; the server reads the keyon every call.
Instead of the key file you can set GARMIN_PERSONAL_API_KEY, which takesprecedence. The key file and bearer-token cache are the same ones Garmin'sgc-personal CLI uses, so a key saved by either works for both.
Tools
All tools take dates as YYYY-MM-DD. Range tools default to the 7 days endingtoday. Tools that return a list wrap it as {"results": [...]}.
| Tool | What it returns |
|---|---|
garmin_get_day |
One day at a glance: summary, sleep, HRV, Body Battery, stress, and activities |
garmin_get_daily_summary |
Every all-day wellness total for one date |
garmin_get_daily_summaries |
Daily summaries across a range (trends over weeks or months) |
garmin_get_steps |
Daily steps, distance, and goal |
garmin_get_stress |
Daily stress level and time in each stress band |
garmin_get_hydration |
Daily intake, goal, and sweat loss |
garmin_get_body_battery |
Daily charge/drain and the events behind it; chunks for intraday lows/highs |
garmin_get_heart_rate |
Resting/min/max HR, 7-day resting average, abnormal HR alerts; samples on request |
garmin_get_spo2 |
Pulse ox averages, hourly averages, acclimation; readings on request |
garmin_get_wellness_activities |
Wellness activities with summary values and time in zones |
garmin_get_sleep |
One night in full: score, stages, timings, overnight vitals |
garmin_get_sleep_summaries |
Nightly sleep records across a range |
garmin_get_hrv |
One night of HRV with every reading |
garmin_get_hrv_summaries |
Nightly HRV, weekly average, baseline, and status across a range |
garmin_get_weight |
Daily weight summaries, range average, and adjacent weigh-ins; every weigh-in with include_all |
garmin_get_weight_goals |
Weight goals in effect and their target ranges |
garmin_get_food_log |
Garmin Connect nutrition log: foods, nutrients, goals, meals |
garmin_search_activities |
Activities with every filter Garmin supports (type, dates, distance, power, area, dives, ...) |
garmin_get_activity |
One activity in full, with splits |
garmin_get_activity_workouts |
The structured workout followed during an activity |
garmin_download_activity |
Save an activity's original file (ZIP with the .fit) on the server's machine |
garmin_get_profile |
Units, formats, time zone, and training-day preferences |
garmin_get_heart_rate_zones |
Zone floors per sport and the HRs they're based on |
garmin_get_fitness_age |
Fitness age, achievable fitness age, and its components |
garmin_get_menstrual_cycle |
Cycle phase, day, fertile window, and predictions |
garmin_get_menstrual_day |
One day's logged symptoms, flow, and cycle detail |
Weights are in grams, distances in meters, and durations in seconds, as Garminreturns them.
Remote / HTTP mode
The default transport is stdio. For network clients:
garmin-personal-mcp --http --host 127.0.0.1 --port 8491
This serves streamable HTTP at /mcp. There is no built-in authentication.Never expose it to the internet. Bind to localhost and front it withsomething that authenticates for you: a VPN or tailnet (e.g. tailscale serve), an authenticating reverse proxy, or an OAuth-aware MCP gateway. Behinda proxy, pass --allowed-host <proxy hostname> (repeatable) so theDNS-rebinding check accepts its Host header.
Configuration
| Variable | Purpose | Default |
|---|---|---|
GARMIN_PERSONAL_API_KEY |
Personal API key; overrides the saved key file | – |
GARMIN_MCP_DOWNLOAD_DIR |
Where garmin_download_activity saves files |
~/Downloads/garmin (platform downloads dir) |
Troubleshooting
- "Garmin rejected the Personal API key": the key expired or was deleted.Create a new one and run
garmin-personal-mcp auth. - "No usable Garmin Personal API key was found": run
garmin-personal-mcp auth, orsetGARMIN_PERSONAL_API_KEYin the client config. {"no_data": ...}: Garmin has nothing for that date yet (today's HRVbefore you've slept, for example), or your device doesn't record thatmetric.- HTTP 400 on a long range: an endpoint without a documented limitrejected the range. Ask for a shorter one.
FAQ
Is this the official Garmin API? Yes. It uses Garmin's Personal API, whichanyone with a Garmin Connect account can enable without applying, throughGarmin's Apache-licensed Python client. The project itself is independent.
Can it change my Garmin data? No. The Personal API is read-only. The onetool that writes anything, garmin_download_activity, saves a file on yourown machine.
Which MCP clients does it work with? Any client that runs a stdio orstreamable HTTP server, including Claude Desktop, Claude Code, Cursor,Windsurf, Cline, and VS Code. AI coding agents can followllms-install.md.
Where does my data go? The server talks only to Garmin. Your key andbearer token stay in ~/.config/garmin/. Tool results go to whichever MCPclient and model you connect it to.
Can I use it for other people's accounts? No. Garmin's Personal API is foryour own data. Apps serving other users need Garmin's business developerprogram.
How it works
garmin-personal-mcp authsaves the key; each call exchanges it for abearer token through Garmin'sPersonalApiAuthenticator, which caches thetoken until an hour before it expires. A token rejected early gets oneretry with a fresh exchange.- Each tool maps to one endpoint on
personal.connectapi.garmin.com(garmin_get_daycombines several). Ranges longer than an endpoint'sdocumented maximum are fetched in consecutive windows and concatenated. - Bulky per-minute sample arrays are dropped by default to keep responsesreadable for a model;
include_samplesorchunksbring them back.
Development
git clone https://github.com/Mason-Levyy/garmin-personal-mcp
cd garmin-personal-mcp
uv sync
uv run pytest
Tests run against synthetic fixtures; no account needed. Lint and formattingare enforced with ruff (uv run ruff check ., uv run ruff format .).
Contributing
Issues and pull requests are welcome, especially when Garmin adds endpoints tothe Personal API. See CONTRIBUTING.md for setup, style, andthe PR checklist, and SECURITY.md for how to reportvulnerabilities privately. Release history is in CHANGELOG.md.
Support the project
If this server saves you time, pleasestar the repo. Stars arehow other Garmin users find it in GitHub search and MCP directories. Bugreports and endpoint requests are just as welcome inissues.
License
MIT. Garmin and Garmin Connect are trademarks of Garmin Ltd. or itssubsidiaries; this project is not affiliated with or endorsed by Garmin.