garmin-mcp-bridge
Allows reading Garmin training data (activities, wellness, heart rate, sleep, etc.) and creating structured workouts that sync to a Garmin watch via Intervals.icu.
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., "@garmin-mcp-bridgeshow my last week's activities with load"
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.
garmin-mcp-bridge
Bring your Garmin training data into Claude — and push structured workouts back to your watch.
Garmin has no public API for individuals. Their Connect Developer API is gated behind a partner agreement, and the unofficial scraping libraries break whenever Garmin changes something. This bridges the gap through Intervals.icu, which syncs with Garmin Connect in both directions and offers a documented API with a plain API key.
Garmin watch ──► Garmin Connect ──► Intervals.icu ──► this MCP server ──► Claude
▲ │
└────────── planned workouts ◄───────────────────────┘Free, runs locally, no third-party service holding your data. Intervals.icu is free to use (donation-supported).
What you get
Nine tools your MCP client can call:
Tool | What it does |
| Verify the API key, report rate limit headroom |
| Thresholds, HR/pace/power zones, FTP, weight |
| Activities in a date range, with totals for time, distance, elevation and load |
| One session in detail, including detected intervals |
| Time series (HR, altitude, pace, gradient, cadence), downsampled |
| HRV, resting HR, sleep, weight, CTL/ATL, plus computed baselines |
| Calendar: planned sessions, notes, races |
| Create a structured workout → syncs to your watch |
| Remove a calendar entry |
Then ask things like "compare my last four weeks of load to the block before", "was my easy pace drifting?", or "build tomorrow's threshold session and put it on my watch".
Related MCP server: intervals.icu MCP Server
Requirements
An MCP client. Claude Desktop is the reference; anything speaking MCP works.
A Garmin Connect account with activities in it.
An Intervals.icu account (free).
Python 3.10+. The installer sets this up via uv if you do not have it.
Setup
1. Create an Intervals.icu account
Sign up at intervals.icu/signup. You can log in with Strava, Google, or email.
2. Connect Garmin
In Settings → Connections, find the Garmin Connect card and authorise it. Make sure these are ticked:
Download activities
Download wellness data — HRV, sleep, resting HR
Upload planned workouts — required if you want workouts to reach your watch
3. Run the backfill
This is the step people miss. Garmin only pushes new activities from the moment you connect. Your history does not arrive on its own.
On the same Garmin card, click Download old data — once under Download activities and again under Download wellness data. They are separate. Pick a start date far enough back to cover the training you care about.
Give it a few minutes. If nothing arrives after an hour, the connection itself is the problem: disconnect on both sides — in Intervals.icu and in Garmin Connect under Account Settings → Connected Apps — then reconnect.
4. Get your API key
Settings → Developer Settings (bottom of the page) → generate a key.
This key grants full access to your Intervals.icu data. Treat it like a password.
5. Install
git clone https://github.com/jonas-theobald/garmin-mcp-bridge.git
cd garmin-mcp-bridgemacOS / Linux
./scripts/install.shWindows
powershell -ExecutionPolicy Bypass -File .\scripts\install.ps1The installer checks for uv, builds the environment, asks for your API key, runs the full selftest against the live API, and registers the server with Claude Desktop — backing up your existing config first.
6. Restart your client
Quit Claude Desktop completely (Cmd+Q on macOS, tray icon → Quit on Windows) and start it again. It only reads the MCP config at startup.
Then ask: "Call check_connection."
Manual install
If you would rather not run a script:
uv sync
INTERVALS_API_KEY=your_key uv run selftest.pySetting the key locally without typing it inline every time: copy .env.example to .env and fill in your key — .env is gitignored, so it never gets committed. uv run picks it up with --env-file:
cp .env.example .env
# edit .env, set INTERVALS_API_KEY
uv run --env-file .env selftest.pyThis keeps the key out of your shell history and out of the client config below — useful for local testing. It is separate from the client config's env block, which the MCP client needs regardless (see Keeping the key out of the config for avoiding plaintext there too).
Then add this to your client's config file:
OS | Path |
macOS |
|
Windows |
|
Linux |
|
{
"mcpServers": {
"garmin": {
"command": "/absolute/path/to/garmin-mcp-bridge/.venv/bin/python",
"args": ["-m", "garmin_mcp_bridge.server"],
"env": {
"INTERVALS_API_KEY": "your_key"
}
}
}
}Use an absolute path to the interpreter inside .venv, not uv run. The client starts the server without your shell environment, so uv will not be on its PATH. On Windows the interpreter is at .venv\Scripts\python.exe.
If the file already has other settings, merge this in rather than replacing it — and mind the commas. Invalid JSON is ignored silently, which looks exactly like the server failing to start.
Verifying it works
The selftest exercises every read path plus, with --write, the workout creation path:
INTERVALS_API_KEY=your_key uv run selftest.py --writePASS auth + athlete profile athlete i123456 (Your Name)
PASS sport settings / zones LTHR=172 maxHR=190 zones=7
PASS list activities (30d) 15 activities, newest: TrailRun 2026-07-18T06:59:59
PASS activity detail + intervals Race — 49 intervals
PASS activity streams streams: {'heartrate': 37292, 'altitude': 37292}
PASS wellness (HRV/sleep/RHR) 31 days, 27 with HRV
PASS calendar events 0 planned events in next 30d
PASS create + delete planned workout created+deleted, 3 steps parsedTo check the config and server as your client will actually launch them:
python3 - <<'EOF'
import json, os, subprocess
path = os.path.expanduser("~/Library/Application Support/Claude/claude_desktop_config.json")
srv = json.load(open(path))["mcpServers"]["garmin"]
msgs = [
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{
"protocolVersion":"2024-11-05","capabilities":{},
"clientInfo":{"name":"verify","version":"1"}}},
{"jsonrpc":"2.0","method":"notifications/initialized"},
{"jsonrpc":"2.0","id":2,"method":"tools/list"},
]
proc = subprocess.run([srv["command"], *srv["args"]],
input="".join(json.dumps(m)+"\n" for m in msgs),
capture_output=True, text=True,
env={**os.environ, **srv.get("env", {})}, timeout=30)
for line in proc.stdout.splitlines():
try: msg = json.loads(line)
except ValueError: continue
if msg.get("id") == 2:
print("OK —", len(msg["result"]["tools"]), "tools")
break
else:
print("FAILED\n", proc.stdout[:500], "\n", proc.stderr[:1000])
EOFWriting workouts
create_planned_workout takes a description in Intervals.icu's native workout syntax:
- 15m Z2 Warmup
3x
- 8m Z4
- 3m Z1
- 10m Z1 CooldownOne step per line, prefixed - . A bare Nx line starts a repeat block covering the steps up to the next blank line. Durations use s, m, h. Targets can be zones (Z2), percentages of threshold (75-82%), absolute heart rates (150-160bpm), or paces (5:30/km).
Set target to HR, PACE or POWER. For trail and hiking, use HR — pace means nothing on a 25% gradient.
The workout_doc trap
Never include a workout_doc field in the payload.
A planned workout only syncs to your watch if Intervals.icu parsed the description into structured steps. What triggers that parsing is undocumented, and the intuitive guess is wrong: sending workout_doc: {} to request parsing actually suppresses it. The server reads the presence of the field as "steps already supplied" and skips the parser. The workout lands in the calendar unstructured and never reaches the watch.
Measured against the live API — every case below sent workout_doc: {} except the last:
Payload | Result |
single endpoint / Run / zones / HR | not parsed |
bulk endpoint / Run / zones / HR | not parsed |
single / Run / % of LTHR / HR | not parsed |
single / Run / absolute bpm / HR | not parsed |
single / Run / pace / PACE | not parsed |
single / Ride / % of FTP / POWER | not parsed |
single / Run / zones / HR, no | parsed — 3 steps, 1380s |
With the field omitted, parsing works across both endpoints, both sports tested, and zone, percentage, bpm and pace syntax alike.
This server omits it and reports back after every write:
parsed_steps— how many steps the server recognisedgarmin_sync_likely—falsewhen nothing parsed
If you get false, open the workout in the Intervals.icu web app and save it — that forces parsing — then check your description syntax.
Troubleshooting
Tools do not appear in the client. The config is only read at startup; quit fully and relaunch. Then check the file is valid JSON (python3 -m json.tool <path>) and that the command path exists. Invalid JSON is ignored without an error message.
401 Unauthorized. The key was regenerated or copied incompletely. Get a fresh one from Developer Settings.
Zero activities. The backfill has not run — see step 3. Wellness and activities backfill separately.
Sporadic 403s. Intervals.icu sits behind Cloudflare, which challenges default library user agents. The client sends a browser-like User-Agent for this reason; do not remove it.
429 Rate limited. 5000 requests per day, 2500 per rolling 15 minutes, 10 per second per IP. Effectively unreachable in personal use. The client waits out short backoffs and surfaces longer ones as errors rather than hanging.
Planned load is empty for runs. Intervals.icu computes planned training load for power-based workouts but not for HR-based runs. Pass training_load explicitly if you want future CTL projections to be meaningful.
Keeping the key out of the config
The installer writes your API key in plain text into the client config. That is normal for MCP servers, but if you would rather not:
macOS — store it in the Keychain:
security add-generic-password -a "$USER" -s intervals-icu -w "your_key"Then point command at a wrapper script (chmod +x it) and drop the env block:
#!/bin/bash
export INTERVALS_API_KEY=$(security find-generic-password -a "$USER" -s intervals-icu -w)
exec /absolute/path/to/.venv/bin/python -m garmin_mcp_bridge.serverWindows — the same pattern works with a .cmd wrapper reading from Credential Manager via cmdkey.
Design notes
Streams are downsampled. A three hour trail run is over 10,000 samples per stream. The tool returns min, max and mean computed from the raw data, plus a series block-averaged to roughly 200 points. The shape is what informs coaching; every individual sample just burns context.
Fields are filtered. A raw activity payload carries 200+ fields, most of them cycling power metrics. The tools return a curated subset. If you need something that is missing, add it to _ACTIVITY_FIELDS in server.py.
Transport is separate from logic. client.py has no MCP dependency. Moving this to an HTTP/SSE server — say, on a Raspberry Pi so a webhook can react to every upload — means replacing server.py only.
Why not run it on a Pi today? A stdio server is launched as a subprocess by the client, so it must live on the same machine. Remote hosting means HTTP transport, an auth layer, and TLS, for no benefit while the client only runs on your desktop anyway.
Sources
The undocumented behaviour above was established empirically against the live API. The documented parts:
API access to Intervals.icu — auth, rate limits, the Cloudflare note
Uploading planned workouts — event payloads
API Integration Cookbook — wellness, activities, webhooks
License
MIT. See LICENSE.
Not affiliated with Garmin or Intervals.icu.
Available Tools
9 toolscheck_connectionA
Verify the API key works and report rate limit headroom.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of explaining behavior. It discloses that the tool tests the API key and returns rate limit headroom, implying a read-only, non-destructive operation. It does not detail error responses or output structure, but for a zero-parameter health check, the essential behavior is transparent.
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 a single focused sentence with no filler. It front-loads the core action ('verify the API key works') and the secondary result ('report rate limit headroom'), earning its place entirely.
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 zero-parameter tool with no output schema, the description provides the core purpose and the key output concept. It lacks explicit return field names or failure behavior, but for a simple connection check the description is sufficiently complete.
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 input schema has zero properties, so there are no parameters to document. Achieves the baseline 4 for a zero-parameter tool since no parameter description is needed.
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 ('verify'), a resource ('API key'), and the outcome ('report rate limit headroom'). This clearly distinguishes it from sibling tools like list_activities or get_athlete_profile, which concern data retrieval rather than connection status.
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 implies the tool is for checking API connectivity and rate limits, which is distinct from all siblings. There is no explicit 'use when' or alternative routing, but the unique purpose provides clear context without needing exclusions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
create_planned_workoutA
Create a structured planned workout on the Intervals.icu calendar.
Intervals.icu syncs planned workouts to a connected Garmin Connect account, so this is the path for getting a session onto the watch. See the README caveat: confirm the first workout actually reaches Garmin before relying on this in a training block.
Args: start_date: Local date YYYY-MM-DD. Time is forced to 00:00:00, which the API requires for calendar events. name: Short session title, e.g. "3x8min Schwelle". description: Workout in Intervals.icu syntax (see below). activity_type: "Run", "Ride", "Hike", "WeightTraining", "Swim". moving_time: Total duration in seconds. Optional; Intervals.icu derives it from the parsed description. target: "HR", "PACE" or "POWER". Use "HR" for trail and hiking work where pace is meaningless on steep terrain. training_load: Optional manual load override. external_id: Stable id of your own. Reusing it with the same date makes the call idempotent, so a re-planned week updates instead of duplicating.
Workout syntax — one step per line, prefixed "- ":
- 15m Z2 Warmup
3x
- 8m Z4
- 3m Z1
- 10m Z1 CooldownA bare "Nx" line on its own starts a repeated block; the following steps until the next blank line are repeated. Durations use m/s/h. Targets can be zones ("Z2"), ranges of threshold ("75-82%"), or free text for steps with no measurable target. Blank lines separate blocks.
| Name | Required | Description | Default |
|---|---|---|---|
| name | Yes | ||
| target | No | HR | |
| start_date | Yes | ||
| description | Yes | ||
| external_id | No | ||
| moving_time | No | ||
| activity_type | No | Run | |
| training_load | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations present, the description carries the full behavioral burden and does so thoroughly: it discloses the Garmin side-effect, idempotent behavior when external_id is reused, forced 00:00:00 start time, and optional moving_time derivation. This goes well beyond the bare schema and helps the agent anticipate real-world consequences.
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 long but tightly organized into a purpose paragraph, a compact Args list, and a syntax example with rules. Every section adds operational knowledge an agent needs, so the length is justified rather than bloated.
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 parameter-heavy creation tool with no output schema and no annotations, this is essentially complete: it covers all inputs, the domain-specific syntax, idempotency, and a real-world caveat. The only omission is a description of the return payload, but that is not required 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 description coverage is 0%, yet the Args section explains all eight parameters with formats, defaults, and reasoning, and the workout-syntax block gives essential semantics for the free-form description parameter. The description fully compensates for the schema's lack of parameter documentation.
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 line names the exact action ('create'), the resource ('structured planned workout'), and the target system ('Intervals.icu calendar'), and the Garmin sync clause separates it from the read/list/delete siblings. This is a specific verb+resource statement, not a tautology or vague paraphrase.
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 first paragraph explicitly frames the tool as the path for getting a session onto a Garmin watch and warns to verify the first sync before relying on it in a training block. It gives clear situational context and even a target-selection rule ('Use HR for trail and hiking work'), though it does not name alternative tools or state an explicit when-not-to-use condition.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
delete_planned_workoutB
Delete a calendar event by its numeric id (from list_planned_workouts).
| Name | Required | Description | Default |
|---|---|---|---|
| event_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It states the action (delete) but does not disclose whether deletion is permanent, reversible, or requires confirmation, nor what happens to associated data. For a destructive operation with zero annotation coverage, this is a significant gap.
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 a single sentence with no wasted words. It front-loads the action and resource, then provides the key parameter source. Every word earns its place.
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 simple one-parameter delete tool, the description is mostly complete: it names the action, the resource, and where to get the id. However, it lacks any mention of return behavior or error conditions, and with no annotations or output schema, an agent cannot know what to expect after a successful deletion.
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 0%, so the description must compensate. It adds meaning by specifying that event_id is a 'numeric id' and that it comes from list_planned_workouts, which is helpful. However, it does not explain the format, range, or any constraints beyond the schema's integer type.
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 ('Delete') and resource ('a calendar event'), and identifies the id source ('from list_planned_workouts'), which distinguishes it from sibling tools like create_planned_workout and list_planned_workouts. It is clear but does not explicitly name sibling alternatives.
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 implies usage context by referencing list_planned_workouts as the source of the id, which tells the agent where to get the required parameter. However, it does not explicitly state when to use this tool versus alternatives or mention any prerequisites or consequences.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_activityA
Get one activity in detail, optionally with detected intervals/laps.
Use for post-session analysis: how each interval actually went, HR drift, and where elevation was gained. Activity ids look like "i55751783".
| Name | Required | Description | Default |
|---|---|---|---|
| activity_id | Yes | ||
| include_intervals | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description must carry behavioral disclosure. It reveals that the tool returns detailed activity data and optionally detected intervals/laps, and it gives an id format hint. However, it does not describe response structure, errors, or access requirements, which would matter without an output schema.
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 concise sentences with no filler: the first states the action, the second gives the usage context, and the third provides an id format example. Every sentence earns its place.
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 two-parameter read tool, the description covers core purpose and parameters well. But with no output schema and no annotations, it leaves the return shape unspecified and doesn't point to list_activities for finding activity ids, which is a meaningful gap.
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 0%, but the description compensates by explaining activity_id format with the example 'i55751783' and clarifying include_intervals as toggling detected intervals/laps. Both parameters receive meaningful semantic context beyond their bare schema definitions.
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?
Description names a specific verb and resource: 'Get one activity in detail' with optional 'detected intervals/laps.' This clearly distinguishes it from list_activities and get_activity_streams, and the mention of post-session analysis adds purpose beyond a generic fetch.
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 explicitly says to use this for post-session analysis and gives concrete examples: how intervals went, HR drift, and elevation gained. It doesn't name alternatives or exclusion conditions, but the intended context is clear.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_activity_streamsA
Get time-series streams for an activity, downsampled to ~200 points each.
Args: activity_id: e.g. "i55751783". types: Stream names. Defaults to heartrate, altitude, velocity_smooth, distance, cadence, grade_smooth. Others: watts, temp, latlng, time, moving, fixed_watts.
Returns min/max/mean plus a downsampled series per stream. Full per-second data is deliberately not returned: a long trail run is >10k samples per stream and the shape is what matters for coaching, not every sample.
| Name | Required | Description | Default |
|---|---|---|---|
| types | No | ||
| activity_id | Yes |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden and does so unusually well. It discloses downsampling to ~200 points, the return of min/max/mean per stream, and the deliberate non-return of full per-second data with a concrete rationale. This gives an agent accurate expectations about output shape and data volume.
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 layout is clear: purpose sentence, Args section, then Returns section. The explanation about coaching shape is slightly editorial but earns its place by clarifying why the data is truncated.
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?
Given only two parameters and no output schema, the description covers input format, defaults, valid options, output summary, and a key limitation. Nothing critical is missing for an agent to invoke 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 0%, so the description must compensate, and it does. It provides a concrete example for activity_id and enumerates valid stream names with defaults and alternatives, giving an agent everything needed to construct valid arguments.
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 time-series streams for an activity') plus the downsampling qualifier. It is distinct enough from siblings like get_activity, but it does not explicitly name or contrast any sibling, so it falls just short of full differentiation.
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 helpful context about default stream types and explains why full per-second data is intentionally omitted, which implies when the tool is appropriate. However, it never explicitly says when to prefer this tool over get_activity or another sibling, nor does it provide any exclusion criteria.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_athlete_profileA
Get athlete profile: thresholds, HR/pace zones, FTP, weight, sport settings.
Call this first in a coaching session. Zone boundaries are needed to interpret every other number, and to write workouts with correct targets.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the behavioral disclosure burden. It conveys that this is a retrieval-style call and adds useful context about zone boundaries being prerequisites, but it does not describe return shape, authentication needs, or edge-case behavior. This is adequate for a simple getter but not rich.
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, front-loaded sentences: the first enumerates the payload, the second gives actionable sequencing rationale. No filler or repetition.
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 zero-parameter retrieval tool, the description covers what is returned and when to call it. It lacks an explicit return-format statement, and there is no output schema or annotations to fill that gap, but the field list and sequencing guidance are sufficient 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?
The tool has zero parameters and schema coverage is 100%, so there is nothing the description needs to add about arguments. The zero-parameter baseline of 4 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?
The description names a specific verb ('Get') and resource ('athlete profile') and lists distinctive contents: thresholds, HR/pace zones, FTP, weight, sport settings. This clearly distinguishes it from activity/workout-focused 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?
It explicitly instructs to call this first in a coaching session and explains why zone boundaries are needed to interpret other numbers and write workouts. This gives strong contextual guidance, though it does not explicitly name alternative tools or when not to use it.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
get_wellnessA
Get daily wellness: HRV, resting HR, sleep, weight, CTL/ATL, soreness.
This is the autoregulation input. Check it before prescribing a hard session, and compare HRV and resting HR against the athlete's own recent baseline rather than population norms.
| Name | Required | Description | Default |
|---|---|---|---|
| newest | No | ||
| oldest | No | ||
| days_back | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the burden of explaining behavior. It states the kind of data returned and frames it as baseline-relative, which is useful. However, it doesn't disclose return format, units, missing-data behavior, or date-range semantics, leaving some behavioral gaps.
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 compact and front-loaded: the first sentence states exactly what the tool returns, and the second provides actionable usage guidance. Every sentence earns its place with no filler or repetition.
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?
The description is helpful for understanding the tool's role, but it is incomplete for correct invocation: it fails to explain how the date-range parameters work, what the default behavior is, or what the response structure looks like. Since there is no output schema and no annotations, these gaps matter.
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 0%, and the description makes no mention of the three parameters (newest, oldest, days_back). It doesn't explain how to specify date ranges or how days_back interacts with the other parameters, so the description provides no added meaning beyond the bare schema names and defaults.
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 opens with a specific verb and resource ('Get daily wellness') and enumerates the concrete metrics returned (HRV, resting HR, sleep, weight, CTL/ATL, soreness). This clearly differentiates it from sibling tools focused on activities, workouts, and athlete profile.
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 explicitly identifies this as the autoregulation input and directs the agent to check it before prescribing a hard session, and to compare HRV/resting HR against the athlete's own recent baseline. It gives clear context for when to use it, though it doesn't mention alternatives or explicit when-not-to-use conditions.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_activitiesA
List completed activities with training load, HR and elevation.
Args:
oldest: Start date YYYY-MM-DD. Defaults to days_back before today.
newest: End date YYYY-MM-DD (inclusive). Defaults to today.
days_back: Used only when explicit dates are omitted.
activity_type: Optional filter, e.g. "Run", "Ride", "Hike",
"WeightTraining". Matched case-insensitively.
| Name | Required | Description | Default |
|---|---|---|---|
| newest | No | ||
| oldest | No | ||
| days_back | No | ||
| activity_type | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
No annotations are provided, so the description carries the full burden of behavioral disclosure. It does state that only completed activities are listed and what metrics are included, but it omits read-only safety, pagination, ordering, and behavior when no activities match. For a list operation with zero annotation coverage, this is a significant gap.
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 first sentence front-loads the tool's purpose, and the Args block is compact with each line adding necessary semantics. There is no filler or repetition, and the structure makes parameters easy to scan.
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 tool with four optional parameters and no output schema, the description covers all inputs and states what data will be returned (training load, HR, elevation). It omits ordering and pagination details, but these are minor for an agent deciding whether and how to invoke this 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 0%, but the description fully compensates: it defines the date format (YYYY-MM-DD), the inclusive semantics of newest, the default of oldest relative to days_back, the condition for days_back being used, and activity_type as a case-insensitive filter with examples. Every parameter is given meaningful documentation.
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 opens with 'List completed activities with training load, HR and elevation', which states a specific verb and resource. The word 'completed' distinguishes it from list_planned_workouts, and the enumerated metrics clarify what the tool returns. It does not explicitly name siblings, so it stops short of full differentiation.
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 implies usage for fetching historical activity data and documents defaults and filters, but it never explicitly states when to prefer this tool over get_activity or list_planned_workouts. No alternatives or exclusion conditions are named.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
list_planned_workoutsA
List calendar events: planned workouts, notes and races.
Use before writing a new week so existing plan entries are not duplicated.
Every event id returned here can be passed to delete_planned_workout.
| Name | Required | Description | Default |
|---|---|---|---|
| newest | No | ||
| oldest | No | ||
| days_ahead | No |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the behavioral burden. It communicates a read-style operation ('List') and adds a useful integration detail: event IDs can be passed to delete_planned_workout. However, it does not disclose time-window behavior, defaults, or the response structure.
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: what the tool does, when to use it, and how results connect to another tool. No filler, and the core behavior is front-loaded.
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?
The description gives a clear use case and an integration hint, making a default zero-argument call viable. However, three parameters are undocumented and there is no output schema, so an agent wanting to customize the time window or understand the full return payload is left without guidance.
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 0% and the description adds no meaning for newest, oldest, or days_ahead. An agent cannot tell from the description what date formats or semantics these parameters expect, so the description fails to compensate for the schema gap.
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: 'List calendar events' and enumerates the content (planned workouts, notes, races). This clearly distinguishes it from siblings like list_activities, which concern a different kind of data.
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 explicit guidance: 'Use before writing a new week so existing plan entries are not duplicated.' This tells an agent when to call it. It does not explicitly contrast with list_activities or state when not to use it, so it stops short of a full 5.
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.
9 tool updates
v0.1.0- First observed
check_connection - First observed
create_planned_workout - First observed
delete_planned_workout - First observed
get_activity - First observed
get_activity_streams - First observed
get_athlete_profile - First observed
get_wellness - First observed
list_activities - First observed
list_planned_workouts
TDQS
Scored across 9 tools
Each tool targets a distinct resource and action: connection health, athlete profile, completed activities (list/detail/streams), daily wellness, and planned workouts (list/create/delete). The list/get/stream progression for activities is clear, and completed vs. planned activities are explicitly separated.
All tool names follow a consistent verb_noun snake_case pattern: get_* for singular resources, list_* for collections, create_/delete_* for mutations, and check_connection for the operational check. There is no mixing of naming conventions or vague verbs.
Nine tools is well within the ideal 3-15 range and each serves a distinct step in the coaching workflow: connection check, profile setup, activity review, wellness monitoring, and workout planning. No tool feels redundant or like padding.
The surface covers a full coaching loop: read athlete profile, review completed activities with detail and streams, check wellness/autoregulation, and manage planned workouts through list/create/delete. The idempotent create via external_id effectively covers updates, and delete is explicitly wired to list output.
Maintenance
Related MCP Connectors
Connect Claude to your Intervals.icu watch data for fitness, workout review, and plan writing.
Garmin data in Claude: 135 tools — activities, sleep, HRV, training, workouts. Free, open source.
Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.
- Coach MCPOAuthai.iamcoach
Your endurance training data in your AI assistant: activities, recovery, plan, workout edits.
Related MCP Servers
- AlicenseAqualityCmaintenanceConnects Claude with the Intervals.icu API to retrieve fitness data including activities, workouts, wellness metrics, and training events.10359GPL 3.0
- AlicenseNot gradedqualityCmaintenanceEnables Claude AI to access and manage intervals.icu training data, including workouts, wellness, and fitness trends, through natural language conversation.MIT
- AlicenseNot gradedqualityBmaintenanceConnects to Intervals.icu to let users query training data, create workouts, manage calendar events, and coach athletes through natural language in Claude Desktop.21 npmMIT
- AlicenseAqualityCmaintenanceEnables Claude and ChatGPT to retrieve and manage activities, intervals, events, wellness data, power curves, and custom items through the Intervals.icu API.21GPL 3.0