durely insights
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| GARMIN_MCP_DATA_DIR | No | Where your synced data is kept | ~/.garmin-insights-mcp |
| GARMIN_MCP_TIMEZONE | No | Your time zone (IANA name, e.g. Europe/Brussels) | system time zone |
| GARMIN_MCP_AUTO_SYNC | No | Refresh automatically when the data is over an hour old | true |
| GARMIN_MCP_LOG_LEVEL | No | debug, info, warn or error (logs go to stderr) | info |
| GARMIN_API_KEY_EXPIRES | No | Your key's expiry date (yyyy-MM-dd), for reminders | |
| GARMIN_MCP_DETAIL_DAYS | No | Days of intraday detail (HR, overnight HRV, SpO2) to keep synced | 150 |
| GARMIN_PERSONAL_API_KEY | No | The key itself, instead of the key file | |
| GARMIN_PERSONAL_API_KEY_FILE | No | Where the key file is | ~/.config/garmin/connect-personal-api-key |
| GARMIN_MCP_REQUESTS_PER_SECOND | No | Request throttle; Garmin publishes no limits | 4 |
Instructions
Guidance the server publishes about itself, which clients place ahead of the tool catalog so the model reads it before choosing anything.
This server publishes no instructions, or was last inspected before Glama recorded them.
Capabilities
Features and capabilities supported by this server
Protocol revision2025-11-25
| Capability | Details |
|---|---|
| tools | {
"listChanged": true
} |
| prompts | {
"listChanged": true
} |
| resources | {
"listChanged": true
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| garmin_statusA | Check that the Garmin Personal API connection works and report its configuration. Reports: where the API key comes from, whether a token could be obtained and when it expires, the API key's expiry (if GARMIN_API_KEY_EXPIRES is set), the time zone used for calendar dates, and the server version. Use this first when another garmin_* tool fails with an authentication error, or when the user asks whether their Garmin connection is set up. |
| garmin_get_profileA | Get the user's Garmin profile settings, heart rate zones per sport, and fitness age. Returns: units and locale, time zone, preferred training days, HR zone floors per sport (with the max HR / LTHR / resting HR used to compute them), and the latest fitness age. Use this before interpreting heart rate data (to know the user's zones), or when the user asks about their zones, max HR, lactate threshold or fitness age. |
| garmin_list_activitiesA | Search the user's Garmin activities (all history, from the local cache), newest first by default. Returns one page of compact summaries plus the total number of matches: id, date, type, name, duration, distance, pace/speed, HR, power, elevation, training effect, training load, TSS/IF and VO2max where available, plus time in HR/power zones (JSON mode). Examples:
The cache refreshes automatically when it's more than an hour old. Use garmin_get_activity for one activity's full details (splits, FTP, workout). |
| garmin_get_activityA | Get full details for one Garmin activity by ID. Returns: name, description, type, start time and time zone, device, summary metrics (duration, distance, speeds, HR min/avg/max, power avg/max/NP/20-min, FTP, cadence, stride, calories, training effect + message, training load, TSS, IF, temperature, intensity minutes), split summaries (e.g. run/walk/stand intervals), the structured workout if one was followed, and multisport parent/child IDs. Get IDs from garmin_list_activities. Example: "Tell me about yesterday's run" -> list activities for that date, then call this with its id. |
| garmin_get_activity_lapsA | Get the laps (and sessions, swim lengths and Garmin's physiological metrics) of one activity, from its original FIT file. Returns per lap: start offset, duration (elapsed and timer), distance, pace/speed, avg/max HR, avg/max/normalized power, cadence, ascent/descent, intensity (active/rest/warmup/cooldown) and lap trigger; for swims, stroke and lengths. Also: device, multisport sessions, and FIT-only metrics when the device recorded them (VO2max, recovery time, lactate threshold HR/power). Use it for interval sessions, splits and pacing. Downloads the FIT file on first use (one request), then it's cached. For a multisport leg ID, returns only that leg's laps. |
| garmin_get_activity_streamsA | Get second-by-second data from one activity's FIT file, downsampled to fit in context. Returns per field min/avg/max over the window, plus columnar series: t (seconds from the start of the activity, or of the leg for a multisport leg) and one array per field. Units: heart_rate bpm, power W, speed m/s, cadence steps/min (running) or rpm (cycling) or strokes/min, altitude m, distance m (cumulative), temperature °C, respiration_rate breaths/min, performance_condition (Garmin's -20..+20 score), vertical_oscillation mm, stance_time ms. Cadence averages leave out zeros. Defaults to heart_rate, power, speed, cadence, altitude (whichever the activity has) at 10 s resolution, at most 500 points; the resolution coarsens automatically for long activities. Zoom in with start_s/end_s (e.g. one interval from garmin_get_activity_laps' start offsets) and a smaller resolution_s. "position" adds GPS latitude/longitude and reveals where the user was: only request it when the user asks for location or route analysis. Developer fields (e.g. running power from a Connect IQ app) can be requested by the name listed in available_fields, like "dev_RP_Power". |
| garmin_download_activity_fitA | Save the original FIT file of an activity to the server's exports folder and return its path, e.g. to import it into another tool (Intervals.icu, Golden Cheetah, a spreadsheet converter). The file is exactly what the device recorded. Saved as /exports/<activity_id>.fit; an existing export is kept, not overwritten. For a multisport leg, exports the whole multisport file. |
| garmin_get_daily_healthA | Get day-by-day wellness and recovery data, from the local cache (all history). Per day: steps (+ goal), floors, resting/min/max heart rate, stress (average, max, % of the day at rest/low/medium/high), Body Battery (min, max, charged, drained), intensity minutes (moderate, vigorous), calories (total, active), respiration, hydration, plus that night's sleep (duration, score) and HRV (last-night average, status). group_by="week" (Monday-based) or "month" aggregates: averages per day, minimums/maximums for min_hr/max_hr/stress_max, and totals plus per-day averages for steps and intensity minutes. Defaults to the last 14 days. Daily rows are limited to 92 days per call; use group_by="week" or "month" for longer periods (e.g. a year by week). Today's values are partial. Examples: "How's my recovery this week?" → defaults. "Resting HR trend this year" → start_date="2026-01-01", group_by="week". |
| garmin_get_sleepA | Get nightly sleep from the local cache: bed and wake time, total sleep, deep/light/REM/awake time, naps, sleep score with quality and Garmin's feedback, awake count, average respiration and sleep stress. JSON mode adds the sleep score's components (duration, stress, deep/light/REM %, restlessness, awake count) with Garmin's rating each. A night belongs to the date you woke up. Defaults to the last 14 nights, at most 92 per call. |
| garmin_get_hrvA | Get nightly HRV (heart rate variability, in ms) from the local cache: last-night average, highest 5-minute value, 7-day average, the personal baseline range (balanced low/high) and Garmin's status (BALANCED, UNBALANCED, LOW, POOR). With readings_date, also returns that night's 5-minute HRV readings (fetched from Garmin if older than the synced detail window). Defaults to the last 28 nights, at most 366 per call. HRV needs a compatible watch worn overnight; history starts when that began. |
| garmin_get_intradayA | Get one day's health data through the day, averaged into intervals: heart rate (bpm), Body Battery (0-100), overnight HRV readings (ms) and SpO2 (pulse ox, %). Returns per metric: min/avg/max, the day's summary values (e.g. resting HR, Body Battery charged/drained, SpO2 averages), and a columnar series (local times "HH:MM" + values). Synced for the last 150 days; older days are fetched from Garmin on demand. Garmin itself keeps intraday heart rate and HRV readings for only about 4–5 months (Body Battery longer), so older days may have just the day summary. Defaults to today, all four metrics, 15-minute intervals. HRV and SpO2 need a compatible watch (SpO2 also needs pulse ox enabled). |
| garmin_get_body_compositionA | Get weigh-ins from the local cache: weight (kg), BMI, body fat %, body water %, muscle and bone mass (kg), visceral fat, and where each came from (scale, manual, linked app). Includes the change over the period and the weight goal if one is set. Only days with a weigh-in appear. Defaults to the last 365 days. |
| garmin_get_nutritionA | Get food logged in Garmin Connect (or a linked app such as MyFitnessPal) per day: calories, carbs, protein and fat against the day's goals, and meals; plus hydration (ml) from the daily summary. Food logs are fetched from Garmin on demand and cached. Defaults to the last 7 days, at most 31 per call. |
| garmin_get_womens_healthA | Get menstrual cycle tracking from Garmin Connect for a date: cycle day, current phase and days until the next, period and cycle length, predicted next cycle, fertile window and ovulation date, plus that day's logged symptoms and notes (day view). Fetched live from Garmin. Returns a clear "not tracked" message when cycle tracking isn't set up. Defaults to today. |
| garmin_analyze_activityA | Compute training metrics for one activity from its second-by-second FIT data:
FTP comes from ftp_w, else from the activity's own record (Garmin cycling FTP). Works for multisport legs too. |
| garmin_training_summaryA | Summarize training per week or month: sessions, hours, distance, elevation and training load, per sport; intensity distribution (share of time in low = HR zones 1–2, moderate = zone 3, high = zones 4–5, with a rough pattern: polarized, pyramidal, threshold-heavy); and the load trend at the end of each period: fitness (CTL, 42-day), fatigue (ATL, 7-day), form (TSB = CTL − ATL) and the acute:chronic ratio (ACWR; above ~1.5 is a commonly cited risk zone). Load is Garmin's training load per activity; activities without it (older devices, some third-party uploads) get an estimate from average heart rate (Banister TRIMP) scaled to Garmin's load using the user's own activities. The response says how much is estimated. Multisport legs count toward their sport; walking is included as its own sport. Defaults to the last 12 weeks by week. Filter with sport (e.g. running, cycling, or a type like virtual_ride). |
| garmin_recovery_trendsA | Relate training load to recovery markers, day by day: resting HR, overnight HRV, sleep score and duration, Body Battery max and stress, each against the user's own rolling 28-day baseline. Returns: a status (last 7 days vs the previous 28: HRV, resting HR, sleep, load; plus current fitness/fatigue/form), days flagged for low HRV, elevated resting HR or poor sleep, weekly averages, and correlations such as "previous day's load vs next morning's HRV" with their strength. Correlation is not causation, and short periods give noisy results. Defaults to the last 8 weeks; at most 180 days. |
| garmin_compare_activitiesA | Compare 2–6 activities side by side: date, type, duration, distance, pace/speed, heart rate, power (avg/NP), elevation, training effect and load, cadence, and efficiency factor (speed or NP per heartbeat; higher means more output for the same heart rate, a classic way to track aerobic progress on similar sessions). With deep=true, also analyzes each one's FIT data (downloads files if needed): aerobic decoupling, time in low/moderate/high HR zones and best efforts. Example: "Am I getting fitter on my Tuesday interval run?" → list those runs, then compare them. |
| garmin_queryA | Run one read-only SQLite query against the local Garmin cache, for analyses the other tools don't cover (custom aggregations, correlations, records, comparisons across years). Views (one row per item; use these first):
Rules: one SELECT or WITH statement; at most max_rows rows returned (default 200); 10-second timeout. Prefer aggregating in SQL over returning many rows. Example: SELECT strftime('%Y', start_date) AS year, sport, ROUND(SUM(distance_m)/1000) AS km FROM activities WHERE is_multisport_parent = 0 GROUP BY 1, 2 ORDER BY 1, 3 DESC |
| garmin_syncA | Start downloading Garmin data into the local cache. Runs in the background and returns immediately; follow progress with garmin_sync_status. You rarely need this: other tools sync automatically on first use and when the cache is over an hour old. Use it to:
Domains (default: all except fit_files): activities, daily_summaries, sleep, hrv, weight, body_battery, hrv_readings, heart_rate, spo2. "fit_files" downloads the original FIT file of every activity (one request each, ~2 activities/s). That's optional: FIT files are otherwise fetched on demand by garmin_get_activity_laps and garmin_get_activity_streams. |
| garmin_sync_statusA | Show what's in the local Garmin cache and the progress of the current or last sync. Returns: the running/last sync (progress, errors), and per data domain the date range covered, number of days, whether all history is in, and the last successful sync. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
| weekly_review | Review the past week of training and recovery against the recent trend |
| activity_deep_dive | Analyze one activity in depth: pacing, intervals, heart rate, power and efficiency |
| recovery_check | Should I train hard today? A readiness check from sleep, HRV, resting HR, Body Battery and recent load |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| garmin-schema | Views and tables available to garmin_query |
TDQS
Scored across 21 tools
Most tools target clearly distinct Garmin resources or analysis layers: daily health vs. sleep vs. HRV vs. intraday, and activity summary vs. laps vs. streams vs. computed analysis. There is some overlap because daily health includes sleep/HRV summaries, and several analysis tools operate on activities, but descriptions make the intended boundaries mostly clear.
All tools use a consistent garmin_ snake_case prefix, which makes the set predictable. Most names follow verb_noun patterns (get_*, list_*, analyze_*, compare_*), though a few are noun phrases or slightly irregular (garmin_status, garmin_training_summary, garmin_recovery_trends, garmin_download_activity_fit).
At 21 tools, the surface is on the heavy side for an MCP server and includes several closely related health and activity-analysis tools that could be consolidated. The breadth of Garmin domains justifies many of them, but the count is borderline rather than clearly well-scoped.
The set covers the Garmin insights domain thoroughly: activity listing/detail/laps/streams/FIT export, daily wellness, sleep, HRV, intraday health, body composition, nutrition, women's health, profile zones, training analysis, recovery trends, sync management, and a SQL escape hatch. No obvious core lifecycle gap exists for a read-only analytics server.