MCP server, CLI, and Python library for the Intervals.ICU fitness tracking API
Project description
intervals-kit
MCP server, CLI, and Python library for the Intervals.ICU fitness tracking API. Exposes activity data (power curves, HR curves, streams, intervals, segments, file downloads) to AI assistants via the Model Context Protocol, and as a command-line tool for scripting and bulk data access.
Requirements
- Python 3.10+
- uv — recommended for running the package
Installation
pip install intervals-kit
Or with uv:
uv pip install intervals-kit
Configuration
The package reads credentials from environment variables or a config file.
Environment variables (recommended):
export INTERVALS_API_KEY=your_api_key # From intervals.icu → Settings → API Key
export INTERVALS_ATHLETE_ID=iXXXXXX # Your athlete ID (visible in the URL when logged in)
Config file (~/.config/intervals-kit/config.toml):
api_key = "your_api_key"
athlete_id = "iXXXXXX"
base_url = "https://intervals.icu" # optional
Environment variables take precedence over the config file.
Usage as MCP Server (Claude Code / Claude Desktop)
The easiest way — no installation needed:
{
"mcpServers": {
"intervals-icu": {
"command": "uvx",
"args": ["intervals-kit"],
"env": {
"INTERVALS_API_KEY": "your_api_key",
"INTERVALS_ATHLETE_ID": "iXXXXXX"
}
}
}
}
Once configured, Claude can directly query your training data:
"How many rides did I do last month?" "What was my best 5-minute power in March?" "Download my activities as a CSV for Q1 2025."
Available MCP Tools
| Tool | Description |
|---|---|
list_activities |
List activities for a date range |
get_activity |
Get full details for a single activity |
search_activities |
Search by name or tag |
update_activity |
Update name, description, type, or RPE |
get_activity_intervals |
Get lap/split data |
get_activity_streams |
Get second-by-second time-series (power, HR, cadence, …) |
get_power_curve |
Mean-maximal power curve for an activity |
get_hr_curve |
Heart rate curve for an activity |
get_pace_curve |
Pace curve for running/swimming |
get_best_efforts |
Best efforts detected in an activity |
get_activity_segments |
Matched Strava/Intervals segments |
get_activity_map |
GPS track (lat/lon) |
get_athlete_power_curves |
Best power curves across a date range |
get_athlete_hr_curves |
Best HR curves across a date range |
For large data (streams >1 hour, CSV exports, binary files) the MCP tools return metadata and tell Claude to use the CLI for the actual download.
Usage as CLI
uvx --from intervals-kit intervals-icu-tools --help
Activity commands
# List activities for a date range (JSON to stdout)
uvx --from intervals-kit intervals-icu-tools list-activities --oldest 2025-01-01 --newest 2025-03-31
# Save to a file instead of stdout
uvx --from intervals-kit intervals-icu-tools -o ./data list-activities --oldest 2025-01-01 --newest 2025-03-31
# Get a single activity
uvx --from intervals-kit intervals-icu-tools get-activity i136292802
# Search by name or tag (# prefix for exact tag match)
uvx --from intervals-kit intervals-icu-tools search-activities "long ride"
uvx --from intervals-kit intervals-icu-tools search-activities "#race" --full
# Update fields
uvx --from intervals-kit intervals-icu-tools update-activity i136292802 --perceived-exertion 7 --description "Felt strong"
Sub-resource commands
# Lap/interval data
uvx --from intervals-kit intervals-icu-tools get-intervals i136292802
# Time-series streams (specify types to limit size)
uvx --from intervals-kit intervals-icu-tools -o ./data get-streams i136292802 --types watts,heartrate,cadence
# Power / HR / pace curves
uvx --from intervals-kit intervals-icu-tools get-power-curve i136292802
uvx --from intervals-kit intervals-icu-tools get-hr-curve i136292802
uvx --from intervals-kit intervals-icu-tools get-pace-curve i136292816 # running activity
# Best efforts, segments, GPS map
uvx --from intervals-kit intervals-icu-tools get-best-efforts i136292802
uvx --from intervals-kit intervals-icu-tools get-segments i136292802
uvx --from intervals-kit intervals-icu-tools -o ./data get-activity-map i136292802
File download commands
# Download original upload / FIT / GPX file
uvx --from intervals-kit intervals-icu-tools -o ./data download-activity-file i136292802 --type fit
uvx --from intervals-kit intervals-icu-tools -o ./data download-activity-file i136292802 --type gpx
# Bulk CSV export for a date range
uvx --from intervals-kit intervals-icu-tools -o ./data download-activities-csv --oldest 2025-01-01 --newest 2025-03-31
Aggregate curves
# Best power/HR/pace curves across all activities in a date range
uvx --from intervals-kit intervals-icu-tools get-athlete-power-curves --oldest 2025-01-01 --newest 2025-03-31
uvx --from intervals-kit intervals-icu-tools get-athlete-hr-curves --oldest 2025-01-01 --newest 2025-03-31
uvx --from intervals-kit intervals-icu-tools get-athlete-pace-curves --oldest 2025-01-01 --newest 2025-03-31
Global options
| Option | Default | Description |
|---|---|---|
-o / --output-dir |
. (stdout) |
Directory to save output files |
-f / --format |
json |
Output format: json or csv |
Exit codes
| Code | Meaning |
|---|---|
| 0 | Success |
| 1 | Auth error or general API error |
| 2 | Rate limit exceeded (retryable) |
| 3 | Download / network error (retryable) |
| 4 | Resource not found |
Usage as Python Library
import asyncio
from intervals_kit import IntervalsService, load_config
async def main():
svc = IntervalsService(load_config())
# List March 2025 activities
activities = await svc.list_activities("2025-03-01", "2025-03-31")
rides = [a for a in activities if a.type == "Ride"]
print(f"Rides: {len(rides)}, Runs: {len(activities) - len(rides)}")
# Get power curve for first ride
if rides:
curve = await svc.get_power_curve(rides[0].id)
print(f"Power curve keys: {list(curve.keys())}")
asyncio.run(main())
Development
# Clone and install with dev dependencies
git clone https://github.com/jrsassen/intervals-kit
cd intervals-kit
uv sync
# Run tests
uv run pytest
# Run a single test
uv run pytest tests/test_service.py -k test_name
# Run integration tests against the real API (requires credentials)
uv run pytest -m integration
Architecture
Three interfaces share one service layer — see SPECIFICATIONS.md for the full architecture and src/intervals_kit/cli_tools.md for the complete CLI reference intended for LLM agents.
MCP Tools (FastMCP) ──┐
CLI Commands (Click) ──┼──▶ service.py ──▶ client.py ──▶ Intervals.ICU API
Python import ──┘
Source layout:
src/intervals_kit/
├── errors.py # Exception types
├── models.py # Pydantic models
├── config.py # Configuration loading
├── client.py # HTTP client (auth, error mapping, streaming)
├── exporters.py # JSON serialization
├── service.py # All business logic
├── mcp_server.py # FastMCP tool definitions
└── cli/ # Click command definitions
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file intervals_kit-0.1.1.tar.gz.
File metadata
- Download URL: intervals_kit-0.1.1.tar.gz
- Upload date:
- Size: 153.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d55f43d5c077bbb6953fe788bbe98f37d0963a706b518b8ddf578587083666a7
|
|
| MD5 |
4cd85432740b816631c6af5b5a80e8be
|
|
| BLAKE2b-256 |
5e3fe3ab40f68b9c660c428cdf229f71ad830abf7863ac2b59d43d04a2d2ce12
|
Provenance
The following attestation bundles were made for intervals_kit-0.1.1.tar.gz:
Publisher:
publish.yml on jrsassen/intervals-kit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
intervals_kit-0.1.1.tar.gz -
Subject digest:
d55f43d5c077bbb6953fe788bbe98f37d0963a706b518b8ddf578587083666a7 - Sigstore transparency entry: 1254108172
- Sigstore integration time:
-
Permalink:
jrsassen/intervals-kit@b81c951ac1cec6aa5b1ccbc3108236bac81c7fb7 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/jrsassen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b81c951ac1cec6aa5b1ccbc3108236bac81c7fb7 -
Trigger Event:
push
-
Statement type:
File details
Details for the file intervals_kit-0.1.1-py3-none-any.whl.
File metadata
- Download URL: intervals_kit-0.1.1-py3-none-any.whl
- Upload date:
- Size: 29.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0bdddddc1e80845fbad64f973c1b720dc1c8428463230b3da173a8b6543c383a
|
|
| MD5 |
24dc78de68b65cfb68ff17abbf625f16
|
|
| BLAKE2b-256 |
6d3db77db01b0ef74a144744fd1714aef90cd0c8e71df5d3efb576bd2bcf43c0
|
Provenance
The following attestation bundles were made for intervals_kit-0.1.1-py3-none-any.whl:
Publisher:
publish.yml on jrsassen/intervals-kit
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
intervals_kit-0.1.1-py3-none-any.whl -
Subject digest:
0bdddddc1e80845fbad64f973c1b720dc1c8428463230b3da173a8b6543c383a - Sigstore transparency entry: 1254108287
- Sigstore integration time:
-
Permalink:
jrsassen/intervals-kit@b81c951ac1cec6aa5b1ccbc3108236bac81c7fb7 -
Branch / Tag:
refs/tags/v0.1.1 - Owner: https://github.com/jrsassen
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@b81c951ac1cec6aa5b1ccbc3108236bac81c7fb7 -
Trigger Event:
push
-
Statement type: