Futureweb Intervals MCP
io.github.futurewebv1.0.0b1更新於 Oct 10, 2026
Self-hosted Intervals.icu MCP server: training analytics, Garmin data, wellness, workout planning
概覽
讓助理讀取並分析 Intervals.icu 訓練資料,包括活動、間歇、健康狀態、負荷與規劃訓練,預設僅提供唯讀工具。
- 功能
- 這是一個自架的 Intervals.icu 訓練分析 MCP 伺服器。它提供 67 個工具,其中 52 個為唯讀,涵蓋一次呼叫產生的活動報告、計畫與實際執行對比、爬坡、最佳成績、雙功率計比較、自訂欄位與資料流、健康趨勢、訓練負荷和行事曆事件。寫入、破壞性與管理類工具有提供,但除非啟用對應權限類別,否則不會註冊。
- 適用情境
- 適合讓助理扮演訓練分析教練,根據你自己的 Intervals.icu 資料工作:檢視一次騎乘、比較計畫與實際執行、追蹤恢復與負荷,或規劃訓練。它是本機自架伺服器,適合希望憑證與資料留在自己電腦上的使用者。
- 執行需求
- 透過 stdio 在本機執行,可用 uvx 執行 PyPI 套件 futureweb-intervals-mcp(或 Python 3.12+ 與 pip),也可用 Docker 執行容器映像。需要 Intervals.icu API 金鑰(API_KEY)和運動員 ID(ATHLETE_ID);選用 ATHLETE_TIMEZONE、MCP_PERMISSIONS 和 MCP_TOOLSET。需要連線至 Intervals.icu API 的網路。遠端 HTTP 或 SSE 使用需要 TLS 反向代理與 OAuth 設定。
安裝
在 SourceWeft 中
- 開啟 儀表板中的 Futureweb Intervals MCP,將其新增到工作區。
- 為需要使用其工具的對話啟用該服務。
Desktop only,透過 STDIO。 STDIO 服務會啟動本機處理程序,因此需要 SourceWeft 桌面主機。
其他 MCP 客戶端
參照 儲存庫 中的啟動說明。
README
[Futureweb Intervals MCP icon]
Futureweb Intervals MCP
Advanced Intervals.icu MCP server for ChatGPT, Claude and every MCP client: Garmin-enriched metrics, every custom field and stream, recovery insights and endurance performance analysis.
[CI] [License: GPL-3.0] [Python 3.12+] [Status: public beta] [Garmin Intervals Bridge]
A Model Context Protocol server that lets AI assistants read and analyse your Intervals.icu training data the way a coach would: activities with every custom field and stream, intervals, wellness against personal baselines, thresholds and zones, planned-versus-executed workouts, climbs, dual power meters, best efforts, efficiency and fatigue resistance, nutrition and weight, training summaries and the calendar. It runs where you run it, talks only to the Intervals.icu API and exposes nothing that writes unless you enable it.
Continuation of mvilanova/intervals-mcp-server. The original project is no longer actively developed (last commit on 2 August 2026, 29 pull requests left open). This community-maintained fork carries it on: the useful open pull requests were reviewed and merged with their authors credited, the bugs fixed, and the server rebuilt around coaching analysis, Garmin data and safe remote access. Not affiliated with Intervals.icu or Garmin.
Companion project: the Garmin Intervals Bridge puts back the metrics Garmin strips from the files it sends to Intervals.icu (stamina, training effect, recovery time, VO₂max, running dynamics, sleep and HRV details …). This MCP is built to read all of it, but works just as well without the bridge.
Contents
- Highlights
- Works with the Garmin Intervals Bridge
- Tools
- Quick start
- Connect an AI client
- Sharing the server with friends
- Configuration
- Permissions and security
- Project status and roadmap
- Documentation
- Development
- Credits and license
Highlights
- Every custom item, resolved dynamically. Custom activity fields, interval fields, streams and wellness fields are read from your own definitions and reported with name, code, value and units. Nothing device-specific is hard-coded; null, NaN, zero and absent stay distinct, fields that do not belong to the sport are kept apart, and device loads are never mixed with the Intervals.icu load.
- Streams at full resolution. Any stream as summary, CSV or JSON, sliced by index or time, downsampled and paged, plus per-interval statistics of any stream (for example the stamina drop of each interval).
- Coaching analysis instead of raw dumps. One-call activity report, planned versus executed per step (also for deleted events and rides extended beyond the plan), climbs and descents, second power meter check, best efforts, similar intervals, repeated workouts over time, power-to-heart-rate efficiency, fatigue resistance, training load (acute:chronic ratio, monotony, strain), three-zone intensity distribution with polarization index, aerobic durability, load projection over the plan, recovery snapshot with 42-day baselines, wellness trends and correlations, nutrition and weight trends, weekly and monthly summaries. Statistics with their sample sizes; the interpretation stays with the coach.
- Token-efficient.
detail_level(compact,standard,full) andoutput_format="json"on the heavy tools, nine ready-made coaching prompts and two MCP resources. - Safe remote access. Built-in OAuth 2.1 server with "Continue with Intervals.icu"
sign-in, a consent page with per-connection permissions, client metadata documents with
private_key_jwt(ChatGPT), PKCE and RFC 9207. Streamable HTTP (/mcp) and SSE from one process. - Read-only by default. Tools are grouped into permission classes (
read,write,destructive,admin) enforced on the server; onlyreadis active unless you enable more. - Tested. More than 400 tests on synthetic data, ruff, mypy, CodeQL, pinned GitHub Actions, build and Docker smoke tests on every pull request.
Works with the Garmin Intervals Bridge
The Garmin Intervals Bridge writes the metrics Garmin filters out into the custom activity fields, custom streams and wellness fields you defined in Intervals.icu. The MCP reads those definitions at run time, so every restored value shows up in the tools automatically:
The MCP never contacts Garmin; the bridge is optional and other devices or sync tools that fill custom items get the same treatment. Worked examples and notes on reading the device metrics correctly: docs/GARMIN_BRIDGE.md.
Tools
67 tools; 52 of them only read. Write tools are marked ✎ (write), ✖ (destructive) or
⚙ (admin) and are hidden unless their class is enabled. Most tools accept output_format="json"
and detail_level (compact first). Tools never take an API key: credentials come only from
the server environment.
The catalogue is kept small for the AI client: short descriptions that say when to use a tool,
a description and (where the values are fixed) an enum for every parameter, and text results
without a duplicate structured copy. Method details and the workout format live in MCP resources
(intervals://methods/<topic>, intervals://workout-syntax) and in get_guide(topic) for clients
that only call tools. tools/list is about 22.7k tokens at MCP_PERMISSIONS=read,write
(was 42.0k; cl100k); see Tool sets for a smaller set.
Activity analysis
Activities and streams
Performance over time
Wellness and recovery
Athlete, gear, calendar and workouts
Custom items and server
Prompts: recovery_check, workout_deep_dive, weekly_training_review,
training_load_review, performance_progression, long_ride_climbing_analysis,
nutrition_weight_trend, power_meter_comparison, workout_planning_validation, race_week
(taper and form on race day, fueling plan from history, weather, logistics), fueling_review,
plan_health_check (load projection and what-if scenario of the planned weeks) and
coach_handoff (compact summary for another coach or session).
Resources: intervals://guide (how to use the tools), intervals://workout-syntax (the
structured workout format), intervals://methods/<topic> (how an analysis works: activity-data,
execution, climbs, power-meters, load, intensity, durability, summary, comparisons, fatigue,
wellness, fueling), intervals://custom-items (your custom item definitions).
The server also sends short instructions in the MCP initialize answer (start with
get_coach_context or get_activity_report, compact first, missing values are not normal,
writes only on request after a preview), and its icon and website in serverInfo. The HTTP
transports serve the icon without authentication at /favicon.ico, /favicon.png, /icon.png,
/icon.svg and /apple-touch-icon.png (also used on the sign-in page).
Tool sets
MCP_TOOLSET=full (default) registers every tool of the enabled permission classes.
MCP_TOOLSET=core registers a curated set of 23 tools for clients with a small tool budget (about
9.4k tokens at MCP_PERMISSIONS=read,write); MCP_PERMISSIONS still applies inside the set:
get_server_status and --doctor show the active tool set and how many tools it leaves out; tool
descriptions, prompts and guides mark the tools outside the set "(full tool set)".
After a server update that changes tools or tool sets, refresh the tool list in the client
(ChatGPT: the connector's refresh in the app settings; Claude: reconnect the connector).
Output conventions: start times are shown local with the timezone name when Intervals.icu
stores one, otherwise with the UTC offset derived from the local and UTC start, plus UTC; run,
walk and hike cadence in steps per minute (spm, 2 x the per-leg value Intervals.icu stores,
which is shown as stored), bike cadence in rpm; temperatures in °C (a temperature custom field
without units takes the unit its sibling temperature fields agree on); missing values are n/a,
never 0.
Quick start
Requirements: an Intervals.icu API key (Settings → Developer Settings) and your athlete ID
(i123456); for the Python package uv (or Python 3.12+ and pip),
for the container image Docker. Every installation runs your own server with your own
credentials; there is no hosted service.
Tagged releases are published as the PyPI package
futureweb-intervals-mcp, the container
images ghcr.io/futureweb/intervals-mcp-server and
futurewebat/futureweb-intervals-mcp
(Docker Hub), a Claude Desktop bundle (.mcpb) on the
GitHub release and an entry in the
official MCP Registry.
Beta:
1.0.0b1is a pre-release. Name the version (uvx [email protected],pip install futureweb-intervals-mcp==1.0.0b1) or allow pre-releases (uvx --prerelease allow futureweb-intervals-mcp,pip install --pre futureweb-intervals-mcp). uv and pip choose a pre-release on their own only while no final version exists; from 1.0.0 on plainuvx futureweb-intervals-mcpgets the latest final release.
From PyPI (uvx or pip)
With pip, in a virtual environment:
From source
Without cloning:
Docker
Tagged releases publish the same multi-arch image (amd64, arm64) to the GitHub Container
Registry and to Docker Hub (latest only for final versions, beta tags such as 1.0.0b1
explicitly):
With MCP_AUTH=oauth mount a volume on /data (the image keeps OAUTH_STATE_FILE there), e.g.
-v intervals-mcp:/data; otherwise every re-created container disconnects all clients.
Claude Desktop bundle (.mcpb)
Every GitHub release carries futureweb-intervals-mcp-<version>.mcpb. Open it with Claude
Desktop (double-click, or Settings → Extensions → Install Extension…) and enter the API key
(stored as a secret), the athlete ID and, optionally, the permissions (read by default) and the
tool set. The bundle contains the sources and the lock file; Claude Desktop starts it with
uv (uv run --frozen), which installs the locked dependencies on
the first start. It needs a Claude Desktop version that supports MCPB manifest 0.4 (uv
server type).
MCP Registry
Releases are listed in the official MCP Registry
as io.github.futureweb/intervals-mcp-server, with the PyPI package and the GHCR image and the
environment variables they need. Clients that read the registry can install the server from
there. The entry lists packages only: every user runs an own instance with their own
Intervals.icu credentials.
Connect an AI client
Claude Desktop and Claude Code (local, stdio)
Besides the bundle above, Claude Desktop can start the server from PyPI with uvx (add to
claude_desktop_config.json; Claude Desktop needs the full path to uvx if it is not on its
PATH, e.g. /Users/you/.local/bin/uvx):
With Docker instead (the values come from env, -e NAME passes them into the container):
From a source checkout:
Claude Code: claude mcp add intervals-icu -e API_KEY=your-api-key -e ATHLETE_ID=i123456 -- uvx [email protected],
or from a checkout claude mcp add intervals-icu -- uv --directory /path/to/intervals-mcp-server run futureweb-intervals-mcp.
ChatGPT, Claude.ai and other remote clients (OAuth)
Remote clients need an HTTPS endpoint. Run the server behind a TLS reverse proxy with OAuth:
- Choose the sign-in: without further settings you sign in with your Intervals.icu API key
(optionally plus an authenticator code,
OAUTH_TOTP_SECRET). For Continue with Intervals.icu create an OAuth app at https://intervals.icu/oauth/apply with the redirect URLhttps://mcp.example.com/oauth/intervals/callback; a server password is the third option. - In ChatGPT (developer mode) add a connection with the URL
https://mcp.example.com/mcpand authentication OAuth; leave client id and secret empty. Claude.ai: Add custom connector with the same URL. - On the consent page choose the permissions for this connection and sign in. With
Intervals.icu only the athletes in
OAUTH_ALLOWED_ATHLETES(defaultATHLETE_ID) can sign in. - After server updates use Refresh on the ChatGPT connection to reload the tools.
Everything about the OAuth server, the reverse proxy (Apache and nginx examples) and the
security model: docs/REMOTE_ACCESS.md. Clients without OAuth can use a
secret endpoint path instead (FASTMCP_SSE_PATH=/mcp-<random>/sse).
Sharing the server with friends
By default the server is single-user (MCP_TENANCY=single): every tool call uses the
server's API_KEY and ATHLETE_ID. Whoever is allowed to connect sees your data, so in this
mode the server refuses to start when OAUTH_ALLOWED_ATHLETES names anyone but you (your own
other Intervals.icu accounts can be listed in OAUTH_OWNER_ACCOUNTS).
To let a few friends use the same deployment with their own Intervals.icu data, switch to the optional multi-user mode:
Setup (details in docs/REMOTE_ACCESS.md):
Run the grants and token-key commands as the service user with the server's environment
(OAUTH_STATE_FILE, ATHLETE_ID), e.g. docker exec -u <uid> in the container. As root they
refuse to change a state directory that belongs to another user (--allow-root overrides; they
never follow links there). Connections from the single-user mode that were not adopted are
refused in the multi-user mode, never treated as yours. If you roll back to an older release after
this one, it drops the recorded athletes again: connections created or refreshed meanwhile need
grants adopt-legacy --owner once more before the next switch (until then they are refused).
Your friends add the same connector URL in ChatGPT or Claude, choose the permissions on the
consent page and approve the Intervals.icu app. The Intervals.icu permissions requested match
the classes they choose (read asks for ACTIVITY, WELLNESS, CALENDAR, LIBRARY and
SETTINGS read access; write and higher add the write scopes the tools need). Activity comments
need Intervals.icu's CHATS permission, which also covers private chats: it is never requested
unless you set INTERVALS_OAUTH_OFFER_CHATS=true and the athlete ticks "Activity comments" on
the consent page; otherwise the two comment tools say that the permission is missing.
What is stored. Per connection the state file keeps the athlete id, the MCP client, creation
and last-use dates, the granted Intervals.icu scopes and the athlete's Intervals.icu access token,
encrypted with the key from OAUTH_TOKEN_KEY / OAUTH_TOKEN_KEY_FILE (without the key the token
cannot be read; keep the key apart from backups of the state file). At most
OAUTH_MAX_GRANTS_PER_ATHLETE connections (default 5) are kept per athlete; your own are never
evicted. Data is not cached on
disk; in-memory caches expire within minutes and are separated per connection.
Privacy. Wellness data such as HRV, sleep, resting heart rate or weight is health data (in the
EU a special category under Art. 9 GDPR), and as the operator you are responsible for it. Invite
only people who explicitly agree, tell them in a short note what is stored (above), who can see it
(you: the state file and the server logs with athlete ids, tool names, request paths and errors,
never tokens or data bodies), how long logs are kept (e.g. journalctl --vacuum-time=14d) and how
to leave. Keep the deployment patched. If the key or the state file may have leaked, put a new key
first in OAUTH_TOKEN_KEY, and ask your friends to revoke the app at Intervals.icu.
Deletion. A connection's stored token is deleted when the MCP client revokes the connection on
disconnect (/revoke; not every client does), after OAUTH_REFRESH_TOKEN_TTL without use (default
30 days; OAUTH_TOKEN_RETENTION_DAYS makes it shorter), or with the grants command. To remove a
friend completely:
futureweb-intervals-mcp grants remove <athlete id>(a running server drops the connections at its next request);- remove the athlete from
OAUTH_ALLOWED_ATHLETESand restart; - the friend revokes the app in their Intervals.icu settings (the server cannot revoke one token without disconnecting all of the athlete's connections; until then the deleted token would still be valid at Intervals.icu);
- optionally purge old log lines (
journalctl --vacuum-time=...).
Limits. All athletes share the request limits of the one Intervals.icu OAuth app: every
athlete has a daily soft budget (MCP_ATHLETE_DAILY_REQUESTS, default 1000), all together a
15-minute budget (MCP_APP_REQUESTS_PER_15MIN, default 2000) of which one athlete may use at most
MCP_ATHLETE_SHARE_PERCENT (default 25; 0 still allows one request per window, 100 means no
per-athlete limit) and the others leave MCP_OWNER_RESERVED_PERCENT (default 20; 100 blocks every
athlete but you) to you; retries count. The per-call limit applies on top. get_server_status shows the mode
and the calling connection's own athlete, scopes and budget, never other users. Switching back to
single drops the other athletes' connections and tokens at the next write; your own connections
keep working in both modes.
Configuration
Environment variables; a .env file in the working directory is loaded automatically
(.env.example).
Further OAuth options (client and redirect host allowlists, token lifetimes, rate limit) are listed in docs/REMOTE_ACCESS.md.
Permissions and security
Tools of a disabled class are not registered at all. With OAuth, each connection additionally
gets only the classes granted on the consent page (intervals:read, intervals:write, …);
other tools are hidden from it and refused if called.
Write tools that can replace existing values (add_or_update_event, add_or_update_note,
update_activity, update_wellness) carry the MCP hint destructiveHint: true, so clients ask
before running them; their class stays write. Nothing is created, paired, renamed or deleted
automatically: delete_events_by_date_range first only lists what matches; it deletes only with
dry_run=false and the confirmed ids from that list (confirm_ids), touches only the named
categories (default planned workouts), at most 31 days, never workouts already paired with an
activity unless asked. Empty values from a client never wipe existing text or workouts.
Every write is predictable and verifiable (details: write safety in intervals://guide):
-
dry_run=trueon every create/update tool (includingcreate_custom_item) returns the exact request (method, path, body after all defaults and merges, as compact JSON) and the validation result; no write request is sent (the server refuses every non-GET request during a dry run). -
Creating an event (single, bulk or from the library) first reads the events of its date (one request over the date range) and refuses a duplicate (same category and sport with the same name, or the same non-trivial workout or text) unless
allow_duplicate=true; a brick day or an AM/PM pair with different names is not a duplicate. The bulk tool decides per entry, lists the refused ones and creates planned double sessions (same name, different content). -
After every event or library workout write the answer reads back what Intervals.icu stored and parsed: date, name, category, sport, duration, load, steps parsed vs sent and parse warnings (notes: date, name, category, text length).
-
delete_event,delete_library_workoutanddelete_custom_itemread the object first and name what was deleted; a missing id deletes nothing. -
Credentials never appear in logs or tool output; in the single-user mode the Intervals.icu sign-in token is used for the identity check only and never stored (in the multi-user mode it is stored encrypted, see above).
-
Never expose the HTTP transports without OAuth or a secret path, and always behind TLS.
-
In the single-user mode one deployment serves one athlete's API key and the sign-in allowlist decides who may connect; share a deployment only in the multi-user mode.
Details and how to report a vulnerability: SECURITY.md.
Project status and roadmap
1.0.0b1 is the first public beta of this fork. Development happens in reviewed pull requests;
main is protected and every change runs the full CI.
Done
- Custom fields, custom streams and interval statistics for any device data (also offered upstream as mvilanova/intervals-mcp-server#153)
- Coaching tools, permission classes, upstream fixes and merged community pull requests
- Performance analytics, execution analysis for deleted and extended workouts, detail levels, one-call activity report, prompts and resources
- OAuth with "Continue with Intervals.icu", per-connection permissions, client metadata documents, streamable HTTP and SSE in one process
- Analytics quality: extended rides split correctly, only comparable intervals compared, custom field aggregation by meaning, clear wellness periods, minimum sample sizes for efficiency trends, honest fatigue resistance, smoothed climb grades, compact report
- Training load and intensity: acute:chronic ratio, monotony and strain, three-zone distribution with polarization index, aerobic durability, load projection and a weekly coach context
Next
- First tagged release: PyPI package, GHCR and Docker Hub images, MCP Registry entry and Claude Desktop bundle, all published by the release workflow from one tag
- Optional multi-athlete mode that uses each athlete's own Intervals.icu OAuth token
- Migration to MCP SDK v2 once it is stable for the transports used here
Documentation
Development
CI runs ruff, mypy and pytest on Python 3.12 and 3.13, builds and imports the wheel and sdist,
builds and smoke-tests the Docker image and the Claude Desktop bundle, validates server.json
against the MCP Registry schema, lints the workflows, and CodeQL scans the code. All GitHub Actions are pinned
to commit SHAs; Dependabot keeps them and the dependencies current. Releases are built from tags
(docs/RELEASE_CHECKLIST.md,
RELEASING.md); beta tags become GitHub pre-releases.
Contributions are welcome: see CONTRIBUTING.md. Never put real athlete data, API keys or hostnames into issues, fixtures or logs.
Credits and license
Original project by Marc Vilanova and contributors: mvilanova/intervals-mcp-server. This fork integrates community pull requests by arnold-maderthaner (#140, #142 to #147), biochaos (#131) and kokostitiahah (#149), and fixes reported and the training load and intensity metrics proposed by morritter (#150); thank you. Maintained by Futureweb, together with the Garmin Intervals Bridge.
Licensed under the GNU General Public License v3.0, see LICENSE. Intervals.icu and Garmin are trademarks of their respective owners and are used only to describe compatibility.
來源:README.md,提交 1090ba7
工具
0版本歷史
1- v1.0.0b1最新Oct 10, 2026


