Garmin Training MCP
Lee tus datos de entrenamiento de Garmin y escribe entrenamientos estructurados de vuelta a tu reloj. Carreras, parciales, sueño y frecuencia cardíaca entran; sesiones de running y fuerza se programan en el dispositivo. Se ejecuta localmente vía stdio, o alojado con OAuth 2.1.
Documentación
garmin-mcp
Pregúntale a Claude sobre tus datos de Garmin y haz que escriba la sesión en tu reloj.
Un MCP local que conecta Claude Desktop con tu propia cuenta de Garmin Connect. Lee tus carreras, splits, zonas de frecuencia cardíaca y métricas diarias de salud — y, a diferencia de las integraciones de solo lectura de Garmin que existen, puede construir un entrenamiento estructurado y programarlo, para que la respuesta a "¿qué debería correr el jueves?" termine en tu muñeca en lugar de en un registro de chat.
Todo se ejecuta como un subproceso local en tu máquina. Sin alojamiento, sin servidor que guarde tus credenciales, sin exposición a la red.
You: My last three runs are all at the same effort. Give me something harder
for Thursday, based on what my recent paces actually support.
Claude: [reads your activities and splits, then proposes]
Thursday Threshold (running, about 52m 55s)
warmup: 15m
5 x
interval: 1.00 km @ 4:00/km-4:10/km
recovery: 1m 30s
cooldown: 10m
Create this and put it on Thursday?
Instalación
macOS 10.15 (Catalina) o más reciente, con Claude Desktop ya instalado:
curl -fsSL https://raw.githubusercontent.com/Bartolome69/garmin-mcp/main/scripts/bootstrap.sh | bash
Eso descarga el código a ~/garmin-mcp, instala un Python moderno mediante
uv, te inicia sesión en Garmin y registra el
servidor con Claude Desktop. Es el único comando que la mayoría de la gente necesita. Léelo
primero si prefieres —
scripts/bootstrap.sh es corto.
Luego cierra Claude Desktop por completo (⌘Q) y vuelve a abrirlo.
Instalación manual, o en Linux
git clone https://github.com/Bartolome69/garmin-mcp.git
cd garmin-mcp
./scripts/setup.sh # venv + dependencies
./scripts/login.sh # sign in to Garmin once, caches the session
Luego regístralo con tu cliente MCP. Para Claude Desktop en macOS,
./scripts/install-claude-desktop.sh lo hace (con la aplicación cerrada). Para cualquier
otra cosa, copia .mcp.json.example, completa las rutas absolutas y apunta tu cliente
a python -m garmin_mcp a través de stdio.
Herramientas
| Herramienta | Qué devuelve |
|---|---|
get_activities(limit, start_date, end_date) | Carreras, paseos y entrenamientos: distancia, duración, ritmo por km y milla, FC media y máxima, zonas de FC, cadencia, efecto del entrenamiento, además de dinámica de carrera y potencia cuando el reloj las registra |
get_activity_details(activity_id) | Una actividad en detalle: distancia por split, ritmo, FC, cadencia, dinámica de carrera y potencia, más el tiempo completo en zona de FC |
get_daily_summary(date) | Pasos, distancia, calorías, FC en reposo/mínima/máxima, batería corporal, estrés, minutos de intensidad |
get_sleep_data(date) | Etapas de sueño con duraciones y porcentajes, puntuación de sueño, VFC nocturna, FC en reposo |
list_workouts(limit) | Entrenamientos estructurados guardados en la cuenta |
create_workout(name, steps, sport, description) | Construye un entrenamiento estructurado y lo añade a Garmin Connect |
schedule_workout(workout_id, date) | Coloca un entrenamiento en una fecha, que es lo que lo sincroniza con el reloj |
unschedule_workout(date, schedule_id) | Quita un entrenamiento de un día. Reversible: el entrenamiento en sí se conserva |
delete_workout(workout_id, confirm) | Elimina un entrenamiento. La primera llamada solo lee su nombre; eliminarlo requiere una segunda llamada que cite ese nombre |
get_plan_chart(weeks_back, weeks_forward) | Dibuja el plan como imagen para la conversación: las sesiones de cada día junto a lo planificado |
get_progress(weeks) | Qué sesiones planificadas se completaron realmente, semana a semana. Cuenta una sesión si ocurrió dentro de un día antes o después de su día programado |
get_profile() | VO2 máx y récords personales: 5k, 10k, medio maratón, maratón y el resto |
get_connection_status() | Si el servidor tiene sesión iniciada, qué cuenta (enmascarada) y el estado de la caché de tokens |
Las fechas aceptan YYYY-MM-DD, today, yesterday, tomorrow o un desplazamiento con signo
como -7 o +3.
Escribir entrenamientos
create_workout toma una lista ordenada de pasos. Cada uno tiene un type (warmup,
interval, recovery, rest, cooldown o repeat), exactamente uno de
duration_seconds o distance_meters, y un objetivo opcional: ya sea pace
(minutos por km, como "4:05" o un rango ["4:00","4:10"]) o hr ([150, 165]).
Calentamiento de 15 minutos, 5×1 km a 4:05 con recuperaciones de 90 segundos, enfriamiento de 10 minutos:
[{"type": "warmup", "duration_seconds": 900},
{"type": "repeat", "times": 5, "steps": [
{"type": "interval", "distance_meters": 1000, "pace": "4:05"},
{"type": "recovery", "duration_seconds": 90}]},
{"type": "cooldown", "duration_seconds": 600}]
Un ritmo único se amplía 5 s/km a cada lado, porque Garmin alerta sobre un rango y un objetivo exacto pita constantemente. Los grupos repetidos no se anidan. Crear un entrenamiento solo lo guarda: prográmalo en una fecha para que llegue al reloj.
Qué puede y qué no puede hacer con tu cuenta
La lectura no tiene restricciones. La escritura se limita a la biblioteca de entrenamientos: crear un entrenamiento, programarlo, desprogramarlo, eliminarlo. Nada llega a tu historial de entrenamiento: ninguna herramienta elimina o edita una actividad registrada, así que una carrera que hayas hecho no se puede perder aquí, por muy mal que salga una llamada a una herramienta.
delete_workout está protegido en lugar de confiar en un docstring. La primera llamada
nunca elimina: lee el entrenamiento y devuelve su nombre, y solo una segunda
llamada que pase ese nombre como confirm lo elimina. Un modelo no puede destruir un entrenamiento
que no haya nombrado primero.
Tu contraseña se lee del entorno, se envía directamente a Garmin y nunca
se escribe en disco. Solo se guarda en caché el token de sesión que emite Garmin, en
~/.garmin-mcp/tokens.json, escrito 0600 dentro de un directorio 0700. Ninguna herramienta
devuelve la contraseña ni el token: get_connection_status informa de una dirección
enmascarada y de la antigüedad y permisos de la caché, nada más. Los registros van a stderr, así que
nunca corrompen el flujo MCP en stdout.
Después del primer inicio de sesión, el servidor funciona con el token en caché. Configura
GARMIN_EMAIL y GARMIN_PASSWORD en el entorno del servidor si quieres
que se vuelva a autenticar sin supervisión cuando ese token expire eventualmente; deja
GARMIN_PASSWORD fuera y volverás a ejecutar scripts/login.sh en su lugar.
Si no funciona
Empieza aquí: recorre desde el intérprete hasta una llamada real a Garmin y nombra el primer eslabón roto:
./scripts/doctor.sh
"Garmin está limitando los inicios de sesión desde esta dirección IP (429)" — el fallo más común, y no es tu contraseña: Garmin bloquea por dirección de red antes de comprobar las credenciales. El wifi de la oficina, las redes universitarias y las VPN son los más afectados. Inicia sesión una vez con un punto de acceso del móvil; después se usa la sesión en caché.
"Garmin pide un código multifactor" — el servidor no puede pedir
por stdio, así que ejecuta ./scripts/login.sh en una terminal una vez. Gestiona el código y
guarda la sesión en caché.
Claude no ve las herramientas — Claude Desktop carga su configuración al iniciar y
escribe su propia copia al cerrar, así que un cambio hecho mientras está en ejecución
desaparece. Ciérralo por completo, ejecuta ./scripts/install-claude-desktop.sh, vuelve a abrirlo.
La instalación falla mencionando Rust, OpenSSL o un compilador — macOS es demasiado antiguo.
El mínimo absoluto es 10.15 (Catalina), establecido por el propio intérprete de Python:
la compilación Intel de uv está compilada con minos 10.15 y no se iniciará por debajo de eso, así que
ninguna fijación de paquetes ayuda. Los instaladores pasan --only-binary :all: para que
esto falle rápido en lugar de convertirse en una compilación de fuente condenada, y reintentan contra
constraints-legacy.txt en caso de que un paquete simplemente haya soltado una rueda.
Sin datos de sueño — el reloj no se usó durante la noche o no se ha sincronizado. El sueño, la VFC y la batería corporal nocturna solo existen si duermes con él.
Habilidades de entrenamiento
skills/ contiene metodología de entrenamiento que se basa en las herramientas: cómo
leer los datos y qué prescribir a partir de ellos. La primera es una habilidad de medio
maratón al estilo de Pete Pfitzinger.
Desarrollo
.venv/bin/python tests/smoke_test.py
Conduce el servidor a través de stdio real como lo haría un cliente MCP, contra una cuenta de Garmin simulada: sin red, sin credenciales. Cubre la forma de respuesta de cada herramienta, la construcción de entrenamientos, la entrada incorrecta y la ruta de inicio sin credenciales.
.venv/bin/python -m garmin_mcp.check
La misma ruta de código contra tu cuenta real, imprimiendo lo que devuelve. Útil para confirmar una configuración de principio a fin.
Otros clientes MCP y ChatGPT
Nada aquí es específico de Claude: habla MCP a través de stdio, así que cualquier cliente que
lance un servidor local lo ejecutará: Claude Code, Cursor, VS Code, Zed,
Windsurf. Copia .mcp.json.example, completa las rutas absolutas, apunta el cliente a
python -m garmin_mcp.
ChatGPT no puede ejecutar esto. Sus conectores toman una URL HTTPS pública a través de SSE, porque ChatGPT se ejecuta en los servidores de OpenAI y no puede iniciar un proceso en tu máquina: no hay opción de servidor local que habilitar. Servirlo a ChatGPT significaría alojarlo públicamente y guardar las credenciales de Garmin de los usuarios, que es exactamente lo que este proyecto evita.
Advertencias
No está afiliado a Garmin. Usa la misma API privada que usa el sitio web de Garmin Connect, a través de
garminconnect, porque
Garmin no publica una API OAuth de consumo. Esa API puede cambiar sin previo aviso y
llevarse esto consigo.
Licencia MIT. Construido con Claude Code.