Skip to main content
Glama
B3r3z

Intervals.icu MCP Server

by B3r3z
README.md
# Intervals.icu MCP Server

Local FastMCP server for evidence reads and typed, durable Intervals.icu
operations. The active write interface is intentionally small: one typed
operation engine plus status, read-only recovery, and an audited admin release.

## Environment

Use Python 3.12 and `uv`. The declared `tzdata` dependency is required on
Windows; use the synced project environment rather than an arbitrary global
interpreter.

```powershell
uv venv --python 3.12
uv sync --all-extras
uv run pytest -q
uv run ruff check .
uv run mypy src tests
```

Copy `.env.example` to an ignored `.env` only for a manually started local
server. Tests use synthetic transports and must not load credentials or access a
live account.

## Run locally

```powershell
$env:MCP_TRANSPORT = 'stdio'
uv run python -m intervals_mcp_server.server
```

For the repository's loopback-only Streamable HTTP setup, use the existing
startup script and `http://127.0.0.1:8000/mcp`. Do not expose that endpoint:
the local server has no separate inbound HTTP authentication.

## Public tools

The retained read surface is:

- `get_capabilities`
- `get_activities`, `get_activity_details`, `get_activity_intervals`,
  `get_activity_messages`, `get_activity_streams`,
  `get_activity_data_quality`
- `export_activity_data`, `get_artifact_chunk`
- `get_activity_interval_stats`, `get_activity_best_efforts`,
  `get_activity_power_hr`
- `get_athlete_power_curves`, `get_activity_power_curves`
- `get_metric_definitions`, `get_sport_settings`, `get_wellness_data`
- `get_events`, `get_event_by_id`, `get_workout_snapshot`
- `get_custom_items`, `get_custom_item_by_id`

The only operation tools are:

- `execute_operation`
- `get_operation_status`
- `recover_operation`
- `release_operation_risk`

`admin` exposes all four. `coach` omits risk release. `readonly` exposes
status and read-only recovery. Administrative operations carry explicit user
direction and do not fabricate a TATRA decision or session identity.

Exact pairing, resource schemas, outcome semantics, locks and read-back rules
are documented in
[docs/agent-tools-contracts.md](docs/agent-tools-contracts.md).

## Durable state and offline migration

Operation records are self-hashed and history-chained. `unknown` is not
`partial`; uncertain effects keep their exact hold. Recovery only reconciles
durable evidence and never resends a mutation.

`scripts/migrate_operation_state.py` classifies a frozen copy of older workout
and analysis-comment journals. A record is promoted to typed-v1 only when the
source already retained ready modern evidence refs and any required
evidence-bound preview; the migrated request must pass semantic scope binding.
Missing evidence, an unsafe delete date, and `prepared` are retained as
hash-sealed, non-executable legacy archives with explicit limitations. The tool
never invents evidence, previews or preconditions.

For a previously confirmed create, the migrated request retains the exact
canonical semantic `create_identity`. The upstream `event_id` or `message_id`
remains in the historical result, execution identity, read-back basis and
provenance; it is not substituted into request identity. Exact retry returns
that historical result, changed content conflicts, and neither path calls an
adapter.

The utility requires explicit offline confirmation, writes a deterministic
external backup first, rejects drive/root/UNC/traversal/backslash paths and
duplicate or case-colliding entries before writing, refuses occupied targets,
and rejects a destination equal to or nested below the canonical source before
creating backup or staging paths. Normalized `..`, symlink-parent and Windows
case aliases follow the same rule; backup and staging remain external and
distinct. It makes no upstream request and stages a candidate directory only;
switching a running installation is a separate operator action.

## Evidence boundary

Passing tests and synthetic replay do not establish live publication,
physiological validity, or account correctness. Live actions require explicit
configuration and user authority; they are outside routine test execution.

## License

GNU General Public License v3.0.

TDQS

A3.5/5.0

Scored across 26 tools

Disambiguation4/5

The tools are mostly distinct: activity streams, intervals, power curves, best efforts, and data quality each map to different upstream resources. However, several names are near-siblings (get_activity_intervals vs get_activity_interval_stats, get_activity_power_curves vs get_athlete_power_curves) and require reading descriptions to avoid misselection.

Naming Consistency4/5

Almost all reads use get_<resource>_<detail> in snake_case, with mutation verbs like export/execute/release/recover. The pattern is readable but not perfectly uniform: some singular reads use _by_id (get_event_by_id, get_custom_item_by_id) while get_activity_details and get_workout_snapshot do not follow that suffix.

Tool Count2/5

At 26 tools, the server crosses the 'too many' threshold; even though each tool has a distinct purpose, the dense activity-reader family and operation-management cluster create a large selection surface. A more consolidated design would be more appropriate.

Completeness3/5

The read/export side is very thorough: activities, streams, intervals, power curves, events, wellness, settings, custom items, and metrics are covered. However, there are no direct create/update/delete tools for activities, events, or custom items; the generic execute_operation is an indirect workaround, and there is no athlete-profile or dedicated workout-list tool beyond get_events.

Maintenance

ActivityMaintained
ResponsivenessUnresponsive