durely insights
Connects to a Garmin Connect account through Garmin's official Personal API to sync and analyze full training history, activities, health, sleep, HRV, Body Battery, training load, and recovery data. Enables AI assistants to answer detailed questions about workouts, trends, laps, zones, and comparisons using local synced data, with read-only access and privacy controls.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@durely insightsHow did I sleep this week, and how was my HRV?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
durely insights
Ask your AI assistant about your own Garmin data: your full training history, health and recovery, analysed.
durely insights is an MCP server that connects your Garmin Connect account to your AI assistant (Claude, Cursor, GitHub Copilot, Gemini CLI, Codex or any other MCP client) through Garmin's official Personal API. It keeps a copy of your history on your own machine, so you can ask about a single run or about years of training and get an answer right away.
Early development (v0.5). Everything below works. Packaging (npm, Docker image on GHCR) comes next; until then you build it yourself, which takes a minute.
Unofficial project: not affiliated with or endorsed by Garmin.
What you can ask
Activities
"What did I do this week?" / "Show my last 10 runs"
"Tell me about yesterday's run": splits, heart rate, training effect, load
"How did my power and heart rate evolve over the intervals of Tuesday's ride?"
"Compare the bike legs of my last two triathlons lap by lap"
"Am I getting fitter on my regular Tuesday run?"
Training
"How has my training load and fitness developed over the last 3 months?"
"Analyse Saturday's ride: time in zones, decoupling, best efforts"
"How many kilometres did I run, ride and swim per year?"
Health and recovery
"How did I sleep this week, and how was my HRV?"
"Does a hard training day affect my HRV the next morning?"
"Compare my resting heart rate and sleep score per month this year"
"Show my heart rate and Body Battery through yesterday"
Related MCP server: garmin-mcp
What makes it different
Official API, no password. It uses a Personal API key that you create in Garmin Connect and can revoke at any time. No scraping, nothing that breaks when Garmin changes its login.
Your whole history, instantly. Everything is synced once to a local database and kept up to date, so trend questions over months or years don't wait on Garmin.
Second-by-second detail. Laps, swim lengths, heart rate, power, cadence and more come from each activity's original FIT file, including VO2max, recovery time and lactate threshold when your device records them.
Analysis built in. Time in zones, training load and fitness/fatigue/form, aerobic decoupling, best efforts, recovery trends and comparisons of similar sessions. For anything else, your assistant can run read-only SQL over your data.
Private by default. Your data stays on your machine. Your name, account ID and GPS positions are kept out of answers unless you ask for a route.
Read-only. It can't change anything in your Garmin account.
Quick start
You need Garmin Connect, an MCP client (Claude Code, Claude Desktop, Cursor, …) and either Node.js 24+ or Docker.
1. Create your Personal API key
In Garmin Connect on the web, open Settings → Personal API Token.
Create a key and pick how long it stays valid (30 days to 1 year). Garmin shows it only once, so copy it.
Save it to a file only you can read:
mkdir -p ~/.config/garmin && chmod 700 ~/.config/garmin pbpaste > ~/.config/garmin/connect-personal-api-key # macOS; elsewhere, paste it into this file with an editor chmod 600 ~/.config/garmin/connect-personal-api-keyWith Node.js you can skip these commands: after step 2, run
node dist/index.js auth. It asks for the key (your input stays hidden), checks it with Garmin and saves it to this file.
Don't paste the key into a chat with your AI assistant.
2. Install the server
With Node.js:
git clone https://github.com/durely/garmin-insights-mcp.git
cd garmin-insights-mcp
npm install && npm run buildYour server command is node /absolute/path/to/garmin-insights-mcp/dist/index.js. Check your key with node dist/index.js auth --check.
Or with Docker (no Node.js needed; Docker must be running):
git clone https://github.com/durely/garmin-insights-mcp.git
cd garmin-insights-mcp
docker build -t garmin-insights-mcp .Your server command is:
docker run -i --rm \
-v ~/.config/garmin/connect-personal-api-key:/run/secrets/garmin_api_key:ro \
-v garmin-mcp-data:/data \
-e GARMIN_MCP_TIMEZONE=Europe/Brussels \
garmin-insights-mcpReplace Europe/Brussels with your own time zone. To check your key, run the same command with auth --check at the end. More Docker tips are in How it works.
Updating: run git pull, then npm install && npm run build (Node) or docker build -t garmin-insights-mcp . (Docker). Your synced data is kept.
3. Add it to your AI client
Claude Code:
claude mcp add garmin --scope user -- node /absolute/path/to/garmin-insights-mcp/dist/index.jsWith Docker:
claude mcp add garmin --scope user -- docker run -i --rm \
-v ~/.config/garmin/connect-personal-api-key:/run/secrets/garmin_api_key:ro \
-v garmin-mcp-data:/data \
-e GARMIN_MCP_TIMEZONE=Europe/Brussels \
garmin-insights-mcp--scope user makes it available in all your projects.
Claude Desktop: open Settings → Developer → Edit Config, add this, and restart Claude Desktop:
{
"mcpServers": {
"garmin": {
"command": "/opt/homebrew/bin/node",
"args": ["/absolute/path/to/garmin-insights-mcp/dist/index.js"]
}
}
}Desktop apps don't see your shell's PATH, so use the full path to node (find it with which node).
Claude Desktop with Docker:
{
"mcpServers": {
"garmin": {
"command": "/usr/local/bin/docker",
"args": [
"run",
"-i",
"--rm",
"-v",
"/Users/you/.config/garmin/connect-personal-api-key:/run/secrets/garmin_api_key:ro",
"-v",
"garmin-mcp-data:/data",
"-e",
"GARMIN_MCP_TIMEZONE=Europe/Brussels",
"garmin-insights-mcp"
]
}
}
}Use full paths here; ~ isn't expanded in JSON configs.
Cursor: the same JSON as Claude Desktop, in ~/.cursor/mcp.json (global) or .cursor/mcp.json (project).
VS Code (GitHub Copilot agent mode): in .vscode/mcp.json, or via the command palette → MCP: Add Server:
{
"servers": {
"garmin": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/garmin-insights-mcp/dist/index.js"]
}
}
}Gemini CLI:
gemini mcp add garmin node /absolute/path/to/garmin-insights-mcp/dist/index.jsOpenAI Codex CLI:
codex mcp add garmin -- node /absolute/path/to/garmin-insights-mcp/dist/index.jsOthers (Windsurf, Cline, Zed, …): look for "MCP servers" in their settings. Any client that supports stdio servers works.
4. Try it
Start a new session and ask: "Check my Garmin connection." It should report connected.
The first question starts a sync in the background. Your activities are there within seconds; the rest of your history follows in a few minutes. After that, the data refreshes automatically when it's more than an hour old.
Good to know
Keep your key's expiry date in mind. Garmin's API doesn't tell the server when your key expires. Set
GARMIN_API_KEY_EXPIRES(e.g.2027-10-24) in your client config andgarmin_statusreminds you in time. With Docker, pass it to the container instead: add-e GARMIN_API_KEY_EXPIRES=2027-10-24to thedocker runarguments. Replacing the key file is enough; no restart is needed.Sync at least every few months. Garmin deletes intraday detail (heart rate through the day, overnight HRV readings) after about 4–5 months. Whatever the server has synced stays in your local copy.
Desktop and CLI clients only, for now. The server runs on your own machine, so it doesn't work in claude.ai on the web or mobile yet.
Your data goes to your AI client. The server only talks to Garmin, but the answers it gives go to the MCP client and model you use.
Troubleshooting
Problem | Fix |
Tools don't show up | Start a new session or restart the client. In Claude Code, check |
| Use the full path to |
"No Garmin Personal API key configured" | The key file is missing or not mounted. Check the path (and the |
"Garmin rejected the Personal API key" | The key expired or was revoked. Create a new one and replace the file (or run |
Dates are off by a day | Set |
Want to see the tools without an AI client |
|
Tools
You don't need to call these yourself; your assistant picks them. For reference:
Tool | What it does |
| Connection check: key, token, time zone, key expiry |
| Profile settings, heart rate zones per sport, fitness age |
| Search your activities by date, sport, name, distance or duration |
| One activity in full: summary metrics, splits, structured workout |
| Laps from the FIT file: pace, HR, power, cadence, swim lengths, VO2max, recovery time |
| Second-by-second HR, power, speed, cadence, altitude, …; zoom into any part |
| Time in zones, NP/IF/TSS, aerobic decoupling, best efforts, intervals |
| 2–6 activities side by side |
| Per week or month: volume per sport, load, intensity, fitness/fatigue/form |
| Sleep, HRV, resting HR, Body Battery and stress against your baseline, and their link with load |
| Per day, week or month: steps, resting HR, stress, Body Battery, calories, sleep, HRV |
| Nightly sleep stages, times and sleep score |
| Nightly HRV, 7-day average, baseline and status |
| One day hour by hour: heart rate, Body Battery, overnight HRV, SpO2 |
| Weigh-ins, body composition, weight goal |
| Food and hydration logged in Garmin Connect or a linked app |
| Menstrual cycle tracking |
| Read-only SQL over your synced data |
| Save an activity's original FIT file, e.g. to import elsewhere |
| Sync now, go further back in time, or download all FIT files |
| What's synced, and sync progress |
In clients that support prompts (often as slash commands), weekly_review, activity_deep_dive and recovery_check start a guided analysis.
Configuration
All optional; set them as environment variables in your client config.
Variable | Default | Purpose |
| Your key's expiry date ( | |
| system time zone | Your time zone (IANA name, e.g. |
| The key itself, instead of the key file | |
|
| Where the key file is |
|
| Where your synced data is kept |
|
| Refresh automatically when the data is over an hour old |
|
| Days of intraday detail (HR, overnight HRV, SpO2) to keep synced |
|
| Request throttle; Garmin publishes no limits |
|
|
|
In Docker, the key file and data directory are /run/secrets/garmin_api_key and /data.
Privacy and security
Your key stays on your machine. It's exchanged for a 24-hour token, cached with owner-only permissions. The server never writes the key itself. To revoke access, delete the key in Garmin Connect.
No telemetry. The server only talks to Garmin's Personal API.
Your synced data is sensitive. The local database and FIT files hold your health and activity history, including GPS tracks. The data directory is readable only by you (in Docker it lives in the
garmin-mcp-datavolume).Identity and location stay out of answers. Your name, profile picture and account ID are removed before anything is stored. GPS positions are only returned when you ask for route or location analysis (or query an activity's start and end point with SQL).
More
How it works: the local cache and sync, FIT files, how the numbers are calculated, Docker details, development
License
Apache-2.0. See LICENSE and NOTICE.
Data provided by Garmin devices via Garmin Connect; the analyses are insights derived in part from Garmin device-sourced data. Garmin and Garmin Connect are trademarks of Garmin Ltd. or its subsidiaries. This project is not affiliated with or endorsed by Garmin.
Available Tools
21 toolsgarmin_analyze_activityAnalyze an activityARead-onlyIdempotent
Compute training metrics for one activity from its second-by-second FIT data:
time in heart rate zones (the user's Garmin zones for that sport) and, with an FTP, in power zones (Coggan)
power: average, normalized power (NP), variability index, intensity factor and TSS (needs FTP)
aerobic decoupling: drift of power or pace per heartbeat between the first and second half (<5% is good for steady efforts of 45+ min)
first vs second half (negative/positive split)
best efforts: power over 5 s–60 min, heart rate over 1–60 min, fastest 400 m–marathon (running), 5–90 km (cycling), 100 m–3.8 km (swimming)
Edwards TRIMP (zone-weighted minutes) and detected work intervals with their consistency
FTP comes from ftp_w, else from the activity's own record (Garmin cycling FTP). Works for multisport legs too.
| Name | Required | Description | Default |
|---|---|---|---|
| ftp_w | No | Functional threshold power in watts, for power zones, IF and TSS | |
| activity_id | Yes | Garmin activity ID from garmin_list_activities | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the description correctly spends its words elsewhere: it discloses the FTP resolution chain ('ftp_w, else from the activity's own record') and gives interpretive context for the decoupling metric. It stops short of stating failure modes, e.g. what happens when no FIT data exists for the activity.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded one-line purpose followed by a scannable bullet list of outputs; each bullet names a distinct metric family. The enumeration is long but load-bearing for an agent deciding whether this tool answers its question.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the metric list effectively doubles as a return-value contract, and the FTP dependency and metric interpretation are covered. The missing piece is the data precondition: nothing says the activity's FIT file must first be fetched (e.g. via garmin_download_activity_fit), which an agent needs to know before calling.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description earns an extra point by explaining the ftp_w fallback behavior that the schema field text omits, telling the agent it can pass null/minimal input and still get power metrics when a cycling FTP is recorded.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('compute training metrics for one activity from its second-by-second FIT data') and then enumerates exactly which derived metrics are produced, which cleanly separates it from raw-data siblings like garmin_get_activity or garmin_get_activity_streams. Scope is further pinned down with 'works for multisport legs too'.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Implied usage is clear (compute per-activity training metrics), and conditional prerequisites are noted ('with an FTP, in power zones', 'needs FTP'). But it never states when to prefer this over garmin_training_summary, garmin_compare_activities, or garmin_get_activity_laps, nor what to do if the FIT file isn't downloaded yet.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_compare_activitiesCompare activitiesARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| deep | No | Also run FIT-based analysis for each activity | |
| activity_ids | Yes | ||
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), but the description adds material behavior those annotations cannot express: deep=true downloads FIT files if needed, which is a network/IO side effect worth flagging and is disclosed. It also implicitly bounds input to 2–6. What's missing is any note on latency or cost of deep mode.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the capability and metric list, then the deep-mode modifier, then a worked example — a logical order with no filler. The parenthetical defining efficiency factor is long but genuinely informative for interpreting results, so it earns its space.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the burden of explaining return content — and it does, enumerating the compared metrics plus what deep mode adds (aerobic decoupling, HR zone time, best efforts). An agent has everything needed to choose and call the tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 67% and the one undocumented parameter (activity_ids) is compensated for by the description stating 'compare 2–6 activities', matching minItems=2/maxItems=6. deep is explained in both schema and prose. It adds value over the schema but does not, for example, clarify what activity_ids refer to or how to obtain them.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb ('compare') and resource (2–6 activities) and immediately enumerates exactly which fields come back (date, type, duration, distance, pace/speed, HR, power avg/NP, elevation, training effect/load, cadence, efficiency factor). This is clearly distinguishable from single-activity siblings like garmin_get_activity or garmin_analyze_activity.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives a concrete usage scenario ('Am I getting fitter on my Tuesday interval run?' → list those runs, then compare them) and explains when to escalate to deep=true for FIT-based analysis. It does not explicitly contrast with garmin_analyze_activity or say when comparison is the wrong choice, so it falls short of the top band.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_download_activity_fitExport activity FIT fileAIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| activity_id | Yes | Garmin activity ID from garmin_list_activities |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations signal a non-read-only but idempotent, non-destructive write, and the description corroborates and enriches this: it discloses the exact output path (<data dir>/exports/<activity_id>.fit), that an existing export is preserved rather than overwritten, and that a multisport leg yields the whole multisport file. These are exactly the side effects and edge cases an agent needs and that annotations alone cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three tight sentences, front-loaded with the action and return value, followed by the file-format guarantee and the overwrite/multisport edge cases. No sentence is redundant or restates the title.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description still specifies what is returned (a path) and the exact filename convention, plus overwrite behavior and multisport handling. For a one-parameter export tool this covers everything needed to invoke it correctly and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The single parameter is fully documented in the schema (100% coverage) and even points to garmin_list_activities as its source, so the description need not explain it further. The description adds no additional semantics about activity_id, which is fine given the schema but keeps this at the baseline.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Save the original FIT file of an activity') plus the destination and return value, which cleanly separates it from parsed-data siblings like garmin_get_activity or garmin_get_activity_streams. An agent can tell immediately that this yields a raw file, not a JSON activity object.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description names concrete downstream consumers (Intervals.icu, Golden Cheetah, spreadsheet converters), giving a clear context for when to pick this over the parsed-activity siblings. It does not explicitly say when NOT to use it — e.g., steer toward garmin_get_activity_streams for programmatic analysis — so the routing is implied rather than complete.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_get_activityGet Garmin activity detailsARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| activity_id | Yes | Garmin activity ID from garmin_list_activities, e.g. 12345678901 | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint, and openWorldHint, so the safety profile is covered; the description adds real value by enumerating exactly what comes back (summary metrics, split summaries, structured workout, multisport parent/child IDs) — understanding that the payload can be large and nested. It omits any note on auth, rate limits, or behavior for invalid/expired activity IDs, which keeps it below a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The purpose and the usage chain are front-loaded, which is good, but the return-value sentence is a single very long parenthetical enumeration of ~20 metrics. That wall of field names is informative yet poorly structured — it would read far better as a short list or a note pointing to response_format='json' for the full structure.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description must carry the return shape — and it does, itemizing metrics, splits, workout, and multisport IDs. Combined with the ID-source guidance and the response_format hint, an agent has everything needed to call this correctly on the first try.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and both parameters are documented there, so the baseline is 3. The description adds the provenance of activity_id ('from garmin_list_activities'), which tells the agent where the value must come from — genuine meaning beyond the schema's 'e.g. 12345678901'. It says nothing extra about response_format beyond what the enum already conveys.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get full details for one Garmin activity') with an explicit scoping constraint ('by ID'), which cleanly separates it from garmin_list_activities, garmin_get_activity_laps, and garmin_get_activity_streams. An agent can place this tool without opening any schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the prerequisite explicitly ('Get IDs from garmin_list_activities') and a concrete chain example ('Tell me about yesterday's run' -> list, then call this with its id). It does not say when to prefer garmin_analyze_activity, garmin_get_activity_laps, or garmin_download_activity_fit instead, so the sibling differentiation stops short of full routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_get_activity_lapsGet activity lapsARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| lap_offset | No | Skip this many laps (for activities with very many laps) | |
| activity_id | Yes | Garmin activity ID from garmin_list_activities | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare it read-only, idempotent and non-destructive, so the description adds value by disclosing the network behavior: the FIT file is downloaded on first use and then cached. It also discloses what data comes only 'when the device recorded them', which sets correct expectations about missing fields — a detail annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose, then a dense field inventory, then usage and caching notes. The return-field sentence is long but each clause maps to real output content rather than filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the full burden of describing return values — and it does so thoroughly, covering lap fields, swim-specific fields, multisport sessions, and FIT-only metrics, plus the caching behavior. An agent has enough to call it correctly and interpret the result.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% and every parameter (activity_id, lap_offset, response_format) is documented in-schema, including the enum. The description adds no syntax or overflow guidance (e.g. when to use lap_offset on very long activities), so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get the laps... of one activity, from its original FIT file') and enumerates the returned granularity, so an agent knows this is the lap/session-level view rather than the activity overview. No sibling is named, so routing between it and garmin_get_activity or garmin_get_activity_streams is inferred rather than stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'Use it for interval sessions, splits and pacing' gives concrete use conditions, and 'For a multisport leg ID, returns only that leg's laps' clarifies a scope boundary. It lacks explicit when-not guidance or a named alternative for activity-level summaries.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_get_activity_streamsGet activity time seriesARead-onlyIdempotent
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".
| Name | Required | Description | Default |
|---|---|---|---|
| end_s | No | Window end, seconds from the start | |
| fields | No | Fields to return: heart_rate, power, speed, cadence, altitude, distance, temperature, respiration_rate, performance_condition, vertical_oscillation, stance_time, position, or a dev_* field | |
| start_s | No | Window start, seconds from the start | |
| max_points | No | Upper bound on points returned | |
| activity_id | Yes | Garmin activity ID from garmin_list_activities | |
| resolution_s | No | Seconds per point (minimum) | |
| response_format | No | 'json' (default) for the full series, 'markdown' for stats and a short preview table | json |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare the read-only, idempotent, non-destructive profile, but the description layers on substantial extra behavior: automatic coarsening for long activities, omission of zeros in cadence averages, and a privacy warning that 'position' reveals where the user was. This is exactly the kind of context annotations cannot convey.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core summary, then organized by returns, defaults, zooming, and the position/dev_fields caveats. Slightly long and repeats a few schema defaults (10 s, 500 points), but every block carries actionable information, so it earns most of its length.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description carries the burden of explaining returns; it does so clearly (per-field min/avg/max plus columnar t-series with one array per field). The only minor gap is not stating error conditions for an activity lacking requested fields (e.g., what happens if power is absent), but overall it is complete for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline would be 3, but the description adds genuine meaning: units for every field (bpm, W, m/s, °C, etc.), the semantics of performance_condition (-20..+20), cumulativeness of distance, dev_* field lookup via available_fields, and how resolution_s/max_points interact. This goes well beyond the schema's one-line descriptions.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get second-by-second data from one activity's FIT file') and immediately adds the key constraint ('downsampled to fit in context'). It distinguishes itself from siblings by referencing garmin_get_activity_laps for finding window offsets, so an agent can route here vs. a laps or analyze tool without opening schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explains default behavior (which fields, 10s resolution, 500 points), how to zoom ('start_s/end_s and a smaller resolution_s'), and where to get offsets from garmin_get_activity_laps. It also gives an explicit guardrail: only request 'position' when the user asks for location or route analysis.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_get_body_compositionWeight and body compositionARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| end_date | No | Defaults to today | |
| start_date | No | Local calendar date, yyyy-MM-dd | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile, and the description adds genuinely new behavior: it reads a local cache (implying possible staleness), only days with recorded weigh-ins appear, the default window is 365 days, and the response includes period change plus an optional weight goal. A hint about needing garmin_sync first would push it higher.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Three short sentences: what comes back, the recording caveat, and the default window. Field list is front-loaded and nothing is redundant.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description does its part by enumerating return fields, units, provenance, period change, and the goal. The main gap is not stating how cached data relates to freshness/sync, which matters for a cache-backed tool.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds the default 365-day window that the start_date field does not document. That is real meaning beyond the schema, though response_format and end_date behavior are left to the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get weigh-ins from the local cache') and enumerates the returned metrics, so an agent can tell it apart from garmin_get_daily_health or garmin_get_profile. It does not explicitly name a sibling it differs from, which holds it back from a 5.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'From the local cache' and 'Only days with a weigh-in appear. Defaults to the last 365 days' imply when the data is available, but the description never says when to choose this over adjacent tools (daily health, profile) or whether a sync is needed first. Usage is only implied.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_get_daily_healthDaily health and recoveryARead-onlyIdempotent
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".
| Name | Required | Description | Default |
|---|---|---|---|
| end_date | No | Defaults to today | |
| group_by | No | day | |
| start_date | No | Local calendar date, yyyy-MM-dd | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld, so the safety profile is covered. The description adds genuinely non-obvious behavior: data comes from a local cache covering all history, today's values are partial, and a hard 92-day row limit exists. It does not say what happens when the cache is empty or stale, which matters given a garmin_sync sibling.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded purpose sentence, then a compact field inventory, then aggregation semantics, limits, and examples in a clear progression. The dense metric list is information the agent needs to answer 'what can I ask this for', so nothing reads as filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, and the description compensates by enumerating the returned metrics and the aggregation shape in detail. The one gap is operational: it says data comes from the local cache but never indicates that a sync may be required first or how to detect an empty cache, which is relevant given the garmin_sync and garmin_sync_status siblings.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
With 75% schema coverage the baseline is 3, and the description earns above that: group_by has no schema description yet the text explains week is Monday-based and what week/month aggregation actually computes (averages per day, min/max for HR and stress, totals for steps and intensity minutes). start_date/end_date semantics (default last 14 days, today partial) and the response_format tradeoff are also covered.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The opening sentence gives a specific verb and resource (day-by-day wellness and recovery data) and enumerates the exact metrics returned, so an agent can tell this is the rolled-up daily wellness view rather than a single-metric tool. It does not explicitly contrast with overlapping siblings such as garmin_get_sleep, garmin_get_hrv, or garmin_get_intraday, so the boundary is inferable but not stated.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is well scaffolded: the 14-day default, the 92-day cap on daily rows, and the rule to switch to group_by="week" or "month" for longer windows are all stated, plus two worked examples mapping a user question to parameters. What is missing is any explicit exclusion (e.g. when to prefer garmin_get_intraday for same-day detail or garmin_get_sleep for a single night).
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_get_hrvHeart rate variabilityARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| end_date | No | Defaults to today | |
| start_date | No | Local calendar date, yyyy-MM-dd | |
| readings_date | No | Night (wake-up date) to include 5-minute readings for | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Beyond the annotations, the description discloses that data comes from a local cache, that 5-minute readings may be fetched from Garmin when older than the synced detail window, the default and maximum ranges, and the compatible-watch requirement. This is rich behavioral context for a read-only tool.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is front-loaded with the core purpose and return values, then proceeds to parameter effects and constraints. Every sentence adds useful information without redundancy.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, but the description thoroughly explains the returned HRV metrics and the optional 5-minute readings. For a read-only cache-backed tool with clear annotations, nothing essential is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is already 100%, so the baseline is 3. The description adds useful meaning beyond the schema by explaining the readings_date effect, the 28-night default, and the 366-night cap, though it does not discuss response_format.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: get nightly HRV from the local cache. It enumerates exactly what is returned (last-night average, highest 5-minute value, 7-day average, baseline range, and Garmin status), making it distinguishable from broader health/recovery siblings.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is clear: default date range, maximum per call, how readings_date changes behavior, and the hardware prerequisite. It does not explicitly name alternative siblings such as recovery trends, but the conditions for correct use are well explained.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_get_intradayIntraday health dataARead-onlyIdempotent
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).
| Name | Required | Description | Default |
|---|---|---|---|
| date | No | Defaults to today | |
| metrics | No | ||
| interval_min | No | Minutes per point | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the read-only/idempotent/non-destructive profile, and the description adds substantive behavior on top: on-demand remote fetching for days older than 150, degraded data availability because Garmin retains intraday HR/HRV for only ~4-5 months, and the fallback that ancient days may return only the day summary. Device prerequisites for HRV and SpO2 are also surfaced.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Purpose and metric list are front-loaded in the first sentence, then return shape, then availability caveats, then defaults — a logical order. It is dense but nearly every clause carries operational information; the defaults sentence slightly duplicates schema defaults.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the return-value burden itself and does so precisely: per-metric min/avg/max, day summary values such as resting HR and Body Battery charged/drained, and a columnar series of local HH:MM timestamps plus values. Together with the retention caveats, an agent knows both what it will get and how complete it will be.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 75%, so the baseline is 3, and the description earns an increment by giving units and ranges for each metric value (bpm, Body Battery 0-100, HRV in ms, SpO2 in %) plus restating the effective defaults for date, metrics and interval. Only response_format is left entirely to the schema, so it stops short of a 5.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The first sentence gives a specific verb (get), resource (one day's health data) and a clear differentiator (averaged into intervals, listing the four metrics). The intraday/interval framing implicitly separates it from summary-style siblings like garmin_get_daily_health and garmin_get_hrv, but no sibling is named, so the agent must infer the boundary.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage context is unusually clear: it states defaults (today, all four metrics, 15-minute intervals), that the last 150 days are pre-synced while older days trigger an on-demand Garmin fetch, and that HRV/SpO2 require a compatible watch with pulse ox enabled. What's missing is explicit routing — it never says when to prefer garmin_get_daily_health or garmin_get_hrv instead.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_get_nutritionNutrition and hydrationARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| end_date | No | Defaults to today | |
| start_date | No | Local calendar date, yyyy-MM-dd | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly, idempotent, openWorld, non-destructive, so the safety profile is free. The description adds real behavioral context beyond that: data is fetched on demand and cached (implying possible latency and staleness) and the 7-day default / 31-day cap. It doesn't explain cache refresh behavior or failure modes, so not a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two tight sentences/short paragraphs: the first front-loads what is returned, the second carries fetch/caching and window limits. No filler, every clause carries information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description must carry the return payload, and it does list the metric groups and hydration units. It lacks detail on the shape of meal entries or how goals are represented, so an agent knows what it gets only at a coarse level.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds the start_date default ('last 7 days') that the schema lacks and the 31-day span limit, which is genuinely new constraint information an agent needs to avoid empty or rejected calls.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: get food logged in Garmin Connect (or linked apps like MyFitnessPal) per day, enumerating the returned metrics (calories, carbs, protein, fat vs goals, meals) plus hydration in ml. No sibling tool covers nutrition, and the enumerations make the scope unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives the operating window ('defaults to the last 7 days, at most 31 per call'), which tells an agent how to size requests, and the data-source note implies when this tool applies versus activity/sleep/health siblings. It stops short of explicitly naming an alternative or a when-not condition, but no sibling overlaps on this data.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_get_profileGet Garmin profile and zonesARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld, so the safety profile is covered. The description adds genuinely useful behavioral detail beyond that by spelling out what comes back (units and locale, time zone, preferred training days, zone floors with the max HR/LTHR/resting HR used, latest fitness age). It does not mention cost of the network call or how markdown vs json differ in completeness.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short blocks, front-loaded with what is returned and followed by the decision rule. Every sentence carries information an agent needs; nothing is filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly carries the return-value burden and does so in useful detail, plus the prerequisite usage rule. Minor gap: it does not tell the agent that returning json preserves the full structured zone/HR data that markdown may compress.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one optional parameter and schema description coverage is 100%, with the enum values fully documented in-schema, so the baseline of 3 applies. The description never mentions response_format or when to prefer json for structured zone data, adding no meaning beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Names a specific verb and resource ('Get the user's Garmin profile settings') and enumerates the exact scope: HR zones per sport and fitness age. That enumerated scope makes it unmistakable against siblings like garmin_get_daily_health or garmin_get_intraday, which cover time-series health data rather than configuration/zones.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives two concrete activation conditions: 'before interpreting heart rate data (to know the user's zones)' and 'when the user asks about their zones, max HR, lactate threshold or fitness age.' Clear and actionable, but no explicit exclusions or named alternative tools for overlapping questions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_get_sleepSleepARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| end_date | No | Defaults to today | |
| start_date | No | Local calendar date, yyyy-MM-dd | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive, so the bar is lower; the description adds that data comes from a local cache (implying possible staleness absent a sync), the per-call cap of 92 nights, and that JSON mode expands the payload with score components. It does not say what happens when the cache is empty or not yet synced.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two paragraphs, front-loaded with the verb and resource, then the return contents, then the date and volume rules. The long field list earns its place because there is no output schema to describe the payload.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly compensates by enumerating return fields and JSON extras, and it covers date semantics and volume limits. The one gap is cache-related behavior — what is returned when a night has not been synced — which matters given 'local cache' and the existence of garmin_sync.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3; the description goes beyond it by explaining the date-semantics convention (a night belongs to the wake-up date) and the 92-nights-per-call limit that constrains start_date/end_date. It also clarifies that response_format switches payload richness, adding meaning beyond the enum labels.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource ('Get nightly sleep from the local cache') and then enumerates exactly what data comes back (bed/wake time, sleep stages, score, respiration, stress). No sibling in the list covers sleep, and the field enumeration makes the scope unmistakable.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
'A night belongs to the date you woke up' plus the default window (last 14 nights) and the 92-night ceiling give the agent concrete calling context. It stops short of naming when to prefer a sibling (e.g., garmin_get_daily_health or garmin_get_hrv) for overlapping wellness questions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_get_womens_healthMenstrual cycleARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| date | No | Defaults to today | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint, idempotentHint and destructiveHint=false, lowering the bar. The description still adds genuine context: 'Fetched live from Garmin' (reinforces openWorld and warns of network dependence) and, more importantly, that it returns a clear 'not tracked' message when cycle tracking isn't set up — an empty-state behavior the annotations cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the resource and payload, then the empty-state caveat, then the default date. All sentences earn their place; the only slight redundancy is 'Defaults to today', which the schema also states.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
There is no output schema, so the description carries the return-value burden — and it discharges it by enumerating every field the call yields plus the not-tracked fallback. With two well-documented parameters and a safety profile already in annotations, an agent has everything needed to call this correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100% and the 'date' parameter already documents its default and pattern; the description's 'Defaults to today' and 'day view' merely restate that. The response_format enum is untouched in the description, so it adds essentially nothing beyond the structured schema. Baseline 3 is correct.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (Get) and a unique resource (menstrual cycle tracking), then enumerates exactly the fields returned: cycle day, phase, period/cycle length, predicted next cycle, fertile window, ovulation date, symptoms and notes. No sibling tool covers this domain, so it is trivially distinguishable from garmin_get_daily_health or garmin_get_body_composition.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The '(day view)' qualifier and 'Defaults to today' give the agent clear context for when this is the right call: a single date's cycle state. It stops short of naming alternatives or an explicit when-not, but no sibling overlaps enough to need that routing.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_list_activitiesList Garmin activitiesARead-onlyIdempotent
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:
"My runs this month" -> activity_type="running", start_date="2026-10-01"
"Longest rides ever" -> activity_type="cycling", sort_by="distance"
"Zwift sessions" -> activity_type="virtual_ride"
"Triathlon bike legs" -> include_multisport_legs=true, activity_type="road_biking"
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).
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum activities to return (1-100) | |
| offset | No | Number of activities to skip, for pagination | |
| search | No | Text to match in the activity name (case-insensitive) | |
| sort_by | No | Sort field | date |
| end_date | No | Only activities on or before this local date, yyyy-MM-dd | |
| sort_order | No | desc = newest/largest first | desc |
| start_date | No | Only activities on or after this local date, yyyy-MM-dd | |
| activity_type | No | Garmin activity type or parent type. Parent types include their subtypes: running (trail_running, treadmill_running, track_running, virtual_run), cycling (road_biking, virtual_ride, indoor_cycling, mountain_biking, gravel_cycling), swimming (lap_swimming, open_water_swimming), walking, hiking, multi_sport, fitness_equipment (strength_training, indoor_cardio, indoor_rowing), racket_sports, water_sports, other. | |
| max_distance_km | No | Maximum distance in km | |
| min_distance_km | No | Minimum distance in km | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
| max_duration_min | No | Maximum duration in minutes | |
| min_duration_min | No | Minimum duration in minutes | |
| include_multisport_legs | No | false (default): multisport activities appear once, as the parent. true: show their individual legs (swim/bike/run/transitions) instead of the parent, e.g. so triathlon bike legs count as cycling volume. Never double counts. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint/idempotentHint/destructiveHint=false, so the safety profile is covered. The description adds genuinely useful behavioral context beyond that: the data comes from a local cache that auto-refreshes when older than an hour, and results are paged with a total match count. It stops short of describing pagination semantics for the total (whether total reflects filters), which keeps it from a 5.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core capability and scope are front-loaded in the first sentence, and the examples and sibling pointer are clearly delineated. It is somewhat long, but each element (return fields, examples, cache note, sibling routing) carries distinct information.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a 14-parameter read tool with no output schema, the description lists the returned summary fields and states the JSON/markdown response distinction, plus the paging model. Combined with 100% schema coverage, an agent has everything needed to select and call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so the baseline is 3, but the description adds value: the examples demonstrate how activity_type, start_date, sort_by, and include_multisport_legs combine for real intents, and they clarify the parent-type expansion and the 'never double counts' behavior of multisport legs in a way the schema terse descriptions do not.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb (search/list) and resource (Garmin activities) with scope ('all history, from the local cache') and ordering ('newest first by default'). It also names the sibling garmin_get_activity as the tool for a single activity's full details, so an agent can distinguish the two without opening either schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides four concrete natural-language query examples mapped to specific parameter combinations, covering filtering by type/date, sorting, and multisport legs. It explicitly routes detail-seeking calls to garmin_get_activity and notes the cache-refresh condition that governs data freshness.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_queryQuery the Garmin cache with SQLARead-onlyIdempotent
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):
activities(id, parent_id, is_multisport_parent, type_key, sport, name, start_local, start_date, duration_s, moving_s, distance_m, elevation_gain_m, avg_speed_mps, avg_hr, max_hr, avg_power_w, norm_power_w, calories, aerobic_te, anaerobic_te, training_load, tss, vo2max) sport = Garmin parent type (running, cycling, swimming, walking, ...); type_key = exact type (road_biking, virtual_ride, lap_swimming, ...). Multisport: parent rows have is_multisport_parent=1, legs have parent_id; to count volume use is_multisport_parent = 0.
daily(date, steps, step_goal, walk_distance_m, floors_up, resting_hr, min_hr, max_hr, stress_avg, stress_max, stress_rest_pct, stress_low_pct, stress_medium_pct, stress_high_pct, body_battery_min, body_battery_max, body_battery_charged, body_battery_drained, intensity_moderate_min, intensity_vigorous_min, calories_total, calories_active, respiration_avg, hydration_ml)
sleep(date, start_local, end_local, sleep_s, deep_s, light_s, rem_s, awake_s, nap_s, score, quality, feedback, awake_count, respiration_avg, sleep_stress_avg) -- date = the morning you woke up
hrv(date, last_night_avg, last_night_5min_high, weekly_avg, baseline_low, baseline_high, status)
weight(date, weight_kg, bmi, body_fat_pct, body_water_pct, muscle_mass_kg, bone_mass_kg, visceral_fat, source, entries) Raw JSON (for fields not in the views, via json_extract):
activity(id, ..., raw_json) -- Garmin's full activity summary, e.g. json_extract(raw_json, '$.maxAvgPower_1200'), '$.hrTimeInZone_2', '$.fastestSplit_5000', '$.avgStrideLength'
daily_raw(domain, date, json) -- domains: daily_summaries, sleep, hrv, weight, body_battery, hrv_readings, heart_rate, spo2, food_logs Dates are 'yyyy-MM-dd' text in the user's local calendar; durations in seconds, distances in meters, speeds in m/s. SQLite dialect: strftime('%Y-%W', date) for weeks, date(date, '-7 days'), window functions (AVG(x) OVER (ORDER BY date ROWS 6 PRECEDING)) are supported.
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
| Name | Required | Description | Default |
|---|---|---|---|
| sql | Yes | A single SELECT or WITH query | |
| max_rows | No | ||
| response_format | No | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
The annotations already declare readOnlyHint, idempotentHint, closed-world, and non-destructive behavior, and the description adds important operational constraints: a single SELECT/WITH statement, max_rows default 200, and a 10-second timeout. It also explains date formats, units, SQLite dialect support, and how multisport records are structured, which materially helps correct invocation.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Despite its length, the description is front-loaded and well-structured: purpose first, then view definitions, raw JSON access, date/unit conventions, SQL dialect notes, rules, and an example. The column lists and example earn their place because they directly enable correct query construction.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
This is a complex SQL-query tool with no output schema and low schema description coverage, so the description must carry substantial context. It does so by documenting available views and columns, raw JSON escape hatches, date and unit semantics, SQL dialect features, execution limits, and an example query, leaving little ambiguity for an agent to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is only 33%, so the description carries most of the parameter burden. It explains the SQL parameter extensively and clarifies max_rows behavior and default, but it does not mention the response_format parameter or distinguish its json and markdown options.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description states a specific verb and resource: run one read-only SQLite query against the local Garmin cache. It also distinguishes this tool from its siblings by positioning it for analyses the other tools don't cover, such as custom aggregations, correlations, records, and cross-year comparisons.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description gives clear usage context: use it for analyses not covered by other tools, prefer the views first, and use raw JSON only for fields not in the views. It does not name specific sibling tools as alternatives, which keeps it just below fully explicit routing guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_recovery_trendsRecovery trendsARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| end_date | No | Defaults to today | |
| start_date | No | Local calendar date, yyyy-MM-dd | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive, openWorld), and the description adds real value beyond them: the response composition (status, flagged days, weekly averages, correlations with strength), the 180-day ceiling, and an honest statistical caveat about causation and noise. It stops short of describing pagination or how the 180-day limit is enforced when exceeded.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core purpose in the first clause, then return contents, caveats, and limits in a logical order. Two compact paragraphs with no filler; only the causation caveat slightly overlaps the noise warning.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
No output schema exists, so the description carries the full burden of describing returns — and it does so concretely (status comparators, flagged days, weekly averages, correlation pairs). For a read-only analytics tool with a fully documented 3-parameter schema, nothing material is missing.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so a baseline 3 applies, but the description genuinely adds meaning the schema lacks: the default range (last 8 weeks) and the maximum window (180 days), which govern how start_date/end_date should be chosen. The response_format enum is fully documented in the schema and needs no prose.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb+resource: 'Relate training load to recovery markers, day by day' with the exact metrics enumerated (resting HR, HRV, sleep score/duration, Body Battery, stress). The rolling-baseline and correlation framing clearly separates it from point-query siblings like garmin_get_hrv, garmin_get_sleep, and garmin_get_daily_health without needing to name them.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives clear operating context — defaults to the last 8 weeks, hard cap of 180 days, and warns that 'short periods give noisy results', which implicitly steers the agent toward longer windows. It does not explicitly say when to prefer point-query siblings over this trend view, so no exclusion guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_statusGarmin connection statusARead-onlyIdempotent
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.
| Name | Required | Description | Default |
|---|---|---|---|
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnly/idempotent/non-destructive/openWorld, so the safety profile is covered; the description adds the substantive behavior — this is a diagnostic that returns a configuration report rather than Garmin data, and it names the specific fields surfaced. With no output schema, spelling out the report contents is exactly the value the description should add.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loaded with the core action, followed by a compact inventory of reported fields, then the usage rule. Three short paragraphs, no filler, and each element adds information an agent would otherwise have to guess.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Covers purpose, return contents, and invocation triggers for a zero-required-param diagnostic, which is nearly everything needed. The one omission is failure semantics — whether a broken connection raises an error or is reported in the output — which matters for a tool whose whole job is checking health.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Only one optional parameter, response_format, and the schema documents it at 100% coverage including the markdown/json enum and default. The description says nothing about it, but the schema already does the work, so the baseline 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: verify the Garmin Personal API connection and report its configuration, then enumerates exactly what is reported (key source, token/expiry, key expiry, time zone, server version). That is far more concrete than the sibling getters. It does not explicitly distinguish itself from garmin_sync_status, which is the one sibling an agent could plausibly confuse it with.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Gives two explicit trigger conditions: call it first after any garmin_* tool fails with an auth error, or when the user asks whether the connection is set up. That is clear when-to-use guidance with a real diagnostic role. It stops short of a when-not-to-use clause or naming garmin_sync_status as the alternative for sync-state questions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_syncSync Garmin dataAIdempotent
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:
fetch the latest data right now (e.g. "I just finished a run"),
extend history further back (from="2019-01-01"),
re-download everything (mode="full"), e.g. after editing many activities in Garmin Connect.
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.
| Name | Required | Description | Default |
|---|---|---|---|
| from | No | Extend history back to this date (yyyy-MM-dd). History starts at your first activity by default; an earlier date fetches older wellness data. A later date has no effect: history is never narrowed. | |
| mode | No | auto: new data plus any history still missing. full: forget what's cached and re-download. | auto |
| domains | No | Only sync these domains. Defaults to all except "fit_files". |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Goes well beyond the annotations: it discloses the fire-and-forget async behavior, the cache-side effect of mode='full' ('forget what's cached'), and the throughput cost of fit_files (~2 activities/s, one request per activity). Annotations only carry the safety profile (readOnly=false, idempotent=true); the description supplies the operational semantics they cannot express.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Front-loads the async/cache contract, then uses a tight bullet list for the when-to-use cases and a short paragraph for domains. Slightly long, but every sentence (including the fit_files cost note) carries information an agent needs.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description correctly explains the return contract (returns immediately, no result payload) and routes the agent to garmin_sync_status for results. Combined with 100% param coverage and annotations, nothing material is missing for correct invocation.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 100%, so baseline is 3, but the description adds real value by giving scenario-anchored examples ('from="2019-01-01"', 'mode="full" after editing many activities') and by spelling out the default domain set. It stops short of listing every domain's effect, which the schema enum already covers.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
Specific verb + resource + destination: 'Start downloading Garmin data into the local cache.' It also states the asynchronous contract up front ('Runs in the background and returns immediately'), which distinguishes it from every read-only getter sibling.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Explicitly says 'You rarely need this' because other tools sync automatically, then enumerates the three concrete cases where it is needed (fresh data, extending history, full re-download). It also names garmin_sync_status as the progress-tracking alternative.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_sync_statusGarmin sync statusARead-only
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.
| Name | Required | Description | Default |
|---|---|---|---|
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already declare readOnlyHint=true, destructiveHint=false and openWorldHint=false, so the safety profile is covered. The description adds real content beyond that: it enumerates headers such as per-domain date range, day counts, all-history flags and last successful sync, and mentions error reporting. It stops short of saying how partial or failed syncs are represented.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two short sentences, front-loaded with what is shown, followed by a compact enumeration of returns. Every clause carries information, though the 'Returns:' block is a dense run-on that could be structured more crisply.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description carries the burden of describing return values, and it does so across sync-level and per-domain detail. It is only slightly incomplete in omitting the response_format choice and how a failed or never-run sync is reported.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100% with a single optional response_format enum, so the schema already documents the only parameter fully. The description adds nothing about format selection, so the baseline of 3 applies.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
States a specific verb and resource: it shows the contents of the local Garmin cache plus the progress of the current or last sync. That is clear enough to act on, but the description never distinguishes this from the close sibling garmin_status or from garmin_sync, which an agent could plausibly pick instead.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Usage is only implied: an agent can infer this is the tool to call before or after garmin_sync to check coverage and errors, but the description never says when to use it, when not to, or which sibling it replaces. No prerequisites or exclusions are given.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
garmin_training_summaryTraining summaryARead-onlyIdempotent
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).
| Name | Required | Description | Default |
|---|---|---|---|
| sport | No | Only this sport (parent type) or activity type | |
| end_date | No | Defaults to today | |
| group_by | No | week | |
| start_date | No | Local calendar date, yyyy-MM-dd | |
| response_format | No | 'markdown' for readable text (default), 'json' for complete structured data | markdown |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
Annotations already cover the safety profile (readOnly, idempotent, non-destructive), and the description goes well beyond them: it defines intensity zones (low = HR 1–2, moderate = 3, high = 4–5), explains CTL/ATL/TSB/ACWR semantics with the ~1.5 risk threshold, and discloses how missing Garmin load is estimated (Banister TRIMP scaled to the user's own activities) plus that the response reports the estimated share.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The core deliverable is front-loaded in the first sentence and the remaining paragraphs cover estimation caveats and defaults, each earning its place. It is on the longer side and the zone/ACWR detail is dense, but not padded with filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
With no output schema, the description must convey what comes back, and it does: metrics per period, intensity distribution with a pattern classification, and the load trend block. Defaults, filtering, multisport/walking handling, and the estimation caveat cover everything needed to call it correctly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema coverage is 80%, so the schema carries most parameter meaning and baseline is 3. The description adds real value on top: it clarifies the sport filter accepts either a parent type or an activity type (e.g. virtual_ride), and that week/month grouping defaults to week over the last 12 weeks.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description names a specific verb (summarize) and a precisely scoped resource: per-week/per-month aggregates of sessions, hours, distance, elevation, load, intensity distribution and load trend. The aggregation scope makes it immediately distinguishable from per-activity siblings like garmin_get_activity or garmin_list_activities without opening those schemas.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
It gives concrete operating context: defaults to the last 12 weeks grouped by week, and filtering is done via sport (with examples such as running, cycling, or a type like virtual_ride). It does not state when to prefer garmin_query, garmin_recovery_trends, or per-activity tools instead, so there are no explicit alternatives or exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
21 tool updates
v0.5.0- First observed
garmin_analyze_activity - First observed
garmin_compare_activities - First observed
garmin_download_activity_fit - First observed
garmin_get_activity - First observed
garmin_get_activity_laps - First observed
garmin_get_activity_streams - First observed
garmin_get_body_composition - First observed
garmin_get_daily_health - First observed
garmin_get_hrv - First observed
garmin_get_intraday - First observed
garmin_get_nutrition - First observed
garmin_get_profile - First observed
garmin_get_sleep - First observed
garmin_get_womens_health - First observed
garmin_list_activities - First observed
garmin_query - First observed
garmin_recovery_trends - First observed
garmin_status - First observed
garmin_sync - First observed
garmin_sync_status - First observed
garmin_training_summary
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.
Related MCP Connectors
Your Garmin, Oura, WHOOP, Hevy and 35 more fitness apps, queryable from your own AI.
Ask your AI about your fitness: activities and data from Garmin, COROS, Strava, GPX and more
AI coach for Garmin: builds training plans and structured workouts, synced straight to your watch.
Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceEnables AI assistants to access and query Garmin Connect health and fitness data, including sleep, HRV, training load, and activities, with an optional coaching plugin for personalized training plans.6 npm4-
- FlicenseNot gradedqualityDmaintenanceExposes Garmin Connect data and workout management to AI agents, supporting tools, resources, and prompts for health data, workout creation, and coaching workflows.1-
- FlicenseNot gradedqualityAmaintenanceEnables AI assistants to retrieve and analyze Garmin Connect health data, including daily summaries, sleep, HRV, workouts, and raw FIT files, while also supporting SQL queries on the underlying database.8-
- AlicenseNot gradedqualityBmaintenanceEnables reading and analyzing Garmin Connect data—activities, health metrics, FIT files, and challenges—through natural language, for AI assistants like Claude and ChatGPT.MIT