Garmin Connect MCP
Reads a user's Garmin Connect account using their own login, exposing activities (distance, pace, power, HR zones, laps, weather, gear, training effect), downsampled time-series streams (heart rate, power, speed, cadence, elevation, temperature), fitness thresholds (lactate threshold, cycling FTP, race predictions), recovery metrics (sleep stages and scores, overnight HRV, Body Battery, stress, training readiness and status), trends (weekly volume, activity mix, comparisons, similar activities), and the rest of the account (weight and body composition, goals, PRs, badges, challenges, devices, gear mileage, workouts). Also exports original .fit files and powers a local dashboard that syncs the full Garmin history.
Optionally connects a Strava account to the local dashboard and tools, adding heart-rate and power zones as configured on Strava plus time spent in them per activity, running best efforts across distances, per-km splits, segments and gear mileage — data Garmin does not provide.
Click on "Deploy 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 Connect MCPhow did my long ride go and am I recovered enough for intervals today?"
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 Connect MCP is a Model Context Protocol server that lets Claude (or any MCP client) read your Garmin Connect account. Ask in plain language — "how did my long ride go?", "am I recovered enough for intervals today?", "chart HR and power for last Saturday" — and the model pulls the real numbers instead of guessing.
It also ships a local dashboard: one command downloads your entire history (activities, sleep, HRV, Body Battery, stress, readiness, VO₂ max, training status, weight) — and, if you connect it, your Strava zones, best efforts, splits, segments and gear — and opens it as an interactive page. Filter any view by dates, sports and source, tap any number to see how it changed over time and the exact rows behind it, and browse or export every table as CSV.
It talks to Garmin Connect with your own login, stores nothing on any server, and keeps your tokens and exported files readable only by your user.
Fork of eddmann/garmin-connect-mcp (MIT, © Edd Mann). This fork fixes tools that never worked upstream, adds the raw data you need to build dashboards, and tightens how credentials and personal data are handled. Every change is listed in What this fork changes.
Like it? A ⭐ on the repo helps other athletes find it.
Contents
Related MCP server: Garmin Health MCP Server
What you can do
Ask about any activity | Distance, pace, power, HR zones, laps, weather, gear and training effect for every run, ride, swim or strength session. |
Chart the raw signal | Downsampled time-series of heart rate, power, speed, cadence, elevation and temperature, ready to plot. |
Know your thresholds | Lactate threshold (HR and pace), cycling FTP, race predictions and weekly running tolerance in one call. |
Check recovery | Sleep stages and scores, overnight HRV, Body Battery, stress, training readiness and training status. |
Spot trends | Weekly volume, activity mix, side-by-side comparisons and "find similar activities". |
Keep the originals | Export the original |
Track the rest | Weight and body composition, goals, PRs, badges, challenges, devices, gear mileage, workouts. |
Why this fork and not upstream?
Upstream 1.0.1 | This fork | |
| Always errors (calls a method that does not exist) | Aerobic/anaerobic TE, label, training load, HR time in zones |
Fitness age in | Always | Returned; failures explained per metric |
| Always errors | Works |
Activity time-series for charts | Not exposed |
|
FTP, lactate threshold, race predictions | Partly, spread across tools |
|
Original | No |
|
Password on disk | Stored in plain text | Not stored by default |
Logins to Garmin | One per tool call | One per server process |
OAuth scopes and profile photo URLs in responses | Included | Stripped |
| 0.3.3 | 0.3.19 (survives Garmin's 2026 Cloudflare changes) |
Dashboard
garmin-connect-mcp auth # once
garmin-connect-mcp dashboard # open the app; it syncs in the background as it loadsThe dashboard is a small local app: it opens straight away with what is already cached and syncs with Garmin in the background, with a progress indicator in the top bar, then refreshes itself when new data lands. The first run downloads every year since your oldest activity (a few hundred requests, a couple of minutes, deliberately paced) and shows a progress screen while it does. After that, only the last week and anything new is fetched, so a refresh takes seconds. If the sync fails (for example, the Garmin login expired) the app says so and keeps showing your saved data. Try it without an account: garmin-connect-mcp dashboard --demo.
Section | What you see |
Summary | One sentence with the period's totals and the change vs the period before; four key numbers with a mini trend; "How are you doing lately?" — the last 7 days of HRV, resting HR, sleep, morning energy and stress against your own normal range, labelled better / normal / worse; weekly hours by sport; and up to four findings from your data written as plain sentences ("After hard training days, your readiness goes down: 37 vs 72"). |
Training | Hours, distance and share of time per sport; month-by-month hours; fitness vs fatigue (weekly); time in each heart-rate zone (Garmin's, or your Strava heart-rate and power zones); a calendar of training days; your best marks of the period; with Strava, your best running times per distance and your gear's mileage. |
Recovery & sleep | One card per metric — HRV, resting HR, sleep hours and score, morning energy (Body Battery), stress, readiness, steps, breathing, pulse ox, relative effort — each with a one-line explanation, the period average, the change vs the previous period and a trend; sleep stages, bed and wake times and regularity; VO₂ max, weight and endurance score. |
Year by year | Running total since 1 January with the selected year highlighted against the others (hours, distance, elevation or activities), and a year table with the best year per column in bold. |
Activities | Every activity, searchable by name, place or gear, sortable by any column. |
Data | Every table the dashboard has — daily metrics, activities, time in zones, best efforts, per-km splits, segments, laps, best power per duration, VO₂ max, weight, endurance, gear — with a column picker, search, a data dictionary and CSV download. |
Filters. One bar drives every view: a period (last 30 or 90 days, last 12 months, this year, any single year, all history, or any custom range picked with two dates), the sports to include, and — with Strava connected — the source (Garmin, Strava or both). The comparison with the previous period, the findings and every chart follow it.
Tap anything. Every number, card, bar, zone, calendar day, record, finding and table row opens a side panel with its history (by day, week or month; the chosen period or all history) and the rows it was computed from, ready to export. An activity shows every field Garmin and Strava recorded — zones, power curve against your best of the period, splits, segments, laps, best efforts — and any of its values opens how that value has varied across your activities of that sport.
Strava
garmin-connect-mcp dashboard strava # or the "Connect Strava" card inside the appStrava adds what Garmin does not give the dashboard: your heart-rate and power zones as set on Strava and the time spent in them per activity, running best efforts (400 m … marathon) with PR ranks, per-kilometre splits, segment efforts, laps, relative effort, kudos and achievements, the device and the gear of each activity, and the total mileage of your bikes and shoes. Activities recorded somewhere else (a phone, Zwift, another watch) are added too.
To connect, create your own API application at strava.com/settings/api (any name and website; Authorization Callback Domain: localhost), then paste its Client ID and Client Secret into the app or the terminal and authorize. Pulso asks for read,activity:read_all,profile:read_all and nothing else; the tokens are stored 0600 in ~/.garmin-dashboard/strava.json and refreshed automatically. garmin-connect-mcp dashboard strava --disconnect forgets them.
Strava then syncs with Garmin every time the app opens. An activity Garmin uploaded to Strava is recognised by its Garmin ID (or, failing that, by its start time and sport) and enriched, never counted twice. Strava allows 100 requests per 15 minutes and 1,000 per day: activity lists cost one request per 200 activities, full detail two requests per activity, so a long history is completed newest first over several syncs; the Data tab says how many are still pending. Maps, coordinates, your name and photos are removed before anything is written to disk.
Correlations
Your history is turned into one row per day, then tested two ways:
A matrix of 18 daily metrics (training load, steps, HRV, resting HR, sleep score and stages, bedtime, stress, Body Battery, readiness, form…), Pearson r.
24 lagged hypotheses — the questions athletes actually ask: does a hard day lower tonight's HRV? Does going to bed late cost sleep score? Does a high acute:chronic ratio show up in readiness? Each reports Pearson r, Spearman ρ, p-value, number of days, and the average outcome on your top-quartile vs bottom-quartile days.
Findings are recomputed in the page for whatever period the filter selects. Only relationships with at least 30 days of data and p < 0.05 are shown as findings; tap one to see the scatter of every day behind it. Rest days count as zero training load, so load is compared against rest, not just easy days against hard ones. These are associations in your own data, not medical advice and not proof of cause.
Options
Command | |
| Open the app on |
| Offline: show the cache, no automatic sync. |
| Re-download all history (after editing old activities). |
| Start from a given year. |
| Sync, then write a standalone |
| Write the static page elsewhere (implies |
| Synthetic athlete, no account needed. Never touches your real cache. |
| Open in its own app window (Chrome, Edge or Brave) instead of a browser tab. |
| Connect your Strava account (guided). |
| macOS: installs Pulso.app (with its icon) in |
From a checkout, the same commands are make dashboard, make dashboard/static, make dashboard/demo, make dashboard/strava and make app. The demo includes a simulated Strava account.
The page is a single file with Chart.js inlined: it opens offline and loads nothing from the internet. It contains your health history, so it is written 0600 and lives outside the repository. Spanish and English, light and dark theme.
How it works
flowchart LR
W[Garmin watch / Edge] -->|sync| GC[(Garmin Connect)]
GC <-->|HTTPS, your OAuth tokens| S[garmin-connect-mcp<br/>on your computer]
S <-->|stdio, MCP| C[Claude Desktop<br/>or any MCP client]
S -.->|export_activity_file| F[~/GarminExports<br/>0600 files]
T[~/.garminconnect<br/>OAuth tokens, 0600] --- SThe server is a local process that Claude starts over stdio. It never opens a network port.
It signs in to Garmin Connect once with your account, keeps the OAuth tokens in
~/.garminconnect/, and refreshes them automatically.Each answer is compact JSON with
data, optionalanalysis(insights and per-metric errors) andmetadata.
Installation
Requirements: uv (it installs Python 3.12+ for you). Docker works too.
1. Sign in once
uvx --from git+https://github.com/scortes5/garmin-connect-mcp garmin-connect-mcp authAsks for your Garmin email and password (the password is hidden while you type) and for the MFA code if your account has one.
Saves OAuth tokens to
~/.garminconnect/and only your email to~/.garminconnect.env(mode0600).The password is used once and thrown away. Tokens last for months and refresh by themselves.
Want the server to be able to sign in again by itself if Garmin ever revokes the tokens? Add --save-password; it is then kept in ~/.garminconnect.env, readable only by you.
2. (Optional) choose where exports go
export GARMIN_EXPORT_DIR="$HOME/GarminExports" # defaultOption: Docker
git clone https://github.com/scortes5/garmin-connect-mcp && cd garmin-connect-mcp
docker build -t garmin-connect-mcp .
touch garmin-connect-mcp.env && mkdir -p ~/.garminconnect-docker
docker run -it --rm \
-v "$PWD/garmin-connect-mcp.env:/app/.env" \
-v "$HOME/.garminconnect-docker:/root/.garminconnect" \
garmin-connect-mcp authOption: from source
git clone https://github.com/scortes5/garmin-connect-mcp && cd garmin-connect-mcp
make deps
make authConnect it to Claude
Open Claude Desktop → Settings → Developer → Edit Config (~/Library/Application Support/Claude/claude_desktop_config.json on Mac, %APPDATA%\Claude\claude_desktop_config.json on Windows) and add:
{
"mcpServers": {
"garmin": {
"command": "uvx",
"args": [
"--from",
"git+https://github.com/scortes5/garmin-connect-mcp",
"garmin-connect-mcp"
]
}
}
}{
"mcpServers": {
"garmin": {
"command": "uv",
"args": ["run", "--directory", "/ABSOLUTE/PATH/TO/garmin-connect-mcp", "garmin-connect-mcp"]
}
}
}{
"mcpServers": {
"garmin": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-v", "/ABSOLUTE/PATH/TO/garmin-connect-mcp.env:/app/.env",
"-v", "/ABSOLUTE/PATH/TO/.garminconnect-docker:/root/.garminconnect",
"-v", "/ABSOLUTE/PATH/TO/GarminExports:/root/GarminExports",
"garmin-connect-mcp"
]
}
}
}Restart Claude Desktop and try:
How did I sleep this week, and how did it affect my HRV?
Compare my last three long rides: power, heart rate and decoupling.
Chart heart rate and power for my last ride.
What are my current FTP and lactate threshold?
Am I ready for intervals today?
Export the original FIT file of yesterday's run.Tools
24 tools in 9 groups. Every read-only tool is marked readOnlyHint so clients can run it without asking.
Raw performance data (new)
Tool | What it returns |
| Aligned columns — elapsed time, distance, HR, speed, power, cadence, elevation, temperature — downsampled to |
| Lactate threshold, cycling FTP, race predictions (5K → marathon), weekly running tolerance. Each part is fetched on its own; failures go to |
| Saves |
Activities
Tool | What it returns |
| Activities by ID, date, date range or most recent, filtered by type, with cursor pagination. |
| One activity with laps/splits (accurate km/mile splits from time-series), weather, HR zones, gear and strength sets. |
Analysis
Tool | What it returns |
| 2–5 activities side by side. |
| Past activities similar to a reference one. |
Training
Tool | What it returns |
| Volume, activity mix and weekly trend for |
| VO2 max, HRV, fitness age (single day) or hill and endurance score (range). |
| Aerobic/anaerobic training effect, label, training load and HR time in zones for an activity; or a progress summary between two dates. |
Health and wellness
Tool | What it returns |
| Daily stats with training readiness, training status and Body Battery. |
| Sleep stages, scores and overnight HRV. |
| Daily heart rate and resting HR. |
| Steps, stress, respiration, SpO2, floors, intensity minutes. |
Profile, goals and challenges
Tool | What it returns |
| Profile, stats and PRs. |
| Goals, personal records and race predictions. |
| Badges and challenges by status. |
Devices and gear
Tool | What it returns |
| Devices, primary training device, settings, solar data, alarms. |
| Shoes, bikes and other gear with usage stats. |
Body and data entry
Tool | What it returns |
| Weight and body composition for a date or range. |
| Add or delete weigh-ins. Writes to your account. |
| Log body composition, blood pressure or hydration. Writes to your account. |
Other
Tool | What it returns |
| List, get, download or upload structured workouts. |
| Menstrual cycle and pregnancy data. |
Resources and prompts
Resources give the model context without a tool call:
Resource | Content |
| Name, unit system, summary and today's stats. |
| Training readiness, morning readiness, Body Battery, HRV and training status for today. |
| Today's steps, sleep, stress and heart rate. |
Prompts are ready-made requests you can pick in Claude:
Prompt | Does |
| Training analysis for a period. |
| Sleep quality with recommendations. |
| Train hard, train easy or rest. |
| Everything about one activity, compared with similar ones. |
| Trends across your latest runs. |
| Steps, sleep, stress, HR, HRV and Body Battery together. |
Building your own charts
The new tools are shaped for charts:
get_activity_streamsreturns columns, not rows:streams.heart_rate_bpm[i]lines up withstreams.elapsed_s[i], so they map straight onto a line chart. Columns the device did not record are left out.get_fitness_thresholdsgives the reference lines (FTP, LTHR) to draw over those charts.export_activity_filewithfitgives you the full-resolution original for your own pipeline (for example parsing with the FIT SDK into PostgreSQL).
Garmin's official personal API (announced October 2026) also returns activity JSON and FIT files for your own account, but it is pull-only, and third-party reports say files delivered through Garmin's APIs have undocumented fields such as VO2 max and recovery time removed. The original file you export here is the one Garmin Connect itself serves to you.
What this fork changes
Fixed
get_training_effectcalled a Garmin method that does not exist; it now reads the values from the activity.Fitness age always came back
null(wrong method name).get_performance_metricsnow explains each metric it could not fetch inanalysis.errors.manage_workoutswithaction="get"called a method that does not exist.garmin://training/readinessreturned generic daily stats; it now returns readiness, Body Battery, HRV and training status.Accurate splits now find the distance and time columns through Garmin's metric descriptors instead of fixed positions.
Added
get_activity_streams,get_fitness_thresholds,export_activity_file.auth --save-password.A secret scan (gitleaks) on every push.
Changed
Password not stored by default; hidden prompt; token-only operation.
One login per server process, dropped and re-created after an auth error.
userRolesand profile image URLs stripped from all responses.garminconnect≥ 0.3.19.
Removed
get_activity_social: the Garmin library has no endpoint behind it, so it always failed.
Full detail in the Changelog.
Privacy and security
Runs only on your computer. The server talks to Garmin Connect and to the MCP client that started it — nothing else. No telemetry, no server of its own, no network port.
Your password is not kept.
authuses it once to get OAuth tokens. Only if you pass--save-passwordis it stored, in a0600file.Files only you can read.
File
What
Permissions
~/.garminconnect/OAuth tokens
folder
0700, files0600~/.garminconnect_base64Token copy for Docker/CI
0600~/.garminconnect.envEmail (and password only with
--save-password)0600$GARMIN_EXPORT_DIR/*.fitExported activities
0600No location unless you ask. Streams leave out latitude and longitude by default: the start and end of most activities is your home.
Less account detail in answers. OAuth scopes and profile photo URLs are removed from every response before the model sees it.
Writes are labelled. Tools that change your Garmin account (
manage_weight_data,log_health_data,manage_workoutsupload) are marked as not read-only, so clients ask before running them.Dashboard data stays local. Synced data lives in
~/.garmin-dashboard/(folders0700, files0600; override withGARMIN_DASHBOARD_DIR). Owner name, account roles and GPS coordinates are dropped from activities before they are cached. The app listens on127.0.0.1only and rejects requests from other hosts or origins.Repository hygiene.
.gitignoreexcludes tokens,.envfiles,.fit/.gpx/.tcx, databases and exports; CI runs a secret scan on every push. Tests use made-up data only.
Found a problem? See SECURITY.md.
Development
make deps # install dependencies (uv)
make test # run the test suite
make lint # ruff + pyright
make can-release # everything CI runs
make auth # sign in from a checkout
make run # start the server on stdioSee docs/ARCHITECTURE.md for how the pieces fit together and the full data dictionary.
Tests are behaviour tests: they drive the real MCP server through an in-memory client and fake Garmin only at the library boundary.
src/garmin_connect_mcp/
server.py tools, resources and prompts registration
middleware.py one shared Garmin session per process
client.py login, token handling, error mapping
auth.py config, token-only auth, private file writes
response_builder.py compact JSON responses, field redaction
tools/ one module per area (activities, training, performance_data…)
dashboard/ sync → cache → dataset → correlations → self-contained HTML
tests/ behaviour and unit testsKnown limitations
Garmin Connect has no public API for individuals; this uses the same endpoints as the Garmin Connect website through the
garminconnectlibrary. Garmin can change them at any time.Metrics depend on your device: a watch without a power meter returns no power stream, and some devices have no running tolerance or hill score. Missing parts are reported in
analysis.errors.Very frequent calls can trigger Garmin rate limits (HTTP 429). Wait a few minutes and try again.
Social data (likes, comments) is not available.
Contributing
Bug reports and pull requests are welcome. Run make can-release before opening a PR, and never paste real tokens, exports or personal activity data into issues, fixtures or tests. Fixes that also apply upstream are worth sending to eddmann/garmin-connect-mcp too.
This project is not affiliated with, endorsed by, or sponsored by Garmin Ltd. or its affiliates. Garmin and Garmin Connect are trademarks of Garmin Ltd.
Made by Sergio Cortés · based on garmin-connect-mcp by Edd Mann · MIT License
This server cannot be deployed
Maintenance
Related MCP Connectors
Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.
Garmin data in Claude: 135 tools — activities, sleep, HRV, training, workouts. Free, open source.
Pace is a remote MCP server that exposes wearable and fitness data to Claude via the Model Context Protocol. It connects to Garmin, Oura, Whoop, Polar, Fitbit and 20+ devices and provides 15 tools for querying sleep, activity, recovery, and training data. Hosted on Google Cloud Run, OAuth 2.1 authentication, Streamable HTTP transport. Instructions: First you need to create an account at: https://pacetraining.co and connect your wearables. After that you can connect the remote Server via Custom Connector in Claude and OAuth 2.1 Flow startet.
Ask your AI about your fitness: activities and data from Garmin, COROS, Strava, GPX and more
Related MCP Servers
- AlicenseBqualityAmaintenanceConnects to Garmin Connect and exposes your fitness and health data (activities, sleep, heart rate, steps, body composition) to Claude and other MCP-compatible clients.1481,398MIT
- AlicenseAqualityDmaintenanceEnables Claude Desktop to access and analyze Garmin wearable health data including sleep, HRV, Body Battery, and activity metrics. Users can query their health trends, track recovery, and generate interactive HTML dashboards using natural language.96MIT
- AlicenseAqualityDmaintenanceA read-only MCP server that gives Claude Desktop access to your Garmin Connect data — daily health metrics, sleep, activities, training status, and body composition.6MIT
- AlicenseAqualityAmaintenanceProvides Claude Code and Claude Desktop with safe, read-only access to your local Garmin training data, readiness decisions, run details, and trends so you can get coaching advice in natural language.131MIT