garmin-raw-mcp
Provides raw access to Garmin Connect data, including activity summaries, lap details (heart rate, cadence, power, etc.), second-by-second streams, comments with lactate parsing, wellness data (sleep, HRV, stress, Body Battery), and personal records.
Click on "Install 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-raw-mcpget activity streams for yesterday's run"
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.
TN Garmin MCP
English | Русский
An MCP server for training analysis on top of Garmin Connect: not "another VO2max dashboard", but enriched, per-profile access to your own data right inside a Claude chat — HR/pace distribution shapes, decoupling, pace-bucketed biomechanics, lactate marks anchored to the exact second they were taken, cross-period aggregates. Methodologically rejects device-side estimates (VO2max / training-effect / out-of-the-box thresholds) — only measurable facts and derivations you can trace, no hidden models.
Two layers, both served over MCP:
garmin-tn(profile-aware, recommended) — enriched analysis plus your own lactate marks and notes. One connector = one Garmin account/profile. Multiple people/accounts → multiple connectors; data never crosses between them.garmin-raw(raw, optional) — unprocessed HR/cadence/power/stride/ elevation per lap and per second, comment-based lactate. Single account per server, no profiles. Useful if you want raw data directly or a JSON export for external analysis.
If unsure what you need, install garmin-tn — it's the primary path.
Requirements
Python 3.10+ and uv. Claude Desktop for MCP access
(connectors run over local stdio — no server or hosting needed).
Related MCP server: Garmin MCP Server
Fresh install
git clone https://github.com/asilenin/Garmin-TN-MCP.git
cd Garmin-TN-MCP
uv sync1. Authenticate with Garmin (once per account)
uv run garmin-raw-authEmail, password, MFA code. Tokens land in ~/.garminconnect — this is the
default account (see "Multiple profiles" below if you have more than one
Garmin account, e.g. yourself + a training partner).
2. Prime the local cache
The profile layer keeps its own local database
(~/.garmin-tn/profiles/<slug>/cache.db) — MCP tools read from it and never
touch the network (see "How this works" below). Fill it once before first use:
uv run python garmin_raw/sync.py <slug> # activity catalog (all dates)
uv run python garmin_raw/sync.py <slug> enrich 50 # enrichment + streams, newest first
uv run python garmin_raw/sync.py <slug> fetch-aux # laps + comments (lactate)<slug> is the connection key <provider>-<user> (e.g. garmin-anton,
garmin-mila; letters/digits/-). With years
of history, run enrich in batches (enrich 100, then again) — it skips
what's already enriched. On a large archive, first enrichment can take over
an hour — expected, Garmin has no bulk endpoint for per-second streams.
Check what's accumulated:
uv run python garmin_raw/sync.py <slug> status3. Connect to Claude Desktop
uv run tn-install <provider> <user>A connection is (provider, user) — e.g. garmin anton. Appends a
tn-<provider>-<user> connector (e.g. tn-garmin-anton) to
claude_desktop_config.json without touching anything else (backs up before
writing), with env TN_USER/TN_PROVIDER. Repo path is auto-detected; pass it
explicitly if needed: uv run tn-install <provider> <user> /full/path/to/repo.
Restart Claude Desktop (Cmd+Q on macOS — not just closing the window) — 15
garmin_* tools will appear.
Multiple profiles (different Garmin accounts)
Example: your own account plus a training partner's.
# for the account authenticated via garmin-raw-auth above — reuse its tokens:
uv run tn-install garmin anton --tokenstore ~/.garminconnect
# for a second account — authenticate separately into its own token folder
# (connection slug = <provider>-<user>, e.g. garmin-mila):
mkdir -p ~/.garmin-tn/profiles/garmin-mila/tokens
GARMIN_TOKENSTORE=~/.garmin-tn/profiles/garmin-mila/tokens uv run garmin-raw-auth
uv run python garmin_raw/sync.py garmin-mila
uv run python garmin_raw/sync.py garmin-mila enrich 50
uv run python garmin_raw/sync.py garmin-mila fetch-aux
uv run tn-install garmin mila--tokenstore is needed only if the profile has no token folder of its
own — it's an explicit flag, not a hidden default: install warns at setup time
if no tokens were found anywhere. A profile with its own tokens
(~/.garmin-tn/profiles/<slug>/tokens/) keeps using them and never mixes up
with another account.
With several profiles installed, Claude sees all of them at once —
garmin_compact, garmin_add_lactate, etc. operate in the context of
whichever connector you're using; profiles never cross (the profile is
deliberately absent from tool names — it's determined by which connector you
use, not by anything you type in chat).
Updating the code
cd Garmin-TN-MCP
git pull
uv syncNo need to touch Claude's config — the connector only stores the repo path, new code is picked up on Claude Desktop's next launch (restart it). If the local database schema changed, migration runs automatically on first access, additively (existing data is preserved).
Syncing — keeping the cache fresh
MCP tools never touch the network — they only read the local cache (fast, predictable, no network failures mid-conversation). New activities need to be pulled in explicitly:
uv run python garmin_raw/sync.py <slug> # new activities into the catalog
uv run python garmin_raw/sync.py <slug> enrich 20 # enrich the newest 20
uv run python garmin_raw/sync.py <slug> fetch-aux # laps/comments for what's missingRun this before discussing recent activities (or on a schedule). sync.py <slug> recompute recomputes all metrics from already-downloaded raw data (run
after a code update if the computation logic changed; no network needed).
Triggering a sync from inside the Claude chat itself ("download today's run") is planned — see the backlog. For now, syncing is a separate terminal step.
Uninstalling
uv run tn-uninstall <provider> <user> # remove one connection connector
uv run garmin-raw-uninstall # remove the raw connector (if installed)Both only edit Claude's config (with a backup) — code and data are untouched. Restart Claude Desktop afterward.
Full cleanup:
rm -rf ~/.garmin-tn # local databases for all profiles
rm -rf ~/.garminconnect # default account's tokens
cd .. && rm -rf Garmin-TN-MCP # the repository itselfTools (garmin-tn, profile-aware)
Tool | Returns |
| what's in the cache: date range, activity count, last sync time |
| activity catalog by filter (no histograms) |
| HR/pace shapes, clusters, decoupling, biomechanics, lactate marks |
| the entire enrichment |
| cross-period aggregates (form over time) |
| record a lactate reading anchored to a second (see below) |
| attach a free-text note to an activity |
| delete a mark/note |
Lactate — anchored to the exact second
Three sources, of differing value:
Garmin comment (
LA:6.1, optionally with context:LA:6.6 @rep12) — read automatically, but it's a bare number: no way to know the HR/pace it was taken at.ConnectIQ TN Splits View watch app (numeric field in the stream) — also read automatically, has a lap anchor, but needs a third-party watch app.
garmin_add_lactate— the recommended way. Tell the chat when the reading was taken (elapsed time or lap number) — the tool resolves it to the exact second in the stream and returns the HR/pace at that moment. The difference matters: "5.1 mmol at HR 129 deep in recovery" and "5.1 mmol at HR 175 mid-effort" are different physiology behind the same number.
Three ways to specify the second (exactly one):
garmin_add_lactate(id, 5.5, at_elapsed_s=2190) # 36:30 from start (as written in comments)
garmin_add_lactate(id, 5.5, at_ms=1782884498000) # absolute timestamp (exact path)
garmin_add_lactate(id, 5.5, user_ref="lap14") # end of Garmin lap 14If the activity isn't cached yet, sync first. If the per-second stream
hasn't been downloaded yet, the mark is saved and resolved automatically on
the next enrich.
How this works (short version)
MCP tools only read a local SQLite database
(~/.garmin-tn/profiles/<slug>/cache.db) — this gives fast, predictable
responses and keeps profiles isolated from each other: each connector is
hard-wired to its own file and its own tokens via environment variables in
Claude's config (not anything typed in chat). Filling the cache is a separate,
explicit operation (sync.py) — only it touches the network.
Notes
Garmin PRs are an auto-detected fastest split, not a race-protocol time; they can beat official results. For fitness markers, prefer protocol races.
PII (owner name/ID) is stripped from the local cache and output, case-insensitively.
If tools return empty/errors on a previously-synced profile, it's almost always expired Garmin tokens:
uv run garmin-raw-auth(withGARMIN_TOKENSTORE=<profile path>for a non-default account), thensync.
Raw layer (garmin-raw, optional)
A separate single-account MCP with no profiles and no enrichment — raw data only. Useful for JSON export to external analysis, or if the profile layer isn't needed.
uv run garmin-raw-install # garmin-raw connector in Claude
uv run garmin-raw-export --start 2026-06-01 --end 2026-06-21 # or a JSON exportTool | Returns |
| raw summaries for a period |
| HR/cadence/power/stride/elevation per lap |
| per-second streams |
| comment + parsed |
| numeric lactate from TN Splits View, per lap |
| sleep, HRV, RHR, stress, Body Battery |
| PRs by distance |
Garmin disclaimer
This project talks to Garmin Connect through an unofficial route (the
community library python-garminconnect,
which logs in with your own credentials). It is not affiliated with, endorsed
by, or supported by Garmin. Use may be subject to Garmin's Terms of Service;
you use it at your own risk. No warranties are made (see
LICENSE).
Authorship & AI generation
This project was designed and written by Claude (Anthropic's AI assistant) during an extended pair-programming session, under the direction, review and testing of Anton Silenin. The methodology, architecture, debugging and final verification against real Garmin data were done collaboratively in conversation: the human author initiated the work, made the design decisions, validated every step on live data, and is the copyright holder.
AI-generated output carries no separate human authorship under copyright law, so
it is released under the human author's name (MIT, see LICENSE). This
note is here for transparency, not as a license requirement. As with any
AI-assisted code, review it before relying on it.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/asilenin/Garmin-TN-MCP'
If you have feedback or need assistance with the MCP directory API, please join our Discord server