intervals-mcp
Allows creating and managing structured workouts that are synchronized to Garmin devices through intervals.icu, with diagnostic tools for push status.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@intervals-mcpCreate a 1-hour endurance ride for tomorrow and push it to my Garmin"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
intervals-mcp
Server MCP per intervals.icu: legge i dati di allenamento e crea allenamenti strutturati sul calendario, da cui intervals.icu li spinge sull'orologio (Garmin, Wahoo, Zwift, Coros, Suunto).
Usa l'API pubblica ufficiale (https://intervals.icu/api/v1, Basic auth con API key).
Setup
npm install
npm run build
cp .env.example .env # e incolla la tua API keyL'API key si trova su intervals.icu → Settings → Developer Settings → API Key.
L'athlete id (i123456) viene rilevato automaticamente dalla key; se serve forzarlo, c'è
INTERVALS_ATHLETE_ID nel .env.
Verifica che tutto risponda:
npm run smoke # solo lettura
npm run smoke -- --write # crea un allenamento di test domani, lo verifica e lo cancellaRegistrazione in Claude Code
claude mcp add intervals -- node /percorso/assoluto/intervals-mcp/dist/stdio.jsLa key non va nella config del client: il server legge il .env accanto al package.
In alternativa, per tenerla nella config: claude mcp add intervals --env INTERVALS_API_KEY=... -- node .../dist/stdio.js.
Per Claude Desktop, in claude_desktop_config.json:
{
"mcpServers": {
"intervals": {
"command": "node",
"args": ["/percorso/assoluto/intervals-mcp/dist/stdio.js"]
}
}
}In sviluppo: npm run dev (tsx, senza build).
Related MCP server: Intervals.icu MCP Server
Deploy remoto su Vercel (opzionale)
Serve solo se vuoi usarlo senza il Mac acceso — da claude.ai, dal telefono, o per condividerlo. In locale lo stdio resta più semplice e la chiave non si muove dalla tua macchina.
api/mcp.ts è una Vercel Node function che espone lo stesso server su Streamable HTTP, in
modalità stateless (server e transport costruiti per richiesta, enableJsonResponse): l'unica
che funziona su serverless, senza Redis né sessioni in memoria. Nessun framework: niente Next.js,
solo la function e l'SDK ufficiale.
Non serve creare nulla dalla dashboard: vercel link crea il progetto. L'ordine conta, perché
env add funziona solo su una directory già linkata.
npm i -g vercel
vercel login
vercel link # crea/collega il progetto (scrive .vercel/, gitignorato)
npm run token # genera il segreto, copialo
vercel env add MCP_AUTH_TOKEN production
vercel env add INTERVALS_API_KEY production
vercel --prod # primo deploySe vuoi che funzionino anche i deploy di preview, ripeti gli env add per preview: le variabili
sono per-ambiente, e un preview senza di esse risponde 500.
vercel.json dichiara outputDirectory: "public" con una pagina statica minima: senza una
directory di output, un progetto con un buildCommand fa fallire il build
("No Output Directory named 'public' found").
Env var richieste sul server: INTERVALS_API_KEY, MCP_AUTH_TOKEN, opzionale
INTERVALS_ATHLETE_ID. La API key di intervals.icu resta lato server: nel client finisce solo
il token.
Due modi per autenticarsi, perché i client differiscono
# Claude Code: header custom (supportati)
claude mcp add --transport http intervals-remote https://<deploy>/mcp \
--header "Authorization: Bearer <token>"Per i client che non mandano header custom — su claude.ai l'auth via request header esiste ma è in beta/rollout — il token va nel path, che è solo un URL:
https://<deploy>/mcp/<token>Le rewrite in vercel.json mappano /mcp e /mcp/:token sulla function. Il server accetta il
token da Authorization: Bearer, x-api-key, x-auth-token, dal path o da ?token=.
Preferisci l'header: un segreto nel path finisce nei log di richiesta. Il confronto è a tempo
costante su digest SHA-256, il 401 risponde con WWW-Authenticate e non rivela nulla, e il server
si rifiuta di partire senza MCP_AUTH_TOKEN (o con un token più corto di 24 caratteri):
meglio un 500 che un endpoint aperto che scrive sul tuo account.
Il token vale quanto la API key — chi lo ha legge e scrive sul tuo intervals.icu. Rotazione = cambio env var + redeploy. Per condividere il server con altri servirebbe OAuth vero, con il client_id da richiedere a david@intervals.icu.
npm test copre i casi di autenticazione (token valido/errato/assente, le varie vie, rotta non
confusa per token).
Il coach
Le regole operative (soglie da verificare prima di scrivere, sintassi, conferma prima di scrivere
in calendario) stanno nelle instructions del server in src/server.ts: vengono inviate a
qualunque client all'initialize, quindi valgono anche da claude.ai e dal telefono senza
ripeterle da nessuna parte.
Sopra ci va il "personaggio", che è per-client:
claude.ai — crea un Project, attiva il connector e incolla nelle istruzioni il contenuto di
docs/coach-project-instructions.md. È in italiano perché fissa anche la lingua delle risposte.Claude Code —
.claude/agents/coach.md, subagent conmodel: opus.
Entrambi definiscono un coach che prende l'iniziativa: legge form, storico e calendario da sé, propone con il motivo di ogni seduta, e scrive sul calendario solo dopo conferma.
Nessun vincolo di metodo, per scelta. I prompt contengono solo ciò che l'agent non può dedurre — i fatti sull'atleta (rientro da infortunio, caldo, carico calcolato da HR per scelta, soglia di passo non verificata), le regole tecniche di scrittura e il limite di sicurezza sul dolore. Volumi, intensità e progressione le decide l'agent, e se gli serve un vincolo lo chiede. I numeri li rilegge ogni volta dai tool, così non invecchiano nel prompt.
Modello: Opus per pianificare e analizzare, Sonnet per le domande di tutti i giorni.
Tool disponibili
Lettura
Tool | Cosa fa |
| Profilo + soglie per sport (FTP, indoor FTP, LTHR, max HR, threshold pace, zone) + configurazione push Garmin |
| Attività completate in un intervallo di date (default: ultimi 30 giorni) |
| Dettaglio di una attività: load, intensità, tempo in zona, decoupling, EF, running dynamics |
| Intervalli/lap rilevati, con potenza, HR, passo, cadenza, load per ripetuta |
| Ricerca per nome o |
| Fitness (CTL), Fatigue (ATL), Form (TSB), peso, HRV, sonno, readiness… (default: 14 giorni) |
| Allenamenti pianificati e altri eventi; con |
| Un singolo evento del calendario |
| Riferimento completo della sintassi workout di intervals.icu |
Scrittura
Tool | Cosa fa |
| Crea un allenamento strutturato sul calendario e (default) lo rilegge con i target risolti per verifica |
| Versione bulk: una settimana o un blocco in una sola chiamata, con |
| Modifica un evento esistente (solo i campi passati) |
| Cancella un evento |
| Aggiorna i valori wellness di una data |
| Diagnostica del push: upload attivo?, ultimo upload, range applicati, |
Come arrivano gli allenamenti sul Garmin
create_workoutscrive un eventocategory: "WORKOUT"sul calendario; il campodescriptioncontiene l'allenamento nella sintassi testuale di intervals.icu.intervals.icu lo interpreta e ne costruisce la struttura (
workout_doc).Se su intervals.icu → Settings, nel box Garmin, è attivo Upload planned workouts (con Garmin Connect autorizzato), i prossimi giorni di calendario vengono caricati su Garmin Connect e da lì arrivano all'orologio.
Eventuali problemi finiscono in
push_errorssull'evento →check_garmin_push.
Scrivendo i target in percentuale (di FTP / LTHR / max HR / threshold pace) l'allenamento segue automaticamente le soglie correnti dell'atleta: la conversione in watt/bpm/passo avviene al momento del push, e Garmin riceve un range (ampiezza configurabile nelle impostazioni Garmin di intervals.icu).
Esempio di description per una sessione di corsa:
Warmup
- 12m 70% Pace
Main set 5x
- 1km 100% Pace
- 90s 60% Pace
Cooldown
- 8m 65% PaceAttenzione: m significa minuti, i metri si scrivono mtr (400mtr).
La sintassi completa è in src/workout-syntax.ts, esposta anche come tool
(workout_syntax_guide) e come risorsa MCP (intervals://workout-syntax).
Troubleshooting: l'allenamento arriva sul Garmin senza target
Sintomo: sull'orologio gli step ci sono, con distanze e nomi giusti, ma ognuno mostra
"No Target". Su intervals.icu il workout_doc sembra perfetto.
Causa: manca la soglia del tipo di target usato nelle sport settings di quello sport (threshold pace per il passo, FTP per la potenza). In quel caso intervals.icu elimina i target dal file che manda al dispositivo — anche quando l'allenamento usa valori assoluti, dove la soglia non servirebbe a niente. L'HR non ne soffre se LTHR o max HR sono impostate.
Verificato decodificando il FIT generato:
curl -s -u "API_KEY:$INTERVALS_API_KEY" \
"https://intervals.icu/api/v1/athlete/0/events/<eventId>/download.fit" -o w.fit
python3 scripts/fitdump.py w.fitSenza threshold pace ogni step esce target=open; impostata la soglia, lo stesso evento
esporta target=speed con i range corretti. create_workout ora fa questo controllo da sé e
restituisce un device_export_warning prima che il problema arrivi all'orologio.
Nota: l'upload parte a fronte di una modifica dell'evento. Sistemare la soglia non ricarica necessariamente un allenamento già spinto — va toccato l'evento (basta riscriverne la description) per far ripartire il push.
Struttura
src/
index.ts bootstrap del server MCP (stdio) + risorsa sintassi
client.ts client HTTP: Basic auth, athlete id, errori parlanti
format.ts riduzione dei payload (Activity ha 183 campi) e formattazione
dates.ts date locali dell'atleta
workout-syntax.ts cheat sheet + guida completa
tools/ athlete, activities, wellness, events
scripts/smoke.ts verifica end-to-end sull'API realeNote sull'API
Auth: Basic, username letterale
API_KEY, password = la tua key.Le date sono sempre locali dell'atleta, senza timezone (
2026-08-20,2026-08-20T18:30:00).Le liste accettano
fields=per ridurre il payload: qui è già usato con set di campi curati.Spec OpenAPI completa (117 endpoint): https://intervals.icu/api/v1/docs/.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityAmaintenanceRead/write MCP server for Intervals.icu — 51 tools spanning activities, streams, wellness, calendar, gear, and sport zones, plus structured workout generation with a built-in syntax reference for cycling, running, and swimming.5852MIT
- Alicense-qualityDmaintenanceIntegrates Intervals.icu training data, wellness records, workouts, and calendar events with AI assistants through MCP tools.121MIT
- AlicenseBqualityBmaintenanceLocal MCP server for analyzing Intervals.icu accounts, creating AI-assisted training plans, and applying managed drafts to the calendar after explicit confirmation.14AGPL 3.0
- AlicenseAqualityAmaintenanceMCP server for Intervals.icu that enables AI assistants to manage athletic training data, including activities, calendar events, wellness metrics, and workout libraries.19Apache 2.0
Related MCP Connectors
MCP server for Withings health data — sleep, activity, heart, and body metrics.
List, fetch, create, edit (replace), delete and schedule structured workouts on Garmin Connect (runn
Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/ale7canna/intervals-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server