get_recent_activitiesLABSCO SUMMARY
One account's running history answers to a client that can also write the next session back to the watch.
The read side goes past the app's summary screens: get_activity_typed_splits breaks a trail run into ClimbPro climb segments with Grade Adjusted Pace, and get_lactate_threshold and get_activity_hr_zones return the numbers that Norwegian double-threshold and 80/20 plans are built on. The write side is a single call — create_running_workout takes warmup, interval, recovery and repeat steps with pace, heart-rate, cadence or power targets and uploads them for the watch to sync. Every Garmin response passes through strip_pii() first, which removes owner names, profile ids and the start and end GPS coordinates before the model sees them.
What it is
A Garmin Connect client built around running, with 24 tools covering activity detail down to the split, weekly and monthly volume, training and HRV metrics, sleep and Body Battery, shoe mileage, and a workout builder that uploads to Garmin.
What you get
- Activities at split resolution: get_recent_activities lists runs up to a count capped at 100, get_activities_by_date takes a start_date and end_date, and get_activity_detail, get_activity_splits and get_activity_hr_zones open one run's stamina, per-kilometre splits and heart-rate zone distribution — 47 fields in all, from pace and cadence through running dynamics, power, Grade Adjusted Pace and gradient.
- Trail runs read as terrain rather than one average: get_activity_typed_splits returns ClimbPro climb segments with their grade and Grade Adjusted Pace, and get_activity_weather returns the temperature, humidity and wind the run happened in.
- Volume trends without a spreadsheet: get_weekly_running_summary aggregates over weeks capped at 12, and get_monthly_running_summary returns a month alongside its comparison with the one before.
- Training metrics against your own baseline: get_training_status and get_training_readiness for a date, get_vo2max_and_fitness for VO2 max and fitness age, get_race_predictions for 5K, 10K, half and full marathon times, and get_lactate_threshold for threshold heart rate and pace across a date range.
- Recovery in its own tools: get_heart_rate_data and get_hrv_data for a date, get_sleep_data for the night, get_daily_wellness for stress, Body Battery, SpO2 and respiration, and get_weekly_wellness_summary over weeks capped at 4.
- Records, goals and gear: get_personal_records covers 1K through marathon, get_goals filters by active, completed or all, and get_running_gear returns each pair of shoes with its cumulative distance and wear rate.
- create_running_workout assembles a structured session from warmup, interval, recovery, rest, cooldown and repeat steps — each ending on duration_seconds or distance_meters, each able to target pace, heart_rate, cadence or power — and uploads it to Garmin for the watch to pick up; get_workouts lists what is already saved.
Requirements
Python 3.10+, the uv package manager, and a Garmin Connect account. Authenticate once with scripts/auth.py, which prompts for an MFA code when the account uses one and stores OAuth tokens in ~/.garminconnect/; putting GARMIN_EMAIL and GARMIN_PASSWORD in .env lets an expired token refresh itself instead of prompting again.
Setup effort
Build from source — git clone https://github.com/leewnsdud/garmin-connect-mcp.git
USE CASES
Reviewing how the running is going
Weekly and monthly summaries with the volume trend, and the month set against the one before it.
Taking one run apart
Splits per kilometre, the detail record, the weather that day, and the ClimbPro grade segments on a trail run.
Deciding whether today is a hard day
Training readiness and training status read next to the night's sleep, heart rate variability and body battery.
Setting paces from your own numbers
VO2max, lactate threshold and race predictions from 5K to the full marathon, rather than a calculator's guess.
Putting tomorrow's session on the watch
Describe the intervals as steps with pace, heart rate, cadence or power targets and the workout uploads to Garmin.
Knowing when to replace your shoes
Each pair with the distance run in it and how worn it is.
24 tools
Listed in project docs. Your client may show a different list.
get_activities_by_dateget_activity_detailget_activity_splitsget_activity_weatherget_activity_typed_splitsget_weekly_running_summaryget_monthly_running_summaryget_training_statusget_training_readinessget_vo2max_and_fitnessget_race_predictionsget_lactate_thresholdget_heart_rate_dataget_hrv_dataget_activity_hr_zonesget_sleep_dataget_daily_wellnessget_weekly_wellness_summaryget_personal_recordsget_goalscreate_running_workoutget_workoutsget_running_gearBEFORE YOU INSTALL
What to know first
Tools you get
24 tools named in the project's documentation. Twenty-three read; the one write, create_running_workout, builds a structured running session and uploads it to your Garmin watch. The server is running-specific, not a general Garmin bridge.
Requires
- Python 3.10+
- uv
- A Garmin Connect account
Where it runs
The documented client runs the server on your machine.
INSTALLATION
Connect your client
You clone this one yourself.
Server setup
git clone https://github.com/leewnsdud/garmin-connect-mcp.git
cd garmin-connect-mcp
uv syncOne-time authentication: uv run python scripts/auth.py — enter your Garmin email and password; the OAuth token is stored in ~/.garminconnect/ (an MFA code prompt appears if MFA is enabled)
Add the mcpServers block to claude_desktop_config.json using the FULL path to uv (check with which uv), then restart Claude Desktop
MCP Clients
Claude Desktop
{
"mcpServers": {
"garmin-mcp": {
"command": "/Users/<YOUR_USERNAME>/.local/bin/uv",
"args": [
"--directory",
"<YOUR_PATH_TO_GARMIN_MCP>",
"run",
"garmin-mcp"
]
}
}
}/Users/<YOUR_USERNAME>/.local/bin/uv is the full path that which uv prints, and <YOUR_PATH_TO_GARMIN_MCP> is the full path of the garmin-connect-mcp folder you cloned.
No password goes in this block: scripts/auth.py (the authentication step above) stores your Garmin OAuth token in ~/.garminconnect/. GARMIN_EMAIL and GARMIN_PASSWORD in the project's .env file are optional — they let the server refresh an expired token without running auth.py again.