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

HerramientaQué 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.