Remote MCP server for Garmin Connect data access via OAuth 1.0a authentication, providing tools for activities, health metrics, training, workouts, nutrition, community, body composition, and power analysis
Strong foundation with 29 well-named tools, comprehensive parameter schemas using Zod, and detailed descriptions for most tools. Naming follows verb_noun convention consistently (get_*, update_*, upload_*). Most tools include rich descriptions (100-400 chars) explaining pagination, data filtering, and API quirks. However, several tools lack output schemas despite returning structured data, and error handling guidance is minimal. Tool composition is sound, each tool has a single responsibility and chains naturally (e.g., get_activities_by_date → get_activity → update_activity). Parameter descriptions are generally strong, with format constraints and enums where appropriate. Missing: explicit error recovery guidance, confirmation patterns for destructive ops, and output schema documentation for ~15 tools.
Get activities between specified dates with pagination support. For accounts with large activity histories, broad date ranges can return thousands of activities in a single response. Use page and page_size to retrieve activities in manageable chunks and avoid "result too large" errors. Activities are ordered newest-first. Pagination: when has_more is true the response includes next_page — pass that value as page on the next call to retrieve the following page. Repeat until has_more is false. Note: total_count for a date range is not available from the Garmin API without fetching all results. Use has_more / next_page to walk pages. Each activity includes an event_type field with values such as: - "race" — explicitly tagged as a race by the user - "training" — explicitly tagged as a training activity - "uncategorized" — no event type set; common for Peloton imports and untagged outdoor runs. Distinct from "training": filter for races with event_type == "race" rather than excluding "training", since many non-race activities appear as "uncategorized" not "training" - field absent — API returned no eventType for this activity; not observed in practice in any activity back to 2012 (oldest activities sampled on this account)
Get activities for a specific date
Get detailed information about a specific activity
Download and parse the FIT file for an activity: session and lap data plus power analysis (normalized power, variability index, power duration curve, W/kg). Remote port: advanced Di2 shift/climb/HRV analytics from the original local server are not included; use include_records for downsampled raw records.
15 tools have minimal descriptions (50 chars or less): get_activity, get_sleep, get_stress, get_body_battery, get_respiration, get_spo2, get_profile, get_social_profile, get_settings, get_training_status, get_training_readiness, get_vo2_max, get_workout, get_nutrition, get_community_challenges. LLMs cannot distinguish when to call these vs similar tools without richer context.
No output schemas declared for any tools. While toolkit.ts defines outputSchema support and uses it for validation, none of the 29 tool definitions in src/tools/*.ts include outputSchema. This prevents LLMs from understanding return structure and planning downstream calls.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-23 | D | 56 | 2025-06-18+ | v2 |
Get body battery data for a date range
Get body composition data for a date range
Get list of community challenges
Get daily health metrics for a specific date: steps, heart rate, stress, body battery, respiration, SpO2, sleep, and more
Get current health snapshot: heart rate, stress, body battery, respiration, SpO2, and more
Get heart rate variability (HRV) data for a date range
Get nutrition data for a specific date
Season-best power duration curve across recent cycling activities, with an FTP estimate (95% of best 20min). Remote port: num_activities capped at 15 (was 20) for the serverless request budget.
Get user profile information
Get respiration data for a date range
Get user settings and preferences
Get sleep data for a specific date
Get user social profile information
Get SpO2 (blood oxygen) data for a date range
Get stress data for a date range
Get training readiness score
Get current training status and metrics
Get VO2 max data
Get detailed information about a specific workout
Get list of available workouts
Update activity fields: name, description, type, event_type, start_time, distance_meters, duration_seconds, calories, avg_hr_bpm, max_hr_bpm, elevation_gain_meters, elevation_loss_meters. Omitted fields are not changed. Garmin merges the payload with the existing activity.
Upload a FIT file to create a new activity. Returns upload_id, activity_id (if immediately available), status, and any messages from Garmin.
Build and upload a minimal TCX file from heart rate samples. Useful for manual HR-only activity logging. Returns upload_id, activity_id (if immediately available), status, and any messages from Garmin.
Upload a TCX file to create a new activity. Returns upload_id, activity_id (if immediately available), status, and any messages from Garmin.
Upload weight and body composition data. Encodes to FIT format and uploads to Garmin.
No error recovery guidance in any tool description. Tools like update_activity and upload_* are destructive/write operations but lack confirmation patterns or error handling hints. Agents cannot self-correct on failure.
Tool annotations (readOnlyHint, destructiveHint, idempotentHint) are not used. All tools are registered without these hints, making it impossible for clients to infer safety properties without reading descriptions.
Date range tools (get_heart_rate_variability, get_stress, get_body_battery, get_respiration, get_spo2, get_body_composition) accept arbitrary date ranges but lack documented max-day constraints. assertSpan() enforces limits in code, but descriptions don't state them, risking LLM calls that fail.