Skip to main content
Glama
intervals-mcp
by VictorForV

Intervals MCP

Русская версия

A self-hosted, read-only MCP server that gives AI assistants access to an athlete's Intervals.icu training data.

Connect a sports watch, bike computer, trainer, Strava, or another supported source to Intervals.icu. Intervals MCP then exposes the normalized training data to ChatGPT, Claude, Claude Code, Cursor, VS Code, and other MCP clients. See Intervals.icu for its current integrations; the list changes over time.

The server only makes GET requests. It cannot create, edit, or delete anything in an athlete's Intervals.icu account.

What an assistant can read

  • Athlete profile, timezone, sport settings, zones, FTP, LTHR, and max HR.

  • Activities, details, laps, intervals, and downsampled streams.

  • Wellness, fitness, fatigue, HRV, sleep, mood, and weight when available.

  • A coach-style training readiness assessment: form (TSB) classified into a band, a ramp-rate read, and whether recent HRV has dropped below baseline.

  • PNG charts: CTL/ATL/TSB over time, and best-effort curves (HR, pace, power) by duration or distance -- for when the shape says more than the numbers.

  • Planned events, best-effort curves, gear, and the workout library.

  • Additional Intervals.icu v1 GET endpoints through a read-only raw tool, which redacts anything that looks like a credential or an email address.

Large responses are compacted before they reach the model. Empty fields are dropped, streams are downsampled, and summaries use the full data series.

Related MCP server: intervals.mcp

Quick start

You need an Ubuntu or Debian VPS with a public hostname. Point the hostname's DNS record at the server and allow inbound TCP ports 80 and 443. The installer adds Docker, Compose, Git, and uv when they are missing:

curl -fsSL https://raw.githubusercontent.com/VictorForV/intervals-mcp/master/install.sh | sudo bash

Review install.sh before running it if you prefer not to pipe a remote script to a privileged shell. Manual installation remains available by cloning the repository and running ./manage.sh after installing the prerequisites.

Choose Initial setup. The manager asks for the public hostname, a short athlete name, and the Intervals.icu athlete ID and API key. The ID and key are available under Settings → Developer Settings in Intervals.icu. The API key uses hidden input.

The manager creates owner-only configuration, generates a strong random URL token, starts the service, and prints the connector URLs. Run ./manage.sh later to add, list, edit, or remove athletes, rotate URLs, rebuild, restart, or inspect the service.

Connecting an AI client

Each athlete receives two secret URLs:

https://mcp.example.com/<secret>/mcp  # Streamable HTTP, preferred
https://mcp.example.com/<secret>/sse  # legacy SSE compatibility

Treat the complete URL like a password. It grants read access to that athlete's training and wellness data.

Claude and Claude Desktop

Open Settings → Connectors → Add custom connector and enter the /mcp URL. Availability and organization permissions depend on the Claude plan. See the current Anthropic instructions.

Claude Code

The manager prints a ready-to-run command:

claude mcp add --transport http intervals-alex https://mcp.example.com/<secret>/mcp

ChatGPT

Add the server as a custom app/connector and use the URL accepted by your current ChatGPT workspace. Availability, UI, and administrator requirements vary by plan and can change. See the current OpenAI apps documentation. The manager shows both URL formats for compatibility.

Other clients

Use /mcp with remote Streamable HTTP clients and /sse with older SSE clients. Follow the client's current documentation and never commit a secret URL to a shared configuration.

Administration

The interactive panel is the recommended interface:

./manage.sh

For automation, the same interface has subcommands:

uv run intervals-mcp-admin add
uv run intervals-mcp-admin list
uv run intervals-mcp-admin show alex
uv run intervals-mcp-admin edit alex
uv run intervals-mcp-admin rotate alex
uv run intervals-mcp-admin remove alex

Avoid --api-key in an interactive shell because command arguments can be saved in shell history or exposed in the process list. Omit it for hidden input.

Local stdio mode

For one athlete and a client that launches local processes, copy .env.example to .env, configure the Intervals.icu credentials, and run:

uv run intervals-mcp

Security model

  • Intervals.icu requests are read-only (GET).

  • Each athlete gets a separate API client and independent random path token.

  • .env and users.toml are gitignored and written with mode 0600.

  • API keys and path tokens are excluded from application and proxy access logs.

  • The public service uses HTTPS through Caddy.

  • users.toml is mounted read-only into the container.

The path token is bearer authentication: anyone with the URL can read that athlete's data. Rotate it from ./manage.sh if exposed. See SECURITY.md for reporting issues.

Development

uv sync
uv run pytest

Tests use fully synthetic, API-shaped fixtures and make no network requests. Regenerate them with uv run python scripts/generate_fixtures.py.

See CONTRIBUTING.md for development guidelines.

License

MIT — see LICENSE.

Available Tools

15 tools
get_activityA

One activity by id, in the same shape as a list_activities entry.

    Use it when you already have an id (from list_activities, an event,
    or the athlete) and want that one activity without re-listing a whole
    window. It does not currently surface fields list_activities omits.
    

Inputs: activity_id (required).

get_activity_intervalsA

Laps and detected intervals inside one activity.

    Use it to see how a session was structured: per-lap distance, duration,
    pace, heart rate, power and zone. This is where interval execution shows
    up, such as whether reps faded.
    

Inputs: activity_id (required).

get_activity_streamsA

Time series inside one activity, downsampled.

    types is a comma-separated list, for example heartrate, velocity_smooth,
    altitude, cadence, watts, temp, latlng. Returns `points` evenly spaced
    samples per series plus min/mean/max over the whole series. points must
    be between 2 and 2000. The raw data can exceed ten thousand samples per
    series, so pass full=true only when the shape of every second genuinely
    matters -- not a small `points` value, which is rejected rather than
    silently answered with the full series.

    latlng sometimes comes back from intervals.icu as latitude only rather
    than [lat, lon] pairs; when that happens the series carries a note
    saying so instead of a silently wrong coordinate.
    

