Garmin Connect + InfluxDB fitness data MCP. Query steps, sleep, HRV, heart rate, activities; sync new data from Garmin Connect. Use when the user asks about their fitness data, training, sleep, steps, calories, or wants to sync new data from Garmin.
→ list_metrics() — no arguments. Returns all measurement names.
→ query_fitness_data — requires metric, range, aggregation. See Metric Catalog below.
→ query_activities — requires range, optional fields, limit, activity_type.
→ delete_data — requires measurement, range. Always confirm with the user before calling this. Data is permanently deleted.
→ sync_garmin — optional start_date, end_date (YYYY-MM-DD). Without dates, syncs from the day after the latest data in DB up to today (~30 days typical). Each day takes ~2.5s due to Garmin rate-limiting. Warn the user if syncing more than 14 days.
→ Use query_fitness_data with an Activity Field metric (distance, duration, averageSpeed, etc.) + activity_type filter + aggregation="sum". Convert meters to miles (/ 1609.34) or seconds to hours (/ 3600) as needed.
Use these metric names exactly in query_fitness_data(metric="..."). Call list_metrics() only when the user asks what measurements exist or when a metric they expect is missing from the catalog.
| Metric | Description | Unit hint |
|---|---|---|
total_steps | Daily step count | steps |
total_burned_calories | Calories burned | kcal |
total_distance_meters | Distance traveled | meters (→ miles via / 1609.34) |
daily_step_goal | Daily step goal | steps |
highly_active_minutes | Vigorous activity | seconds (→ hours via / 3600) |
moderately_active_minutes | Moderate activity | seconds (→ hours via / 3600) |
sedentary_minutes | Sedentary time | seconds (→ hours via / 3600) |
| Metric | Description |
|---|---|
total_sleep_minutes | Total time asleep |
light_sleep_minutes | Light sleep |
deep_sleep_minutes | Deep sleep |
awake_minutes | Time awake after sleep onset |
| Metric | Description |
|---|---|
resting_heart_rate | Resting HR |
lowest_heart_rate | Minimum HR that day |
highest_heart_rate | Maximum HR that day |
| Metric | Description |
|---|---|
floors_ascended | Floors climbed up |
floors_descended | Floors climbed down |
| Metric | Description |
|---|---|
hrv_last_night_avg | Last night's HRV average |
hrv_weekly_avg | Weekly HRV average |
activityType)Note: These metrics support
activity_typefiltering inquery_fitness_data. Daily Stats, Sleep, Heart Rate, Floors, and HRV metrics do not have activity type tags --activity_typeis ignored for those.
| Metric | Description | Unit hint |
|---|---|---|
distance | Activity distance | meters |
duration | Activity duration | seconds (→ hours via / 3600) |
averageSpeed | Avg speed | km/h (→ mph via × 0.621371) |
maxSpeed | Max speed | km/h |
averageHR | Avg heart rate | bpm |
maxHR | Max heart rate | bpm |
steps | Steps during activity | steps |
averageRunningCadenceInStepsPerMinute | Running cadence | spm |
avgStrideLength | Average stride length | cm |
| Metric | Description |
|---|---|
steps | Per-timestamp step counts throughout the day |
Two formats are accepted:
now() - <duration> — e.g. 4w (4 weeks), 7d (7 days), 1d (1 day)YYYY-MM-DD..YYYY-MM-DD — e.g. 2026-01-01..2026-04-13Examples:
range="4w"range="2026-03-01..2026-03-31"range="2026-01-01..2026-04-13"Pass to aggregation= in query_fitness_data:
| Value | Meaning |
|---|---|
sum | Total (steps, calories, distance) |
mean | Average |
min | Minimum |
max | Maximum |
count | Number of data points |
last | Most recent value |
Use with activity_type=["running"] etc. in query_fitness_data or query_activities. Common types: running, walking, cycling, swimming, strength_training, yoga, hiit, other. Filter by multiple: activity_type=["running", "cycling"].
query_fitness_data(metric="total_steps", range="1w", aggregation="sum")
query_fitness_data(metric="total_sleep_minutes", range="2w", aggregation="mean")
→ Display as hours: divide seconds by 3600.
query_fitness_data(metric="resting_heart_rate", range="4w", aggregation="mean", group_by="1d")
query_activities(range="2w", limit=5)
query_activities(range="4w", limit=10, activity_type=["running"])
query_fitness_data(metric="total_burned_calories", range="1w", aggregation="sum")
query_fitness_data(metric="hrv_last_night_avg", range="1w", aggregation="mean")
query_fitness_data(metric="hrv_last_night_avg", range="2w", aggregation="mean")
query_fitness_data(metric="distance", range="2026-01-01..2026-03-31", aggregation="sum", activity_type=["running", "walking"])
Result is in meters -- divide by 1609.34 for miles.
query_fitness_data(metric="duration", range="4w", aggregation="sum", activity_type=["running"])
Result is in seconds -- divide by 3600 for hours.
sync_garmin() without dates:
total_steps entry in InfluxDB, or 30 days ago if DB is emptystart_date and end_dateIf the default range would sync more than 14 days, warn the user: "This will take ~35 seconds due to Garmin rate-limiting. Continue?" Use explicit short ranges when the user only needs recent data.
sync_garmin(start_date="2026-04-01", end_date="2026-04-13")
list_metrics() to check what metrics exist — the Metric Catalog in this skill lists all of them. Call list_metrics() only when the user asks "what measurements do you have?".delete_data without explicit user confirmation. Data is permanent. Show the user what will be deleted first: "Delete all total_sleep_minutes from 2026-03-01 to 2026-03-31? This cannot be undone."sync_garmin with no date range for large gaps — if the user asks to sync "all of March", specify start_date and end_date explicitly rather than relying on the auto-default which starts from the latest data.sync_garmin().mean on metrics that are already daily totals (like total_steps) and then compare across different range sizes without accounting for the difference. A 4-week sum and 1-week sum need the same time base for comparison.