garmin-connect-api
Server Configuration
Describes the environment variables required to run the server.
| Name | Required | Description | Default |
|---|---|---|---|
| GARMINTOKENS | No | Where tokens are stored. Defaults to ~/.garmin-api/default. | ~/.garmin-api/default |
| GARMIN_API_KEY | No | Required to bind the HTTP service beyond localhost. | |
| GARMIN_API_HOSTS | No | Extra host names the HTTP service answers to, comma-separated. |
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
} |
| logging | {} |
| prompts | {
"listChanged": false
} |
| resources | {
"subscribe": false,
"listChanged": false
} |
Tools
Functions exposed to the LLM to take actions
| Name | Description |
|---|---|
| garmin_statusA | Check whether this server holds a Garmin login. Call this first if anything fails. It reports whether tokens exist and how old they are, without calling Garmin, so tokens Garmin has since revoked still show as authenticated; any other call reveals that. |
| find_exerciseA | Search Garmin's strength exercise catalogue by name, best match first; each result has the display name, category and exercise (the variant). Use it before create_strength_workout, log_strength_session or edit_activity_sets whenever the Garmin pair is not known: those reject any other name, and accept a result's category and exercise as they are. Matching is by word starts ("lat pull" finds "Lat Pull-down"), with plurals and common gym names (rdl, ohp, skull crusher) understood. To turn one free-text name into exactly one exercise or nothing, use match_exercise. Answered from a bundled copy of the catalogue: no Garmin request, no login needed. |
| recent_strength_sessionsA | List the most recent completed strength sessions, newest first, each with its exercises, reps and weights and its total volume (reps times weight over the working sets). One call instead of list_activities plus get_activity_sets per session. It takes no dates: for a period, use list_activities with activity_type strength_training and start_date. Its sets carry no set_number, so read a session with get_activity_sets before correcting it with edit_activity_sets. One Garmin request per session plus one, and one more the first time in a process (the activity types); a session whose sets cannot be read carries sets_error, and a rate limit stops the call. |
| week_summaryA | Summarise the seven days ending on end_day (default today, in the account's timezone): each day's steps, resting heart rate, sleep hours and morning readiness, plus the activities started in that window (up to 50). For one day in full use get_day_summary; for one metric over longer ranges, get_trend, which costs far fewer requests per day. This makes three Garmin requests per day plus one for the activities, over 20 in all, so do not call it repeatedly. A night's sleep belongs to the day it ended on. |
| list_activitiesA | List activities, newest first. Completed activities, not planned workouts. Filter by type and by date range; end_date needs start_date. For strength sessions pass activity_type=strength_training, then fetch the sets of one to see the exercises, reps and weights. |
| get_activityA | Return one activity by id: type, start time (UTC and local wall clock), duration, distance, heart rate and calories, plus Garmin's full record under raw. Ids come from list_activities, recent_strength_sessions or week_summary. It has no per-set or per-lap detail: for a strength session's exercises, reps and weights use get_activity_sets; for a run, ride or swim's laps and pacing, get_activity_laps. |
| delete_activityA | Permanently delete one activity from Garmin Connect. There is no undo. Use it for an activity that should not exist, such as a session logged twice. To fix a strength session's sets use edit_activity_sets, and to rename it, update_activity; both keep the activity. A copy already shared to Strava or another connected app stays there. |
| update_activityA | Rename an activity, replace its description, or both; what is not given is left as it is. For a strength session's exercises, reps or weights use edit_activity_sets; to remove the activity, delete_activity. The new text replaces the old. Name and description are separate Garmin requests, so if the second fails the first still stands. |
| get_activity_setsA | Return a strength activity's sets: exercise category and name, reps, weight in kg and duration, with the total volume. Each working set has a set_number (1, 2, 3...), which edit_activity_sets takes to correct or delete sets; rests have none and are left out unless include_rests. Only strength activities have sets: for runs, rides and swims use get_activity_laps. For the last few sessions at once, recent_strength_sessions saves a call per session. |
| edit_activity_setsA | Correct a strength activity's sets: exercise, reps or weight, or delete sets. Address sets by the set_number get_activity_sets shows; within one call, every number means the set as numbered before it. Deleting renumbers the sets after it, so repeating a delete removes a different set: use the numbers this returns for any further edit. Name exercises with Garmin's category and exercise_name; find_exercise looks them up. To rename the activity or change its description, use update_activity. Returns the sets as Garmin now holds them. |
| get_activity_lapsA | Return the laps of a run or ride, or the pace per 100 m or yd of a pool swim, with a summary: average pace or speed, first half against second half, and the fastest and slowest lap or 100. Answers "did my pace hold up?". Strength sessions have sets, not laps: use get_activity_sets. Two Garmin requests. |
| get_day_summaryA | Return one calendar day's numbers in a single answer: steps, calories, heart rate, stress, body battery, last night's sleep, HRV, the morning readiness score and the day's last weigh-in. It does not list the day's activities: use list_activities with start_date and end_date both set to the day. For one metric, its own tool (get_sleep, get_hrv, get_stress, get_steps, get_training_readiness) gives more detail in one Garmin request instead of five; for seven days use week_summary, for a range get_trend. A part whose request fails is null and named under unavailable; if every part fails, or Garmin rate limits, the call returns an error instead. A night's sleep belongs to the day it ended on. |
| get_sleepA | Return one night's sleep: start and end, total, deep, light, REM and awake time, sleep score and average respiration. A night belongs to the day it ended on: last night is today's date. Null when no sleep was recorded. The same summary is inside get_day_summary, which costs five Garmin requests to this one's one; for sleep hours or score over many nights use get_trend with metric sleep or sleep_score. |
| get_hrvA | Return one night's heart rate variability in milliseconds: the night's average and five-minute high, the weekly average, Garmin's status (such as BALANCED, UNBALANCED or LOW) and the baseline band. A night belongs to the day it ended on: last night is today's date. With no HRV for that night the reply is null, or its fields are. The nightly average and status are also in get_day_summary; over weeks or months use get_trend with metric hrv. include_readings adds the five-minute readings. |
| get_stressA | Return one day's stress: the average and peak, and the minutes at rest, in Garmin's low, medium and high bands, and unmeasured. The day's average alone is also in get_day_summary; for the daily average over weeks or months use get_trend with metric stress. With no stress data for the day the reply is null, or its fields are. include_samples adds the three-minute readings, which run to hundreds; leave it off unless the shape of the day matters. |
| get_body_batteryA | Return Garmin's own body battery record for each day from start to end, unprocessed. Use it for the detail behind a day's number. For one day's high and low, get_day_summary already has them; for daily highs over weeks or months, with an average and the change, use get_trend with metric body_battery. One Garmin request whatever the range, so keep it to days. The reply is Garmin's JSON as it comes: field names are Garmin's and nothing is converted. |
| get_stepsA | Return one day's steps: the total, and 24 hourly totals by GMT hour, not local time. For the total beside the day's other numbers use get_day_summary; for daily totals over a range with an average and the change, get_trend with metric steps. total is null, not 0, when Garmin did not answer. include_buckets adds Garmin's quarter-hour buckets. |
| get_training_readinessA | Return every training readiness entry Garmin recorded for one day: the score, its level and the factors behind it. Use it for why the score is what it is. Garmin recomputes readiness through the day; the entry whose inputContext is AFTER_WAKEUP_RESET is the morning score, which get_day_summary gives on its own and get_trend with metric readiness follows over weeks or months. One Garmin request. The reply is Garmin's JSON as it comes, usually a list of entries; null or empty when nothing was recorded. |
| get_training_statusA | Return Garmin's training status for one date: the status, training load and VO2 max context behind it, as Garmin's unprocessed JSON. For VO2 max over time use get_trend with metric vo2max (running) or vo2max_cycling; for whether to train today, get_training_readiness. One Garmin request; null when Garmin reports nothing for the date. Field names are Garmin's own. |
| get_personal_recordsA | List every personal record Garmin holds for the account, each named and in units (e.g. "Fastest 1 km run"), newest first; records with no date come last. A record set in an activity carries its activity_id, which get_activity opens; step and goal-streak records have none. For how a metric moved over a range use get_trend. Two Garmin requests the first time (the record types are then kept for the process), one after. |
| list_weigh_insA | List every weigh-in from start to end (end defaults to start), oldest first, with body composition and the sample_pk that delete_weigh_in takes. Includes every reading on days with more than one. For weight or body fat as one value a day with an average and the change, use get_trend with metric weight or body_fat; get_day_summary gives the day's last weigh-in. |
| add_weigh_inA | Record one body weight in Garmin Connect, in kg or lbs, with no body composition. For a smart scale reading with fat, water, muscle or bone, use add_body_composition instead. Without a timestamp it is filed now. A timestamp without an offset is taken as local time in the Garmin account's timezone, and one with an offset is moved into that timezone, so it lands on the right day. To correct a reading, delete it with delete_weigh_in (list_weigh_ins gives its sample_pk) rather than adding another. |
| add_body_compositionA | Record a weigh-in with body composition: fat, water, muscle, bone, BMI. This is the way to bring a smart scale's full reading into Garmin. A plain add_weigh_in carries weight only. Garmin reports every upload as "processed"; an identical measurement sent again is still kept only once, but a different reading at the same moment is kept as a second weigh-in. To correct one, delete the wrong one first: list_weigh_ins gives its id. |
| delete_weigh_inA | Permanently delete one weigh-in, identified by the sample_pk and day that list_weigh_ins gives for it. Use it to remove a wrong or duplicate reading; to correct one, delete it and record the right value with add_weigh_in or add_body_composition. Nothing here restores it, and day summaries and weight trends change with it. |
| get_trendA | How one metric moved over a range, with average, extremes and change. Metrics: steps, resting_hr, sleep (hours), sleep_score, hrv, readiness (the morning score), stress (the day's average), body_battery (the day's high), weight, body_fat, vo2max (running), vo2max_cycling. Up to two months comes back daily, up to a year weekly, longer monthly. Ranges are limited to two years. Steps, sleep, sleep_score, stress and body_battery are fetched four weeks per Garmin request, so a year of one is about 14 requests; hrv, readiness and resting_hr a year per request; weight, body_fat and VO2 max one request. For one day use get_day_summary or that metric's own tool; for every weigh-in rather than one a day, list_weigh_ins. The summary gives days_with_data (periods_with_data for VO2 max, which Garmin groups itself), the average, min and max of the days, the first and last day, and change: the last whole period's average minus the first whole period's, so a week the range cuts short does not count. |
| list_workoutsA | List the saved workouts in the account's library: plans to follow, with name, sport and estimated duration but not their steps. A saved workout is not on the calendar until scheduled: for what is planned on which date use list_scheduled_workouts, and for sessions already done, list_activities. For one workout's full step structure, get_workout. Paged: start skips that many workouts. |
| list_scheduled_workoutsA | List the workouts scheduled on the Garmin calendar in one month, with each entry's schedule_id, workout_id and date. Only planned workouts are returned: the completed activities, naps and badges Garmin's calendar also holds are dropped, as are the neighbouring months' days its grid spills into. For sessions done on those dates use list_activities; for the saved workouts whether scheduled or not, list_workouts. The schedule_id is what unschedule_workout takes. |
| get_workoutA | Return one saved workout by id: name, sport, description and estimated duration, with Garmin's full definition (every step, target and repeat) under raw. Use it to see what a plan asks for before scheduling or pushing it, or to check what create_strength_workout or create_endurance_workout built. Ids come from list_workouts or list_scheduled_workouts. A completed session is an activity: read it with get_activity or get_activity_sets. |
| delete_workoutA | Permanently delete a saved workout (a plan) from the account's workout library. To take a workout off one date but keep it, use unschedule_workout with the calendar entry's schedule_id instead. Completed sessions are activities, not workouts: delete those with delete_activity. Nothing here restores a deleted workout; get_workout first if its structure may be wanted again, since its raw field holds the full definition. |
| create_strength_workoutA | Create a strength workout to follow later. Each exercise becomes a block of sets with a rest between them. Name exercises with Garmin's category and exercise name, which find_exercise gives; an unknown name is rejected with suggestions. For runs, rides and swims use create_endurance_workout; to record a session already done, log_strength_session. Without schedule_date it is saved, not scheduled. With it, it is put on the calendar in the same call, and the reply carries the schedule_id. If scheduling fails the workout still exists and the error gives its id: schedule that one rather than creating it again. |
| create_endurance_workoutA | Create a run, ride or pool swim workout to follow on the watch. Steps end on a time, a distance or the lap button, and can repeat. Runs and rides take a target: pace per km or mile, speed, heart-rate zone or range, power zone or watts, or cadence. Swims take a stroke, equipment and a pool length; distances must be whole lengths. Give schedule_date to put it on the calendar too; the reply then carries the schedule_id, and if scheduling fails the error gives the new workout's id. For strength workouts use create_strength_workout. |
| create_workout_from_dtoA | Create a workout from a full Garmin DTO, for shapes the builder omits. Sent to Garmin as given: exercise names are not checked against the catalogue here, so prefer create_strength_workout where it can express it. |
| schedule_workoutA | Put a saved workout on the calendar for a date. Returns the calendar entry. Its schedule_id, not the workout id, is what unschedule_workout takes. Scheduling again adds a second entry; to move a workout to another day, unschedule the old entry first. |
| unschedule_workoutA | Remove one entry from the Garmin calendar; the saved workout itself is kept. Takes the schedule_id from list_scheduled_workouts, schedule_workout, or a create_* call made with schedule_date; not the workout_id. To move a workout, unschedule it and schedule_workout it on the new date. To delete the workout itself, use delete_workout. |
| push_workout_to_deviceA | Queue a saved workout for one of the account's watches; it arrives at the watch's next sync, not immediately. Without device_id it goes to the device last used, if it is on the account's list, else the primary activity tracker, else the only device; when none of those settles it, the call is refused and asks for a device_id. list_devices gives the ids, and the reply names the device chosen. Pushing does not schedule it: to put it on a date, use schedule_workout. |
| list_devicesA | List the Garmin devices paired with the account: device_id, name, product, and which one is the primary activity tracker. Use it to pick the device_id push_workout_to_device takes. A push without one prefers the device last used, which this does not show, so pass device_id when the device matters. One Garmin request. |
| log_strength_sessionA | Log a completed strength session to Garmin Connect as an activity. Takes the session as it happened, exercise by exercise with the reps and weight of every set, encodes it as a FIT activity file and uploads it. It appears in Garmin Connect as a Strength Training activity with the sets intact, named after the session, with its notes as the description. If the account shares to Strava or another app, the activity may be posted there too, publicly, and deleting it from Garmin does not delete it there. Name exercises with Garmin's category and exercise_name pair, which find_exercise gives. Logging the identical session again is reported as a duplicate and changes nothing; logging it with any set changed creates a second activity, so correct one with edit_activity_sets. |
| match_exerciseA | Map one free-text exercise name, such as one exported from another app, onto exactly one catalogue exercise, or return null when no single match is certain. Use it when converting names from another source, where a wrong guess would log the wrong lift. To browse candidates and choose, use find_exercise, which returns a ranked list. Only a certain match is returned: the exact or normalised name, the same words up to a typo, plural or hyphenation, or a search with one hit that adds at most an implement (barbell, dumbbell, kettlebell). No Garmin request. |
Prompts
Interactive templates invoked by user choice
| Name | Description |
|---|---|
No prompts | |
Resources
Contextual data attached and managed by the client
| Name | Description |
|---|---|
| list_exercise_categories | Every exercise category Garmin knows. |
TDQS
Scored across 38 tools
Tools are well-differentiated by resource and action, and overlapping metric tools (get_day_summary vs get_sleep/get_hrv/get_stress, get_trend vs individual metrics) are explicitly cross-referenced with guidance on when to use each. Minor potential confusion remains due to the sheer number of similar-sounding health and activity tools, but the descriptions resolve it.
Nearly all tools use consistent snake_case with verb_noun patterns (get_activity, list_workouts, create_strength_workout). A few outliers (garmin_status, recent_strength_sessions, week_summary) are noun-first or adjective-first, but they are readable and minor deviations.
38 tools is heavy for an MCP server; while the Garmin Connect domain is broad, several composite/convenience tools (week_summary, get_day_summary, recent_strength_sessions) add surface area that could be composed. The count is borderline but justified by the breadth of activities, health metrics, workouts, weight, and devices.
Core CRUD/lifecycle coverage is strong across activities, health metrics, weight, workouts, and devices. Notable gaps include no update_workout (must delete/recreate) and no generic activity creation beyond log_strength_session, but these are minor workarounds.