# Futureweb Intervals MCP (pypi · futureweb-intervals-mcp)

Self-hosted Intervals.icu MCP server: training analytics, Garmin data, wellness, workout planning

- Trust score: 71/100 (medium)
- Change this week: +4
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-10-23

## Components

- oci · `ghcr.io/futureweb/intervals-mcp-server`: 45/100, [markdown](https://verifymcp.io/servers/futureweb-intervals-mcp-server/ghcr-io-futureweb-intervals-mcp-server.md), [page](https://verifymcp.io/servers/futureweb-intervals-mcp-server/ghcr-io-futureweb-intervals-mcp-server)
- pypi · `futureweb-intervals-mcp`: 71/100 (this document), [markdown](https://verifymcp.io/servers/futureweb-intervals-mcp-server/futureweb-intervals-mcp.md), [page](https://verifymcp.io/servers/futureweb-intervals-mcp-server/futureweb-intervals-mcp)

## Channel facts

- Registry: `pypi`
- Package: `futureweb-intervals-mcp`
- Version: `1.0.0b2`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-10-23.

- **Supply Chain Security**: 50/100
  - Malware scan not yet available for this package.
  - No known CVEs affecting this package version or its production dependencies.
  - Runs hatchling.build at install time, a recognised build step with no custom scripting around it.
  - 0 of 32 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 100/100
  - Source repository is publicly reachable at the declared URL.
  - Cryptographically verified build provenance (signed, bound to futureweb/intervals-mcp-server).
  - Clear OSI-approved license (GPL-3.0-only).
  - Actively maintained (last published 7 days ago).
  - Publishes a security disclosure policy (SECURITY.md).
- **Schema Quality & AI Usability**: 74/100
  - 100% of prompts and resources have a non-trivial description (not blank, and not just the item's name).
  - AI-judged instruction clarity (good).
  - Context-footprint check failed: tool/resource definitions use about 16210 tokens (~241/item across 67 items; 52 tools + 15 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 30/100
  - Stability observed for 9 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
- **Tool Safety**: 100/100
  - No prompt-injection markers were found in the server instructions, tool names or descriptions we captured.
  - We read all 52 captured tool definition(s), and no name or description among them implies an irreversible operation.
  - An AI judge read all 54 captured unit(s) of tool text and found none that tries to manipulate the model reading it.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### How do I install the Futureweb Intervals MCP server?

Futureweb Intervals MCP runs locally as a PyPI package, launched with uvx futureweb-intervals-mcp. Ready-made configuration for Claude, Cursor, VS Code, Codex and 5 more is on this page, copied from each client's own documentation.

### Claude

```bash
claude mcp add futureweb-intervals-mcp-server -- uvx futureweb-intervals-mcp
```

### Cursor

```json
{
  "mcpServers": {
    "futureweb-intervals-mcp-server": {
      "command": "uvx",
      "args": [
        "futureweb-intervals-mcp"
      ]
    }
  }
}
```

### VS Code

```json
{
  "servers": {
    "futureweb-intervals-mcp-server": {
      "command": "uvx",
      "args": [
        "futureweb-intervals-mcp"
      ]
    }
  }
}
```

### Codex

```bash
codex mcp add futureweb-intervals-mcp-server -- uvx futureweb-intervals-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "futureweb-intervals-mcp-server": {
      "type": "local",
      "command": [
        "uvx",
        "futureweb-intervals-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add futureweb-intervals-mcp-server --command uvx --arg futureweb-intervals-mcp
```

### Hermes

```yaml
mcp_servers:
  futureweb-intervals-mcp-server:
    command: "uvx"
    args: ["futureweb-intervals-mcp"]
```

### Netclaw

```json
{
  "McpServers": {
    "futureweb-intervals-mcp-server": {
      "Transport": "stdio",
      "Command": "uvx",
      "Arguments": [
        "futureweb-intervals-mcp"
      ]
    }
  }
}
```

### Vellum

```bash
assistant mcp add futureweb-intervals-mcp-server -t stdio -c uvx -a futureweb-intervals-mcp
```

### Other

```json
{
  "mcpServers": {
    "futureweb-intervals-mcp-server": {
      "command": "uvx",
      "args": [
        "futureweb-intervals-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-10-23 (score 71, +1)

No change was recorded against any check on this day. Stability & Change Management went from 27 to 30. That category is still filling its 30-day observation window: 8 days of observed history at the previous scan, 9 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-21 (score 70, +1)

No change was recorded against any check on this day. Stability & Change Management went from 20 to 23. That category is still filling its 30-day observation window: 6 days of observed history at the previous scan, 7 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-19 (score 69, +1)

No change was recorded against any check on this day. Stability & Change Management went from 13 to 17. That category is still filling its 30-day observation window: 4 days of observed history at the previous scan, 5 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-10-18 (score 68, −15)

- [security regression] Malware scan: pass → unverified

### 2026-10-17 (score 83, +16)

- [security improvement] Malware scan: unverified → pass

### 2026-10-16 (score 67, −15)

- [security regression] Malware scan: pass → unverified

### 2026-10-15 (score 82, +16)

- [security regression] Tool safety: pass → unverified
- [security improvement] Malware scan: unverified → pass
- [security] Stability: Stability not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet.
- [functional regression] Schema quality: 100 → unverified
- [functional regression] Capabilities: pass → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional improvement] Stability: unverified → 0.03
- [functional] Package version: 1.0.0b1 → 1.0.0b2

### 2026-10-14 (score 66, +16)

- [security regression] Malware scan: pass → unverified
- [security improvement] Injection markers: unverified → pass
- [security] First check of Judged manipulation: pass
- [security] Stability: Stability not yet verified: not enough scan history yet (needs a 30-day window).
- [functional improvement] Schema quality: unverified → 100
- [functional improvement] MCP protocol: unverified → pass
- [functional improvement] Tool coverage: unverified → 100
- [functional] First check of Schema quality: fail
- [functional] First check of Destructive annotations: pass
- [functional] First check of Schema quality: fail
- [functional] First check of Schema quality: good
- [functional] First check of Tool coverage: 100

## MCP tools (52)

### `get_gear_list` (~118 tokens)

Use to find gear ids and get an overview of the athlete's bikes, shoes and components (read-only).

One row per item: id, type, name, default-for, activity count, distance in km and retired
flag. Details of one item (components, reminders, filters): get_gear_details; activities on
a gear: get_activities(gear_id=...).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `refresh` (boolean): Re-fetch instead of using the 30-minute cache

### `get_gear_details` (~196 tokens)

Use for the details of one gear item (bike, shoes, component; read-only).

Distance, time and activity count, purchase and retirement dates, notes, the bike a
component belongs to, the activity type filters that assign activities automatically,
maintenance reminders with their usage, and for a bike its components (frame, power meter,
chain, tyres ...) with their own mileage. Which power meter recorded an activity is not
derived from gear: get_activity_details shows the power meter and serial from the device
file. Activities on this gear: get_activities(gear_id=...).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `gear_id` (string, required): Gear id from get_gear_list, e.g. "b12472159" (bike) or "30303" (component)
- `refresh` (boolean): Re-fetch the gear catalog instead of using the 30-minute cache

### `get_athlete_profile` (~175 tokens)

Use for who the athlete is: name, sex, date of birth, location, time zone, units, weight, height, resting HR, bikes and shoes, training plan and coach (read-only).

Also one line per sport setting (FTP, indoor FTP, LTHR, max HR, threshold pace). Only
coaching-relevant fields: account internals such as e-mail, API keys or OAuth scopes are
never returned. The profile's time zone defines "today" for all tools. Details:
get_sport_settings, get_training_zones, get_gear_list.

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `output_format` (string): json = machine-readable, all fields
- `refresh` (boolean): Re-fetch instead of using the 10-minute cache

### `get_sport_settings` (~217 tokens)

Use for the current thresholds and settings per sport (a group of activity types such as Ride, GravelRide/MountainBikeRide or Run/TrailRun; read-only).

Per sport setting: FTP and indoor FTP, W', Pmax, the latest Intervals.icu eFTP estimate,
LTHR and max HR, threshold pace with pace units, load models, default outdoor/indoor gear,
warm-up/cool-down times and the power, HR and pace zones with absolute ranges. The
thresholds in force for a past activity are in get_activity_details (snapshot stored with
the activity). Zones only: get_training_zones; change thresholds: update_sport_settings.

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `output_format` (string): json = machine-readable, all fields
- `refresh` (boolean): Re-fetch instead of using the 10-minute cache
- `sport_type` (string): Only the setting that covers this activity type, e.g. "GravelRide"

### `get_training_zones` (~186 tokens)

Use for the power, heart rate and pace zones of each sport setting (read-only).

Power zones in % of FTP with watts from the current FTP and the sweet spot range, HR zones
in bpm, pace zones in % of threshold speed with the pace from the threshold pace; each zone
has its name, bounds and absolute range. Current settings only. Thresholds and other
settings: get_sport_settings.

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `output_format` (string): json = machine-readable, all fields
- `refresh` (boolean): Re-fetch the sport settings instead of using the 10-minute cache
- `sport_type` (string): Only the setting that covers this activity type, e.g. "Run"; default all
- `zone_type` (string): Zone kind; all = power, HR and pace

### `get_custom_items` (~85 tokens)

Use to list the athlete's custom items (charts, custom activity, interval and wellness fields, streams, zones ...) with id, name, type and description (read-only).

Also refreshes the cached definitions the other tools use to label custom fields. Full
definition of one item: get_custom_item_by_id.

Input parameters:

- `athlete_id` (string): Default: the configured athlete

### `get_custom_item_by_id` (~86 tokens)

Use for the full definition of one custom item: name, type, description, visibility, index and its content configuration as JSON (code, value type, units, options, aggregate ...; read-only).

Ids: get_custom_items.

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `item_id` (integer, required): Custom item id (get_custom_items)

### `get_activities` (~397 tokens)

Use to find activities and their ids in a date range (default the last 30 days up to today, 10 per page), e.g. all rides on one bike over a season.

Returns one summary block per activity (Intervals.icu load, power, HR, feel/RPE, gear), one
line each with detail_level=compact, or JSON records with units and local/UTC start. Filters:
sport types, gear, power meter name. Any filter, sort, offset, compact or json gives a paged
listing with the total and the next offset. Unnamed activities are hidden unless
include_unnamed; nothing outside the date range is listed. Read-only. One activity in depth:
get_activity_report. Method: intervals://methods/activity-data (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `detail_level` (string): summary = text block per activity; compact = one line each
- `end_date` (string): Last day YYYY-MM-DD; default today
- `gear_id` (string): Only activities on this gear id (get_gear_list)
- `include_unnamed` (boolean): Also list activities without a name
- `limit` (integer): Activities per page
- `offset` (integer): Matching activities to skip (pagination)
- `output_format` (string): text, or json (records with units, local and UTC start, paging)
- `power_meter` (string): Only activities whose power meter name contains this text, e.g. Rally; others excluded
- `sort_by` (string): Newest or oldest first, or largest distance, moving time or load first
- `sport_types` (string): Comma-separated activity types, e.g. "Ride,GravelRide"
- `start_date` (string): First day YYYY-MM-DD; default 30 days before the earlier of end_date and today

### `get_activity_details` (~291 tokens)

Use when one activity's full summary, thresholds or device custom fields are needed beyond get_activity_report.

Returns the summary (time, distance, Intervals.icu load, power, HR, cadence, feel/RPE, FTP and
thresholds used, device and power meter), fueling, weather, W′ balance and source, plus every
custom activity field with a value (device metrics such as training effect, recovery time,
stamina, sweat loss), read from the athlete's own definitions with name, code, value and
units; 'no value' = null/NaN on Intervals.icu. full adds time in zones, running dynamics and
other raw fields. Read-only. Method: intervals://methods/activity-data (get_guide).

Input parameters:

- `activity_id` (string, required): Activity id, e.g. i123456789
- `detail_level` (string): compact = ~8 lines: key numbers, thresholds, sport-assigned custom fields, data quality; standard = full summary; full adds every other payload field
- `include_all_fields` (boolean): Also list every other non-empty payload field (same as detail_level=full)
- `include_custom_fields` (boolean): List the athlete's custom activity fields that have a value
- `output_format` (string): text, or json (raw activity, start times, gear name, thresholds, custom fields with status)

### `get_activity_intervals` (~369 tokens)

Use for per-interval numbers of one activity (laps or detected efforts): power, HR, cadence, speed, intensity, custom interval fields and groups.

Cadence follows the sport: steps per minute on foot (2 x the stored per-leg value), rpm
otherwise. stream_types adds start/end/min/max/mean/delta of any stream per interval from the
recorded samples, e.g. stamina drop or a second power meter (list_activity_streams shows what
exists). include_planned_types shows the planned step matched to each interval and the time
beyond the plan; the Intervals.icu type is kept. Without intervals use analyze_climbs.
Read-only; 2 API calls, +1 for streams, +1 for a paired event. Methods:
intervals://methods/activity-data, intervals://methods/execution (get_guide).

Input parameters:

- `activity_id` (string, required): Activity id, e.g. i123456789
- `detail_level` (string): compact = one line per interval; standard = full block per interval; full adds every custom stream when stream_types is empty
- `include_custom_fields` (boolean): List the athlete's custom interval fields per interval
- `include_planned_types` (boolean): Show the planned step matched to each interval (paired event or planned_workout_doc)
- `output_format` (string): text, or json (raw intervals and groups with custom fields, stream statistics, planned step)
- `planned_workout_doc` (object): Workout document {"steps": [...]} to match against; implies include_planned_types
- `stream_types` (string): Comma-separated streams to evaluate per interval, e.g. Stamina,secondary_power; custom = custom streams + secondary_power; all = every stream

### `get_activity_streams` (~403 tokens)

Use for the raw time-series samples of one activity (power, HR, cadence, altitude or any custom stream such as Stamina) when summaries are not enough.

Default output is a per-stream summary (units, statistics, first/last values); full gives a
CSV table, json one object with arrays (empty/null = no value). Default streams: time, watts,
heartrate, cadence, altitude, distance, velocity_smooth; "all" = every stream. full/json return
at most max_points samples (default 2000) and say where to continue; slice by index or time,
downsample keeps every n-th sample. time = seconds since start, pauses appear as jumps.
Read-only. Discover streams with list_activity_streams. Method:
intervals://methods/activity-data (get_guide).

Input parameters:

- `activity_id` (string, required): Activity id, e.g. i123456789
- `downsample` (integer): Keep every n-th sample in full/json (skipped, never averaged)
- `end_index` (integer): Sample index to stop before (exclusive; full/json)
- `end_time` (integer): Only samples with time < this, seconds since start (full/json)
- `max_points` (integer): Max samples in full/json, at most 20000; longer output is cut with a continue hint
- `output_format` (string): summary = per-stream units, statistics, preview; full = CSV row per sample; json = one object with arrays and next_start_index
- `start_index` (integer): First sample index (full/json); same indices as get_activity_intervals
- `start_time` (integer): Only samples with time >= this, seconds since start (full/json)
- `stream_types` (string): Comma-separated stream types (standard or custom codes) or all; default time,watts,heartrate,cadence,altitude,distance,velocity_smooth

### `list_activity_streams` (~167 tokens)

Use before get_activity_streams or get_activity_intervals(stream_types=...) to see which data streams one activity has.

Lists the standard streams and the athlete's custom streams present on the activity (e.g.
stamina, potential stamina, performance condition, grade adjusted speed, gear selection,
battery) with type code, display name, units and description, plus the power fields of the
file. include_stats downloads the streams and adds per-stream sample counts and
start/end/min/max/mean. Read-only. Method: intervals://methods/activity-data (get_guide).

Input parameters:

- `activity_id` (string, required): Activity id, e.g. i123456789
- `include_stats` (boolean): Also download the streams for sample counts and start/end/min/max/mean per stream

### `get_activity_messages` (~52 tokens)

Use to read the notes and comments on one activity: author, time, type and text of each message (read-only).

Input parameters:

- `activity_id` (string, required): Activity id, e.g. i123456789

### `get_events` (~194 tokens)

Use to see the athlete's calendar: planned workouts, races, notes and other events of a date range (default today to 30 days ahead).

Each event shows its category (Workout, Race A/B/C, Note ...), sport (Ride, Run ...), planned time and load, and the paired activity once it has been done. Full workout steps: get_event_by_id. Plan phases and weekly targets: get_training_plan.

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `categories` (string): Comma-separated categories, e.g. "WORKOUT" or "RACE_A,RACE_B,RACE_C,NOTE"; default all
- `end_date` (string): Last day YYYY-MM-DD; default 30 days ahead
- `output_format` (string): text or json (events with technical fields)
- `start_date` (string): First day YYYY-MM-DD; default today

### `get_event_by_id` (~134 tokens)

Use to read one calendar event completely, e.g. to read back a workout right after writing it.

Returns category and sport, planned time and load, the paired activity and the full workout document (steps, planned time in zones).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `event_id` (string, required): Intervals.icu event id (get_events)
- `output_format` (string): text or json (complete event incl. workout_doc)
- `resolve_targets` (boolean): Resolve %FTP / %LTHR / pace targets of the steps to W, bpm and m/s

### `get_training_plan` (~182 tokens)

Use for the season view: the assigned training plan, plan phases, weekly targets, races with priority and events that set the fitness model (read-only).

Reads the training plan assigned to the athlete and the calendar entries of the annual plan: PLAN (phases/blocks), TARGET (weekly load, time or distance targets), RACE_A/B/C, SEASON_START, and set eFTP / set fitness and fatigue / fitness days. Default range: 30 days back to 180 days ahead. Single workouts: get_events.

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `end_date` (string): Last day YYYY-MM-DD; default 180 days ahead
- `output_format` (string): json = machine-readable, all fields
- `start_date` (string): First day YYYY-MM-DD; default 30 days ago

### `get_athlete_power_curves` (~322 tokens)

Use for an athlete's best power per duration over whole periods: season bests, progress between seasons or date ranges.

Returns watts and W/kg per duration for this season, last season and/or a custom range,
each with the activity that set it. Defaults: Ride, 5 s to 60 min, both seasons;
durations that are not curve points are left out. Read-only, one API call. One activity:
get_best_efforts; HR and pace: get_hr_curves, get_pace_curves. Method:
intervals://methods/comparisons (get_guide).

Input parameters:

- `activity_type` (string): Activity type of the curves, e.g. Ride, VirtualRide, Run
- `athlete_id` (string): Default: the configured athlete
- `durations` (array): Durations in seconds as a JSON array of integers, e.g. [5, 60, 300, 1200]; default 5 s to 60 min
- `end_date` (string): Last day YYYY-MM-DD of the custom-range curve, after start_date
- `include_normalised` (boolean): Include W/kg values
- `indoor_outdoor` (string): Only indoor or outdoor activities; omit for both
- `last_season` (boolean): Include last season's curve (s1)
- `start_date` (string): First day YYYY-MM-DD of an extra custom-range curve; needs end_date
- `this_season` (boolean): Include this season's curve (s0)

### `get_hr_curves` (~294 tokens)

Use for the highest average heart rate an athlete sustained per duration over one or more periods (e.g. comparing periods; with get_pace_curves the same pace at a lower HR).

Returns bpm per duration for each curve (default the last 90 days) with the activity that
set it; durations without data are listed as not available. Read-only, one API call.
Power: get_athlete_power_curves. Method: intervals://methods/comparisons (get_guide).

Input parameters:

- `activity_type` (string): Activity type of the curves, e.g. Run, Ride, Swim
- `athlete_id` (string): Default: the configured athlete
- `curves` (array): Curve ids as a JSON array of strings, e.g. ["90d", "1y"], "s0" this season, "s1" last season, "r.2026-01-01.2026-03-01" a range; default ["90d"]
- `durations` (array): Durations in seconds as a JSON array of integers, e.g. [60, 300, 1200]; default 5 s to 60 min
- `end_date` (string): Last day YYYY-MM-DD of the custom-range curve, after start_date
- `start_date` (string): First day YYYY-MM-DD of an extra custom-range curve; needs end_date

### `get_pace_curves` (~343 tokens)

Use for an athlete's best times per distance over one or more periods: PBs, comparing periods, progress in running or swimming.

Returns the best time and pace (min/km; min/100 m for Swim and OpenWaterSwim) per
distance for each curve (default the last 90 days) with the activity that set it;
optionally gradient-adjusted pace. Distances not on the curve are listed as not
available. Read-only, one API call. HR side: get_hr_curves. Method:
intervals://methods/comparisons (get_guide).

Input parameters:

- `activity_type` (string): Activity type of the curves, e.g. Run, TrailRun, Swim
- `athlete_id` (string): Default: the configured athlete
- `curves` (array): Curve ids as a JSON array of strings, e.g. ["90d", "1y"], "s0" this season, "s1" last season, "r.2026-01-01.2026-03-01" a range; default ["90d"]
- `distances` (array): Distances in metres as a JSON array of numbers, e.g. [1000, 5000, 21097.5]; default 400 m to marathon, swims 50-400 m
- `end_date` (string): Last day YYYY-MM-DD of the custom-range curve, after start_date
- `gap` (boolean): Gradient-adjusted pace (GAP) instead of raw pace
- `start_date` (string): First day YYYY-MM-DD of an extra custom-range curve; needs end_date

### `get_best_efforts` (~334 tokens)

Use for the peak efforts of one activity: best average power, HR or speed over durations (s) or distances (m), e.g. peak 5 s to 20 min power or the fastest km of a run (velocity_smooth with distances).

Returns per effort the average (W, bpm or m/s with pace) and its position as elapsed
h:mm:ss and sample indices (usable as start_index / end_index); windows spanning a
recording pause are flagged. Default durations 5 s to 60 min; longer than the activity =
not available. Read-only; one API call per duration or distance plus 1-2. Several
activities: compare_best_efforts; period bests: get_athlete_power_curves. Method:
intervals://methods/comparisons (get_guide).

Input parameters:

- `activity_id` (string, required): Activity id, e.g. i123456789
- `count` (integer): Non-overlapping best efforts per duration or distance, 1-20
- `distances` (string): Comma-separated metres, e.g. "1000,5000" (added to durations)
- `durations`: Comma-separated seconds; "" for distances only
- `end_index` (integer): Sample index to stop before
- `exclude_intervals` (boolean): Ignore samples inside detected intervals
- `output_format` (string): json = machine-readable, all fields
- `start_index` (integer): First sample index searched
- `stream` (string): Stream, e.g. watts, heartrate, velocity_smooth (speed), cadence

### `compare_best_efforts` (~393 tokens)

Use to compare peak efforts (e.g. 1 / 5 / 20 min power) of several activities side by side: development over a block, races, or whether a new bike or power meter reads differently.

Returns a matrix of activities (date, sport, gear, FTP at the time) by duration with the
best average of the stream, and the best activity per duration. Activities come from
activity_ids or a date range (default the last 90 days), filtered by sport and gear; newest
first, limit 10 (max 25), at most 10 durations. Power meters of different bikes are not
calibrated against each other; no verdict. Read-only; one API call per activity and
duration (up to 250) plus the list and gear calls. One activity in detail: get_best_efforts.
Method: intervals://methods/comparisons (get_guide).

Input parameters:

- `activity_ids` (string): Comma-separated activity ids; otherwise the date range is used
- `athlete_id` (string): Default: the configured athlete
- `durations` (string): Comma-separated seconds, at most 10, e.g. "60,300,1200"
- `end_date` (string): Last day YYYY-MM-DD; default today
- `gear_id` (string): Only activities on this gear id (get_gear_list)
- `limit` (integer): Maximum activities, newest first; capped to 1-25
- `output_format` (string): json = machine-readable, all fields
- `sport_types` (string): Comma-separated activity types, e.g. "Ride,GravelRide"
- `start_date` (string): First day YYYY-MM-DD; without activity_ids default 90 days before end_date
- `stream` (string): Stream, e.g. watts, heartrate, velocity_smooth

### `find_similar_intervals` (~562 tokens)

Use to find earlier activities with intervals of a given length and intensity (% of FTP), or like the main set of a reference activity, ranked by comparability.

Pass min/max_secs and min/max_intensity, or reference_activity_id (window from its main
set: length ±25 %, intensity ±8 points of FTP; explicit values win; only the 365 days
before it unless start_date is given). Returns per activity date, sport, interval summary,
load, FTP at the time, gear, power meter, compliance and a comparability score 0-100 with
reasons. Sport defaults to one family (other families are counted, "all" keeps every
sport); watts of different power meters are not comparable, use % of FTP. Read-only; one
API call (+2 with a reference, +1 gear catalog). Details: get_activity_intervals; same
workout over time: compare_workouts. Method: intervals://methods/comparisons (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `end_date` (string): Last day YYYY-MM-DD; default no limit
- `ftp_range` (string): Only activities with FTP at the time in "low-high" W, e.g. "225-240"
- `ftp_tolerance_pct` (number): FTP difference in % to the reference or newest result flagged as other FTP context
- `gear_id` (string): Only activities on this gear id (get_gear_list)
- `limit` (integer): Maximum activities returned
- `max_intensity` (number): Highest % of FTP, 0-300 (rounded up)
- `max_reps` (integer): Maximum matching repetitions per activity
- `max_secs` (integer): Longest interval (s); required without reference_activity_id
- `min_intensity` (number): Lowest % of FTP, 0-300 (rounded down)
- `min_reps` (integer): Minimum matching repetitions per activity
- `min_secs` (integer): Shortest interval (s); required without reference_activity_id
- `output_format` (string): json = machine-readable, all fields
- `reference_activity_id` (string): Activity whose main work set defines the search window and the ranking
- `sort_by` (string): Default comparability with a reference, else date (newest first)
- `sport_types` (string): Comma-separated activity types or "all"; default the sport family of the reference or of most results
- `start_date` (string): First day YYYY-MM-DD; default 365 days before the reference, else no limit
- `target` (string): Workout target type (not the sport); omit for any

### `get_activity_histogram` (~221 tokens)

Use for the time distribution of one activity independent of zone definitions: how polarised a ride was, time above FTP, the pace spread of a run.

Returns the seconds and % of recorded time in each power (W), heart rate (bpm), pace or
grade-adjusted pace bucket, as computed by Intervals.icu; pace and GAP buckets are speeds
in m/s shown with the pace range. bucket_size applies to power and hr only. Read-only,
one API call. Method: intervals://methods/comparisons (get_guide).

Input parameters:

- `activity_id` (string, required): Activity id, e.g. i123456789
- `bucket_size` (integer): Bucket width in W (power, default 25) or bpm (hr, default 5); not for pace or gap
- `metric` (string): power (W), hr (bpm), pace or gap (grade-adjusted pace); pace and gap buckets are m/s
- `output_format` (string): json = machine-readable, all fields

### `compare_workouts` (~610 tokens)

Use to compare repeated executions of the same workout over time (e.g. every 3 x 10 min threshold session) on truly comparable work intervals.

Activities by name search (query), activity_ids or a date range (default the last 90
days); limit 8 (max 12). WORK intervals are split into main set (similar length and
intensity), surges, other and excluded; the main set gets time-weighted power, NP, HR, max
HR, cadence, W/bpm. Only activities matching the reference pattern (reference_activity_id,
else the newest; length ±25 %, intensity ±8 points of FTP) are compared; trends first ->
last with n (< 3 not reliable). RPE is whole-activity only; gear and power meter
differences are flagged; no verdict. Read-only; one API call per activity plus 1-3 (one
more per id with activity_ids). Method: intervals://methods/comparisons (get_guide).

Input parameters:

- `activity_ids` (string): Comma-separated activity ids (query is then ignored)
- `athlete_id` (string): Default: the configured athlete
- `comparable_only` (boolean): Table only activities matching the pattern; false tables all, with the reason
- `end_date` (string): Last day YYYY-MM-DD; default today
- `ftp_range` (string): Only activities with FTP at the time in "low-high" W, e.g. "225-240"
- `gear_id` (string): Only activities on this gear id (get_gear_list)
- `include_rpe` (boolean): Show whole-activity RPE and its trend
- `limit` (integer): Maximum activities, newest first; capped to 1-12
- `max_intensity` (number): Only WORK intervals at or below this % of FTP
- `max_interval_secs` (integer): Only WORK intervals at most this long (s)
- `max_reps` (integer): Only main sets with at most this many intervals
- `min_intensity` (number): Only WORK intervals at or above this % of FTP (replaces the 70 % floor)
- `min_interval_secs` (integer): Only WORK intervals at least this long (s); shorter ones under 2 min are surges
- `min_reps` (integer): Only main sets with at least this many intervals
- `output_format` (string): json = machine-readable, all fields
- `query` (string): Text in activity names, or "#tag" for an exact tag
- `reference_activity_id` (string): Activity whose main set defines the pattern; default the newest
- `sport_types` (string): Comma-separated activity types or "all"; default the sport family of the reference or newest
- `start_date` (string): First day YYYY-MM-DD; default 90 days before end_date (name search: none, or 365 days before the reference)

### `get_power_hr_efficiency` (~457 tokens)

Use to track power-to-heart-rate efficiency (W per bpm at the same power) over weeks.

Puts every WORK interval of at least min_interval_secs with power and HR into the power
band of its average power; returns per activity and band the count and time-weighted W,
HR and W/bpm, and per band the oldest vs the newest group of activities (each counts once;
at least 3 per group, else not reliable) compared with the day-to-day SD. Default the
last 90 days of rides, limit 30 (max 60); trends per gear when several power meters are
involved; filters for gear, indoor/outdoor and interval start time. Heat, fatigue,
cadence and sensors move the ratio: statistics only, no fitness verdict. Read-only; one API
call per activity plus 2. Method: intervals://methods/comparisons (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `end_date` (string): Last day YYYY-MM-DD; default today
- `environment` (string): Only indoor (trainer, virtual) or outdoor sessions; omit for both
- `gear_id` (string): Only activities on this gear id (get_gear_list)
- `limit` (integer): Maximum activities, newest first; capped to 1-60
- `max_start_minutes` (number): Only intervals starting at most this many minutes into the activity
- `min_activities_per_group` (integer): Independent activities needed in the oldest and in the newest group for a trend, >= 1
- `min_interval_secs` (integer): Shortest WORK interval counted, in seconds
- `min_start_minutes` (number): Only intervals starting at least this many minutes into the activity
- `output_format` (string): json = machine-readable, all fields
- `power_bands` (string): Comma-separated non-overlapping bands in W as "low-high"; low <= W < high
- `sport_types` (string): Comma-separated activity types, e.g. "Ride,VirtualRide"
- `start_date` (string): First day YYYY-MM-DD; default 90 days before end_date

### `get_fatigue_resistance` (~339 tokens)

Use for fatigue resistance: best power fresh vs after the athlete's work thresholds kJ0 / kJ1 (Intervals.icu fatigued power curves).

Reads the sport settings first. When they hold no kJ thresholds no fatigued values are
shown: the tool explains the setting and (suggest_thresholds) proposes thresholds from
body mass and recent rides, never saved. Otherwise returns watts per duration fresh and
after kJ0 / kJ1 with the change in %, for one activity or for athlete curves (default
42d); a fatigued curve without data is reported as missing, one equal to fresh as
identical, without a change. Read-only, 2-5 API calls. Within one long ride:
get_long_ride_fatigue_profile. Method: intervals://methods/comparisons (get_guide).

Input parameters:

- `activity_id` (string): Activity whose curves are compared; omit for the athlete curves
- `activity_type` (string): Activity type of the curves and kJ thresholds, e.g. Ride, VirtualRide
- `athlete_id` (string): Default: the configured athlete
- `curves` (string): Comma-separated athlete curve ids, e.g. "42d,90d,1y,s0"; ignored with activity_id
- `durations` (string): Comma-separated seconds, e.g. "60,300,1200"
- `output_format` (string): json = machine-readable, all fields
- `suggest_thresholds` (boolean): Suggest kJ0/kJ1 when not both are configured; a suggestion only, nothing is saved

### `compare_power_streams` (~440 tokens)

Use to compare two power meters recorded on the same ride (watts vs secondary_power by default), on one ride or across several rides.

One ride (activity_id): offset in W and % (secondary - primary), per power band, in stable 30/60
s windows, drift over the ride quarters, lag, best efforts of each stream and the samples
excluded as coasting, missing or outliers. Several rides (no activity_id, or activity_ids): the
rides that carry the second stream (default 180 days to end_date, newest first, limit 10, max
20), each compared on its own and summarised per bike and power meter with median,
between-ride SD and range. No calibration and no correction factor; sensors are named only
from the file's device data. Read-only. Method: intervals://methods/power-meters (get_guide).

Input parameters:

- `activity_id` (string): One ride, e.g. i123456789; omit (or give activity_ids) to compare several rides
- `activity_ids` (string): Comma-separated activity ids to compare as several rides (duplicates ignored, cut to limit)
- `athlete_id` (string): Default: the configured athlete
- `detail_level` (string): Several rides: compact = summary only; standard adds one line per ride; full adds power bins and device data per ride
- `end_date` (string): Several rides: last day YYYY-MM-DD; default today
- `end_index` (integer): Sample index to stop before (exclusive; one ride only)
- `limit` (integer): Several rides: at most this many, newest first, 1-20
- `output_format` (string): json = machine-readable, all fields
- `primary` (string): Stream type of the reference power source
- `secondary` (string): Stream type of the compared power source
- `start_date` (string): Several rides: first day YYYY-MM-DD; default 179 days before end_date (180 days)
- `start_index` (integer): First sample index to compare (one ride only)

### `analyze_workout_execution` (~419 tokens)

Use to check how a planned workout was executed, or without a plan to evaluate each detected interval of one activity.

The plan comes from planned_workout_doc, event_id or the event paired with the activity.
Planned steps (repeats expanded) are aligned with the intervals by order, duration or distance
and target intensity, never by names; laps that split one effort are merged. Per step: planned
vs actual moving time, target (W, bpm or pace) vs actual, time in target, HR response, cadence,
fade, Pw:HR drift (work steps of 10 min or more) and custom stream changes, with deviation notes
and an alignment confidence. Time past a step's plan and training after the plan are reported
apart. Unpaired: up to three candidate events, nothing is paired. Read-only. Method:
intervals://methods/execution (get_guide).

Input parameters:

- `activity_id` (string, required): Activity id, e.g. i123456789
- `detail_level` (string): compact = one line per step plus summary; standard; full adds counter and other-sport custom streams
- `duration_tolerance_pct` (number): Step length deviation in % of the step (at least 30 s) before it is split or flagged; default 10
- `event_id` (string): Planned workout event to compare against; default the event paired with the activity
- `output_format` (string): json = machine-readable, all fields
- `pause_tolerance_s` (number): Recording pause per step that is not flagged, seconds; default 60
- `planned_workout_doc` (object): Workout document {"steps": [...]} (format of add_or_update_event), e.g. when the event was deleted
- `start_tolerance_s` (number): Flag steps starting further than this from the plan timeline, seconds; default 120
- `suggest_matches` (boolean): Unpaired activity without plan: list candidate events of the same days (read-only)

### `analyze_climbs` (~446 tokens)

Use for activities without useful intervals (tours, mountain hikes, trail runs) to split the recording into climbs, descents, sections in between and pauses.

Per segment: time and sample indices, moving time, distance, gain/loss, average and steepest
grade, VAM, speed, power, NP, HR, cadence and start/end/min/max/mean/delta of every custom
stream. Defaults follow the sport (foot vs bike); implausible grades are flagged and each
segment gets a grade confidence. Slow scrambling counts as moving, real pauses as pause. Climb
gains are not the activity's total elevation gain. Text lists up to max_segments segments.
Read-only, 2 API calls (activity, all streams). Method: intervals://methods/climbs (get_guide).

Input parameters:

- `activity_id` (string, required): Activity id, e.g. i123456789
- `extra_stream_types` (string): Comma-separated standard streams to evaluate per segment besides the custom ones, e.g. temp,respiration,left_right_balance
- `grade_window_m` (number): Distance window of the steepest grade, metres; default 50 on foot, 100 otherwise
- `max_segments` (integer): Segments listed in text output
- `min_climb_gain_m` (number): Minimum elevation gain of a climb, metres
- `min_descent_loss_m` (number): Minimum elevation loss of a descent, metres
- `min_grade_distance_m` (number): No grade below this horizontal distance, metres; default 30 on foot, 50 otherwise
- `min_grade_pct` (number): Minimum average grade of climbs and descents, %
- `output_format` (string): json = machine-readable, all fields
- `pause_min_secs` (integer): Minimum length of a reported stationary period, seconds
- `show_raw_grade` (boolean): Also report the grade of the unsmoothed altitude (windows of at least min_grade_distance_m)
- `stationary_speed_m_s` (number): Pause candidate below this speed, m/s; default 0.3 on foot, 0.5 otherwise

### `get_training_load` (~357 tokens)

Use for acute and chronic training load in detail: acute (default 7 d) and chronic (28 d) Intervals.icu load, acute:chronic ratio (coupled daily means), Foster monotony and strain, deload-like weeks, per sport family with the primary sport, ISO weeks, and CTL/ATL/form/ramp at the end date (read-only).

Rest days count as 0; sessions without a load are counted, not added. Device loads (custom
fields such as a Garmin training load) are listed apart on their own scale, never added. With
the default end date and nothing recorded today yet, the windows end yesterday. Reference
ranges (ACWR 0.8-1.3, monotony > 2.0) are shown with sources as context; small samples are
flagged; no verdict. Overview: get_coach_context; planned load: get_load_projection.
Method: intervals://methods/load (get_guide).

Input parameters:

- `acute_days` (integer): Acute window in days, 3-28
- `athlete_id` (string): Default: the configured athlete
- `chronic_days` (integer): Chronic window in days, 14-120, longer than acute_days
- `detail_level` (string): compact = windows, ratio, monotony, fitness, top 3 sports; standard adds all sports, ISO weeks, device loads; full adds daily loads and definitions
- `end_date` (string): Last day YYYY-MM-DD; default today; not in the future
- `output_format` (string): json = machine-readable, all fields
- `weeks` (integer): ISO weeks in the weekly table, 1-26

### `get_load_projection` (~554 tokens)

Use for future fitness: CTL, ATL and form projected over the planned workouts in the calendar, or a what-if scenario (sessions or weekly templates not in the calendar) against the calendar plan (read-only, nothing is written).

Starts from Intervals.icu's CTL/ATL at the end of yesterday plus today's completed load;
planned workouts without a load are reported, not guessed. Returns end values, lowest form,
highest ramp, ISO weeks with plan statistics, race days, Intervals.icu's own projection, a
model check and weeks outside commonly cited ranges (ramp 5-8 CTL/week, monotony > 2.0, no rest
day). With target_date, target_form or a scenario: the target day (default the next RACE_A)
at the start of the day; target_form adds a search for the load of the last taper_days that
reaches it. Arithmetic, not a forecast; no verdict. Method and scenario format:
intervals://methods/load (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `atl_days` (integer): ATL time constant in days, at least 1
- `ctl_days` (integer): CTL time constant in days; atl_days < ctl_days <= 365
- `detail_level` (string): compact = start, end, lowest form, races, target; standard adds ISO weeks and plan checks; full adds days (JSON: days always, with a scenario only at full)
- `end_date` (string): Last day YYYY-MM-DD, max 180 days ahead; default 28 days ahead, extended to the target and scenario
- `output_format` (string): json = machine-readable, all fields
- `scenario`: What-if plan not in the calendar, object or JSON text: {"calendar": "add"|"replace"|"none", "sessions": [{"date", "load" or "duration_min"+"intensity_factor"}], "weekly": [{"start", "weeks", "load" o…
- `taper_days` (integer): Days before the target varied by the search, 1-42
- `target_date` (string): Target day YYYY-MM-DD, today or later (form at the start of that day); default the next RACE_A event
- `target_form`: Form range at the start of the target day: "5,15" (CTL - ATL) or "5%,20%" (of CTL); starts the search for the load before it

### `get_activity_data_audit` (~315 tokens)

Use to check where an activity's data came from and what is missing, or without activity_id how complete the data of a period is.

One activity: source (sync, upload, Strava stub), upload and analysis times, filtered
duplicates, recording stops, FIT laps vs intervals and edits, sensors, streams vs those usual
for the sport with coverage, custom fields with value / zero placeholder / none, fields the
Garmin Intervals Bridge could fill. Period (default 28 days to end_date): per sport how many
activities have power, HR, GPS, weather, custom streams and fields. Facts and counts, no
verdict; read-only, 1-3 API requests. Method: intervals://methods/activity-data (get_guide).

Input parameters:

- `activity_id` (string): Activity to audit, e.g. i123456789; omit for the coverage of a period
- `athlete_id` (string): Default: the configured athlete
- `detail_level` (string): compact = no stream download, shorter lists; full = every stream, gap and field
- `end_date` (string): Period: last day YYYY-MM-DD; default today
- `output_format` (string): json = machine-readable, all fields
- `sport_types` (string): Comma-separated activity types, e.g. "Ride,GravelRide"
- `start_date` (string): Period: first day YYYY-MM-DD; default 27 days before end_date; max 366 days

### `get_activity_report` (~423 tokens)

Use first for any question about one activity: overview, plan vs execution, power meter check, climbs and data quality in one call (read-only, 3-4 API requests).

The overview has thresholds, device, sport-assigned custom fields, fueling, weather and W′
balance. With a paired event or planned_workout_doc the plan-vs-execution analysis follows
(as analyze_workout_execution), otherwise the intervals; a second-power-meter check only with
enough valid paired samples; climbs without intervals or above 500 m gain; then data-quality
notes. compact = core numbers and up to 5 key findings. Full detail: get_activity_details,
analyze_workout_execution, compare_power_streams, analyze_climbs, get_activity_data_audit.
Methods: intervals://methods/activity-data, intervals://methods/execution (get_guide).

Input parameters:

- `activity_id` (string, required): Activity id, e.g. i123456789
- `detail_level` (string): compact = core numbers, up to 5 key findings, data-quality flags; standard = full analysis, at most 30 interval lines; full = everything, all custom fields and streams
- `duration_tolerance_pct` (number): Step duration tolerance in % before a step is split or flagged short; default 10
- `include_climbs` (boolean): Force (true) or suppress (false) the climbs; default only without intervals or above 500 m gain
- `include_route_history` (boolean): Add earlier activities on the same Intervals.icu route (2 extra requests)
- `output_format` (string): json = machine-readable, all fields
- `pause_tolerance_s` (number): Recording pause per step before it is flagged, seconds; default 60
- `planned_workout_doc` (object): Workout document {"steps": [...]} to compare against, e.g. when the event was deleted
- `start_tolerance_s` (number): Plan timeline shift before a step is flagged, seconds; default 120

### `get_fueling_analysis` (~375 tokens)

Use for carbohydrate, fluid and sodium intake of one activity (activity_id) or of the long sessions of a period (default the last 90 days, sessions of at least min_minutes; read-only).

Carbs used (Intervals.icu estimate) and ingested (logged total) in g and g/h, the ingested
share of used, kcal and kJ, and fluid intake, sodium and sweat loss per hour where custom
fields exist (found by units and name). One activity also gets the intake per hour from a
custom intake stream, if there is one. Period: statistics per sport family, by duration and
by intensity, Spearman correlations from 8 sessions, with sample sizes. Not logged is never
0; used minus ingested is no 1:1 energy deficit; no targets.
Method: intervals://methods/fueling (get_guide).

Input parameters:

- `activity_id` (string): One activity, e.g. i123456789; omit for the period mode
- `athlete_id` (string): Default: the configured athlete
- `detail_level` (string): period: compact = per sport family; standard adds duration/IF buckets, correlations, 15 sessions; full lists all sessions. One activity: compact omits notes
- `end_date` (string): Last day YYYY-MM-DD (period mode); default today
- `min_minutes` (number): Minimum moving time in minutes (period mode), not negative
- `output_format` (string): json = machine-readable, all fields
- `sport_types` (string): Comma-separated activity types (period mode), e.g. "Ride,GravelRide"
- `start_date` (string): First day YYYY-MM-DD (period mode); default 89 days before end_date; max 366 days

### `get_recovery_snapshot` (~327 tokens)

Use for the recovery and readiness context of one day in one call (default today; read-only, numbers only, no readiness verdict).

For the day and days_back days before: native wellness values, CTL/ATL/form/ramp rate,
subjective scores, custom wellness fields with a value (e.g. Body Battery from a sync
bridge), missing values and the record's update time; recorded SICK/INJURED entries; personal
baselines of baseline_metrics (7-day and 42-day mean, median, SD, latest value vs baseline
with z-score; small samples flagged); the activities of those days with loads and device
fields; the planned events of the day. Today is flagged preliminary and a line (JSON
today_completeness) names the usual fields not yet in today's record, grouped by when they
usually arrive: not yet available, not normal. Trends: get_wellness_trends.
Method: intervals://methods/wellness (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `baseline_metrics` (string): Comma-separated wellness field codes (native or custom) for the baseline block
- `date_str` (string): The day YYYY-MM-DD; default today
- `days_back` (integer): Days before date_str to include, 0-14
- `detail_level` (string): compact = no custom fields; standard = up to 20 custom fields per day; full = all
- `output_format` (string): json = machine-readable, all fields

### `get_wellness_trends` (~383 tokens)

Use for multi-day wellness trends against the athlete's own baseline (default the 42 days ending today; read-only, statistics only).

Per metric with units: the daily values of the last 14 days with trailing means, period
statistics, a personal baseline (the 42 days ending at end_date), the latest value vs that
baseline (difference, %, z-score), rolling means, the last 7 days vs the 7 before and
outliers (|z| >= 2.5). Missing days are never filled in; for physiological metrics a stored 0
counts as missing. Small samples are flagged (baseline under 14 values, correlation under 30
paired days). Weight adds a 7/14/28-day slope in kg per week. Optional correlations
(Pearson, Spearman, with lag) are associations, not causes. One day in context:
get_recovery_snapshot. Method: intervals://methods/wellness (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `correlations` (string): Comma-separated pairs "a:b" or "a:b:lag_days" (b lag days later), e.g. "hrv:readiness,restingHR:sleepScore:1"
- `end_date` (string): Last day YYYY-MM-DD; default today
- `metrics` (string): Comma-separated, at most 16: native codes (hrv, restingHR, weight, ctl ...), custom field codes, eftp_<Type>
- `output_format` (string): json = machine-readable, all fields
- `start_date` (string): First day YYYY-MM-DD; default 41 days before end_date (42 days)
- `windows` (string): Comma-separated rolling windows in days, 2-365

### `get_nutrition_summary` (~337 tokens)

Use for food intake, calorie balance and weight trend over a period (default the 28 days ending today; read-only).

Per day: logged kcal, carbohydrates, protein and fat, the device's total and active burn and
balance (custom wellness fields, codes configurable) and weight. Per window (default 7/14/28
days): intake totals and means over logged days only, days without logged intake, burn mean,
balance total and mean on logged days, weight change and slope in kg per week. A day without
logged intake is never 0 kcal; the device burn is an estimate; a calorie balance does not
measure fat change. Optionally the Intervals.icu training load per day.
Method: intervals://methods/wellness (get_guide).

Input parameters:

- `active_field` (string): Custom wellness field code of the active burn (kcal)
- `athlete_id` (string): Default: the configured athlete
- `balance_field` (string): Custom wellness field code of a device balance; where missing, intake minus burn
- `burn_field` (string): Custom wellness field code of the total daily burn (kcal)
- `end_date` (string): Last day YYYY-MM-DD; default today
- `include_training_load` (boolean): Add the Intervals.icu training load per day
- `output_format` (string): json = machine-readable, all fields
- `start_date` (string): First day YYYY-MM-DD; default 27 days before end_date (28 days)
- `windows` (string): Comma-separated windows in days, 2-365

### `get_training_summary` (~408 tokens)

Use for training totals of a period grouped by ISO week, month, sport (activity type), gear or in total, including custom activity fields (read-only).

Per group and in total: sessions, moving/elapsed time, distance, elevation, Intervals.icu load
with the power/HR/pace load sums, time-weighted intensity, CTL/ATL/form/ramp at the end of the
group's week or month, time in power (sweet spot apart) and HR zones, sport and gear splits,
feel and RPE, sessions of 3 h or more, the longest session, trainer sessions. Numeric custom
fields are aggregated by units and meaning: additive values summed, device loads summed apart
from the Intervals.icu load, estimates as latest value and change, per-activity values as
mean/median/range. Missing values are skipped, never counted as 0. Per-week view in one
call: get_weekly_summary. Method: intervals://methods/summary (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `detail_level` (string): compact = totals, loads, fitness, sessions per sport, device loads; standard (text default) adds zones, gear, feel/RPE, custom fields; full adds the aggregation reason per custom field
- `end_date` (string): Last day YYYY-MM-DD; default today
- `group_by` (string): week = ISO weeks from Monday; month; sport = activity type; gear; total = one group
- `include_gear` (boolean): Per-gear split inside each group (text, standard and full)
- `output_format` (string): text (readable) or json (the parts of an explicit detail_level, else all fields)
- `sport_types` (string): Comma-separated activity types, e.g. "Ride,GravelRide"
- `start_date` (string, required): First day YYYY-MM-DD

### `get_intensity_distribution` (~377 tokens)

Use for the training intensity distribution of a period (default the last 4 weeks, read-only): Intervals.icu's time in zones of each activity mapped to the three-zone model (Z1 below the first threshold, Z2 between, Z3 above the second).

Returns Z1/Z2/Z3 shares and hours, the polarization index (Treff et al. 2019), the class
(Base, Polarized, Pyramidal, Threshold, HIT) and hard sessions and days for the period, per
sport family and per ISO week, and the drift between the two halves. The mapping depends on
the zone basis and the zone count of the athlete's model. Activities without zone data are
never counted as easy; the coverage is reported. Statistics only, no verdict. Overview:
get_coach_context. Method: intervals://methods/intensity (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `detail_level` (string): compact = period, sports, drift; standard adds ISO weeks, zone mapping and rules; full adds every session
- `end_date` (string): Last day YYYY-MM-DD; default today
- `output_format` (string): json = machine-readable, all fields
- `sport_types` (string): Comma-separated activity types, e.g. "Ride,GravelRide"
- `start_date` (string): First day YYYY-MM-DD; default 27 days before end_date (4 weeks); max 366 days
- `threshold_as` (string): Power zone Z4 (91-105 % FTP) counts as moderate (three-zone Z2) or high (Z3)
- `zone_basis` (string): auto = power for cycling, else HR, then pace, then power; or one basis for all

### `get_durability` (~479 tokens)

Use for aerobic durability: Intervals.icu's aerobic decoupling (power:HR, or pace:HR for runs without power; drift between the halves in %) of steady long cycling and running sessions and the efficiency factor trend (read-only, default the last 6 weeks).

Sessions pass a quality filter (min_minutes moving, few stops, HR, rides with power,
variability index up to max_vi, temperature up to max_temp_c, optionally indoor or outdoor
only); excluded ones are counted per reason. Per sport family: median, range, quartiles,
sessions above drift_threshold_pct (5 % commonly cited) and the last recent_days against the
window. Fewer than 8 qualifying sessions are flagged as a small sample; mixed indoor/outdoor,
bikes/shoes or power meters are noted. Statistics only, no verdict. Per interval and bike:
get_power_hr_efficiency. Method: intervals://methods/durability (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `detail_level` (string): compact = per-sport summary; standard adds the qualifying sessions and the reference; full adds the excluded sessions
- `drift_threshold_pct` (number): Decoupling in % above which sessions are counted
- `end_date` (string): Last day YYYY-MM-DD; default today
- `environment` (string): Only indoor (trainer, virtual) or outdoor sessions; omit for both
- `max_temp_c`: Maximum average temperature in °C; null = no limit; a missing temperature passes
- `max_vi` (number): Maximum variability index (steadiness), at least 1
- `min_minutes` (number): Minimum moving time in minutes, above 0
- `output_format` (string): json = machine-readable, all fields
- `recent_days` (integer): Recent window in days compared with the whole period
- `sport_types` (string): Comma-separated activity types, e.g. "Ride,VirtualRide"; default every cycling and running type
- `start_date` (string): First day YYYY-MM-DD; default 41 days before end_date (6 weeks); max 366 days
- `temperature_source` (string): Temperature for max_temp_c: device sensor, Intervals.icu weather or its feels-like

### `get_long_ride_fatigue_profile` (~540 tokens)

Use to see how long rides change at matched power as work accumulates: HR, W/bpm, cadence and Garmin stamina in steady segments of a power band (default 75-85 % FTP) before vs after work thresholds.

Phases by work (default 750 / 1,500 kJ, or kJ/kg) are compared with the phase before the
first threshold. Threshold crossings and climbs carry the prior work (kJ, kJ/kg, kJ and
time above FTP, efforts above FTP). Rides from activity_ids or the long rides of a period
(default 180 days, reaching the highest threshold; limit 6, max 12). Across rides: median
and range of the changes with n, small samples flagged. Statistics only, no verdict.
Read-only; one stream call per ride plus 1-4 (one more per id with activity_ids). Fresh vs
fatigued power curves: get_fatigue_resistance. Method: intervals://methods/fatigue
(get_guide).

Input parameters:

- `activity_ids` (string): Comma-separated activity ids (capped to limit); default the long rides of the period
- `athlete_id` (string): Default: the configured athlete
- `climb_after_hours` (number): Climbs starting after this many hours are marked late, >= 0
- `detail_level` (string): compact = ride totals, changes, climb count; standard adds thresholds, phases, climbs, method; full adds every segment
- `end_date` (string): Last day YYYY-MM-DD; default today
- `limit` (integer): Rides analysed, newest first; capped to 1-12
- `min_climb_gain_m` (number): Minimum climb elevation gain in metres, > 0
- `min_segment_secs` (integer): Minimum steady segment length in seconds, >= 90
- `output_format` (string): json = machine-readable, all fields
- `power_bands` (string): Comma-separated non-overlapping bands in W as "low-high", e.g. "180-200"; default 75-85 % FTP
- `sport_types` (string): Comma-separated activity types of the period search
- `start_date` (string): First day YYYY-MM-DD; default 180 days before end_date
- `threshold_unit` (string): kj = absolute work; kj_per_kg = kJ per kg body mass
- `work_thresholds` (string): 1-3 comma-separated positive values in threshold_unit, e.g. "750,1500"

### `get_submax_test_trends` (~410 tokens)

Use to follow the submaximal fatigue tests Intervals.icu detects (#SFT) over the weeks: which are valid benchmarks and how HR responds.

Lists the tests of the period (default 180 days; limit 30, max 60) with target, average,
CV, end HR, efficiency factor and HR recovery (HRRc; not measured is never 0). Valid: on
target, steady, not ignored and (check_context) not inside a longer work interval, not
continued, not after hard riding; excluded tests carry the reason. Valid tests are
trended per sport family and test type (power and pace never pooled) and ISO week: n,
change, slope, SD. Statistics only, no verdict. Read-only; 2 API calls plus 2 per power
test with check_context. Method: intervals://methods/fatigue (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `check_context` (boolean): Check intervals and streams around each power test (2 API calls each)
- `detail_level` (string): compact = counts, exclusion reasons, HR/EF/HRRc trends; standard adds each test, stream trends, ISO weeks; full adds context notes
- `end_date` (string): Last day YYYY-MM-DD; default today
- `limit` (integer): Tests, newest first; capped to 1-60
- `output_format` (string): json = machine-readable, all fields
- `require_recovery` (boolean): Exclude tests without an HR recovery (HRRc) part
- `sport_types` (string): Comma-separated activity types, e.g. "Ride,Run"; omit for all
- `start_date` (string): First day YYYY-MM-DD; default 180 days before end_date
- `tolerance_pct` (number): Allowed deviation of the average from the target in %, 0-50; default the test's own

### `get_coach_context` (~369 tokens)

Use first for a weekly or general training review: load, intensity, recovery, durability and plan for one end date in one compact call (read-only, about 2-3k characters).

Combines 7/28-day Intervals.icu load with acute:chronic ratio, monotony, strain and
CTL/ATL/form; the three-zone intensity of 7 and 28 days; recovery markers (HRV, resting HR,
sleep) against personal baselines with a z-score; durability; recorded SICK/INJURED
entries; top sessions; and, when the end date is today, planned workouts of the next 7 days
and the next race. For today it names wellness fields not yet recorded (not yet available,
not normal). A method line states windows and rules; small samples are flagged; missing
values are never 0; no verdict. Details: get_training_load, get_intensity_distribution,
get_durability, get_recovery_snapshot, get_load_projection. Method:
intervals://methods/load (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `detail_level` (string): compact = load, fitness, intensity, recovery, durability, method; standard (text default) adds sports, drift, top sessions, plan, coverage; full adds 4 ISO weeks and references
- `end_date` (string): Last day YYYY-MM-DD; default today; not in the future
- `output_format` (string): text (readable) or json (the parts of an explicit detail_level, else the full structure)
- `threshold_as` (string): Power zone Z4 (91-105 % FTP) counts as moderate (three-zone Z2) or high (Z3)

### `preview_workout` (~168 tokens)

Use to show the athlete how a drafted workout will look before writing it: renders the workout document as Intervals.icu workout text with its totals (no API call, nothing written).

Expands repeats, sums planned duration and distance, counts steps with targets and open-ended steps, and shows the text add_or_update_event would send. Full check list: validate_workout.

Input parameters:

- `moving_time` (integer): Expected moving time in seconds, compared with the step sum
- `output_format` (string): json = machine-readable, all fields
- `workout_doc` (object, required): Workout document with steps, as for add_or_update_event. Format: intervals://workout-syntax
- `workout_type` (string): Sport of the workout, e.g. Ride, GravelRide, Run

### `validate_workout` (~273 tokens)

Use before every workout write (add_or_update_event, add_events_bulk, create_library_workout) to check a drafted workout document; read-only, nothing is written.

Checks durations or distances per step, repeat blocks, target units per sport and plausible values, ramps and ranges, warm-up and cool-down, the step sum against moving_time and the sport; with start_date it lists the events already on that day and flags a same-name event as a possible duplicate. Format: intervals://workout-syntax (get_guide). Show the result to the athlete before writing.

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `check_calendar` (boolean): Look up the events already on start_date
- `moving_time` (integer): Expected moving time in seconds, compared with the step sum
- `name` (string): Planned event name, for the duplicate check
- `output_format` (string): json = machine-readable, all fields
- `start_date` (string): Planned day YYYY-MM-DD, for the calendar check
- `workout_doc` (object, required): Workout document with steps, as for add_or_update_event. Format: intervals://workout-syntax
- `workout_type` (string, required): Sport of the workout, e.g. Ride, GravelRide, Run, Swim

### `get_server_status` (~75 tokens)

Use to check the connection when tools are missing or fail: server version, enabled permission classes and tool set, registered and hidden tools, whether Intervals.icu answers, and the athlete's custom field and stream counts. The API key is never shown.

Input parameters:

- `output_format` (string): json = machine-readable, all fields

### `get_guide` (~99 tokens)

Use when the short tool descriptions are not enough: read the workout syntax before writing a workout, or how an analysis works (method, windows, filters, caveats).

Returns the same Markdown as the resources intervals://guide, intervals://workout-syntax and intervals://methods/<topic>. Static text, no athlete data.

Input parameters:

- `topic` (string): usage = tool overview; workout-syntax = workout format; others = method of that analysis

### `get_weekly_summary` (~194 tokens)

Use for a quick per-week overview from Intervals.icu's athlete summary (read-only, one API call).

Per ISO week (from Monday): sessions, moving time, distance and training load, a split per
sport category, time in HR zones (non-zero zones only) and CTL/ATL/form/ramp at the end of
the week (the latest day with data for the current week). Sessions without HR (e.g.
strength) are counted. Rows of other (followed or coached) athletes are ignored. Grouping by
month, sport or gear, separate power/HR/pace loads and custom fields: get_training_summary.
Method: intervals://methods/summary (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `end_date` (string, required): Last day YYYY-MM-DD
- `start_date` (string, required): First day YYYY-MM-DD

### `get_plan_compliance` (~204 tokens)

Use to compare planned workouts with the activities done in a date range (read-only, two API calls).

Planned workouts (calendar WORKOUT events) are linked to activities by the event's
paired_activity_id or the activity's paired_event_id; each pair shows planned vs actual
duration and load with the deviation in %. An activity counts for one event only. Unlinked
past workouts are missed, those of today or later upcoming (athlete's local date).
Activities without a planned workout are unplanned; those linked to a workout outside the
range are listed apart. Completion = completed / (completed + missed). NOTE events with
training availability, allowed sports or a maximum training time are listed too.
Method: intervals://methods/summary (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `end_date` (string, required): Last day YYYY-MM-DD
- `start_date` (string, required): First day YYYY-MM-DD

### `get_workout_library` (~75 tokens)

Use to list the athlete's workout library: folders and plans with their workouts and ids (read-only). One workout in detail: get_library_workout.

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `folder` (string): Only this folder or plan: name (case-insensitive) or id

### `get_library_workout` (~106 tokens)

Use to read one library workout (steps, planned time, load, targets), e.g. to reuse it with add_or_update_event or validate_workout. Ids: get_workout_library.

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `output_format` (string): text or json (complete workout incl. workout_doc)
- `workout_id` (string, required): Library workout id (get_workout_library); small numbers such as 1 are normal

### `get_wellness_data` (~258 tokens)

Use for the raw daily wellness records of a date range (default the last 30 days; read-only).

Per day as stored: CTL/ATL and eFTP per sport, vitals (weight, resting HR, HRV, SpO2 ...),
sleep, subjective scores, nutrition, steps and comments; include_all_fields adds every other
field, custom wellness fields labelled with name and units. When the range includes today, a
line names the usual fields not yet in today's record, grouped by when they usually arrive:
not yet available, not normal. Long ranges are paged by day: a note gives the start_date to
continue with. Baselines and trends: get_recovery_snapshot, get_wellness_trends,
get_nutrition_summary.
Method: intervals://methods/wellness (get_guide).

Input parameters:

- `athlete_id` (string): Default: the configured athlete
- `end_date` (string): Last day YYYY-MM-DD; default today
- `include_all_fields` (boolean): Also list every other field, custom wellness fields with name and units
- `start_date` (string): First day YYYY-MM-DD; default 30 days before the earlier of end_date and today

## Diagnostics

Captured diagnostic sections: Provenance, Install scripts, Dependencies. The full working is on the page: https://verifymcp.io/servers/futureweb-intervals-mcp-server/futureweb-intervals-mcp#diagnostics

## Score history

- 2026-10-23: 71
- 2026-10-22: 70
- 2026-10-21: 70
- 2026-10-20: 69
- 2026-10-19: 69
- 2026-10-18: 68
- 2026-10-17: 83
- 2026-10-16: 67
- 2026-10-15: 82
- 2026-10-14: 66
- 2026-10-13: 50
- 2026-10-12: 35

## Common questions

### What is the Futureweb Intervals MCP server?

Futureweb Intervals MCP is listed in the public MCP registry as io.github.futureweb/intervals-mcp-server. Self-hosted Intervals.icu MCP server: training analytics, Garmin data, wellness, workout planning. This page covers its PyPI package (futureweb-intervals-mcp).

### Is the Futureweb Intervals MCP server safe to use?

Futureweb Intervals MCP scores 71 out of 100 on VerifyMCP. We found no known CVEs affecting it as of 23 October 2026. Its build provenance is signed and verified. That is a record of what we were able to check automatically, not an endorsement. The category breakdown on this page shows every signal behind the number, including the ones we could not confirm.

### What tools does the Futureweb Intervals MCP server expose?

Futureweb Intervals MCP exposes 52 tools: get_gear_list, get_gear_details, get_athlete_profile, get_sport_settings, get_training_zones, and 47 more. Their descriptions and schemas cost roughly 15,538 tokens of context every time the server is loaded.

### Is the Futureweb Intervals MCP server still maintained?

Futureweb Intervals MCP is still listed as active in the MCP registry. We last reached this channel on 23 October 2026. Those dates come from our own scans of the registry and the channel itself, not from anything the publisher announced.

### What licence is the Futureweb Intervals MCP server under?

Futureweb Intervals MCP declares the GPL-3.0-only licence, which is OSI-approved. That covers the source only, and says nothing about the cost of any service it calls.

## Links

- PyPI project: https://pypi.org/project/futureweb-intervals-mcp/
- Socket report: https://socket.dev/pypi/package/futureweb-intervals-mcp
- Repository: https://github.com/futureweb/intervals-mcp-server
- Changelog RSS feed: https://verifymcp.io/servers/futureweb-intervals-mcp-server/futureweb-intervals-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/futureweb-intervals-mcp-server/futureweb-intervals-mcp.json
- HTML version of this page: https://verifymcp.io/servers/futureweb-intervals-mcp-server/futureweb-intervals-mcp