Inputs: activity_id (required), full, types, points.

get_athlete_profileA

The athlete's profile: name, location, timezone, sex.

    Read this first when you need to interpret local times or address the
    athlete by name.
    

Inputs: no named parameters.

get_best_effort_chartA

A PNG of the best-effort curve for a sport: HR, pace or power against duration or distance, log-scaled since a curve spans seconds to hours.

    kind is hr, pace or power, same as get_best_efforts. Use this when the
    shape of the curve -- a plateau, a cliff past some duration -- says
    more than the ten named points get_best_efforts returns.
    

Inputs: kind (required), newest, oldest, sport_type.

get_best_effortsA

Best-effort curve for a sport: the athlete's peak sustained values.

    kind is hr, pace or power. Returns the best value held for 5s, 15s, 30s,
    1m, 5m, 10m, 20m, 30m, 1h and 1h30m over the window, which defaults to
    the last 12 months. Use it to compare current form against past peaks.
    

Inputs: kind (required), newest, oldest, sport_type.

get_eventsA

Planned calendar entries: future workouts, races and goals.

    Defaults to today through 28 days ahead. Pass an earlier oldest to see
    what was planned in the past. An empty list means nothing is scheduled.
    

Inputs: newest, oldest.

get_gearA

Registered gear such as shoes and bikes, with accumulated distance.

Useful for mileage on a given pair of shoes. An empty list means the athlete tracks no gear.

Inputs: no named parameters.

get_sport_settingsA

Training zones and thresholds per sport: FTP, LTHR, max HR, power, heart-rate and pace zones, sweet spot range.

    Read this before judging whether a session was easy or hard; zone
    boundaries differ per sport.
    

Inputs: no named parameters.

get_training_load_chartA

A PNG chart of CTL (fitness), ATL (fatigue) and TSB (form) over time.

Defaults to the last 90 days, the usual window for seeing a build and a taper. Use this when a shape -- a spike, a plateau, a steady climb -- says more than the numbers would on their own.

Inputs: newest, oldest.

get_training_readinessA

Assess current form from CTL/ATL/ramp rate and recent HRV, coach-style.

    Defaults to a six-week window so recent HRV has a real baseline to
    compare against. Returns TSB (fitness minus fatigue) classified into a
    band -- high_risk, overreaching, neutral, fresh, very_fresh -- each
    with a plain-language note, plus a ramp-rate read (declining,
    maintaining, building, aggressive) and, when HRV is logged, the last
    7 days against the rest of the window with a flag if it has dropped
    more than 10% below baseline.
    

Inputs: newest, oldest.

get_wellnessB

Daily wellness and training-load history.

    Defaults to the last 30 days. Per day: CTL (fitness), ATL (fatigue),
    ramp rate, plus whatever the athlete logs — weight, resting HR, HRV,
    sleep, soreness, fatigue, stress, mood, motivation. This is the record
    to read before judging whether load is sustainable.
    

Inputs: newest, oldest.

intervals_get_rawA

Escape hatch: GET any intervals.icu v1 path and return it unshaped.

    Use only when a dedicated tool cannot answer the question, since raw
    payloads are large. path is relative to https://intervals.icu/api/v1,
    for example "athlete/{athlete}/activities"; "{athlete}" expands to the
    configured athlete id. Pass query arguments in params, not in the path.
    This is still read-only.

    Field names are returned as-is, but values that look like credentials
    or personal contact info -- email, API keys, tokens, invitation links
    -- are replaced with "[redacted]" wherever they appear in the payload.
    

Inputs: path (required), params.

list_activitiesB

Completed activities in a date range, newest first.

    Defaults to the last 30 days. Filter by activity_type such as Run,
    TrailRun, Ride, Swim, Hike, Workout, WeightTraining, Yoga. Each entry
    carries distance, duration, pace, heart rate, elevation, training load
    and the CTL/ATL standing at the time. The response reports how many
    activities matched versus how many were returned.
    

Inputs: limit, newest, oldest, activity_type.

list_workoutsA

The athlete's saved workout library and its folders.

    These are workout templates, not completed sessions; use list_activities
    for what was actually done.
    

Inputs: no named parameters.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A4/5.0

    Scored across 15 tools

    Disambiguation5/5

    Every tool targets a distinct resource: profile, wellness, settings, activities (list vs single), intervals, streams, readiness, charts, events, best efforts, gear, workouts, and a raw fallback. Even closely related tools like get_activity_intervals and get_activity_streams are clearly separated by their descriptions.

    Naming Consistency4/5

    The naming is mostly consistent with a get_/list_ + noun pattern. The notable outlier is intervals_get_raw, which reverses the convention, and minor singular/plural inconsistency between get_best_efforts and get_best_effort_chart, but the pattern is otherwise predictable.

    Tool Count5/5

    15 tools sits right at the upper bound of a well-scoped set, and each tool maps cleanly to a meaningful part of the intervals.icu API. No redundant or filler tools; even the raw escape hatch serves a clear fallback role.

    Completeness5/5

    The surface thoroughly covers the read-only athlete analytics domain: profile, training load, wellness, activities with multiple detail levels, best efforts, charts, events, gear, and workout templates. The raw escape hatch closes any remaining gaps, making dead ends unlikely.

    Maintenance

    ActivityStale
    ResponsivenessOutdated data

    Related MCP Connectors

    Related MCP Servers