Configuration Garmin¶
Cette page détaille l'accès à Garmin Connect utilisé par ai-running-coach.
Architecture¶
Mode direct (défaut)¶
flowchart LR
A["Votre IDE<br/>(agent IA)"] --> B["garmin-mcp<br/>(serveur, liste blanche)"]
B --> C["Garmin Connect<br/>(API)"]
Mode passerelle (optionnel — power user)¶
flowchart LR
A["Votre IDE<br/>(agent IA)"] --> B["leanproxy-mcp<br/>(passerelle)"]
B --> C["garmin-mcp<br/>(serveur)"]
C --> D["Garmin Connect<br/>(API)"]
garmin-mcp— serveur MCP qui expose les données Garmin Connect (activités, santé, sommeil, calendrier, planification d'entraînements). Mode direct par défaut : il est enregistré directement dans votre IDE avec une liste blanche d'outils (GARMIN_ENABLED_TOOLS) pour réduire la taxe de contexte (~151 outils → ~25).leanproxy-mcp— passerelle MCP optionnelle (mode power user) qui agrège les serveurs, charge les schémas à la demande et économise ~98 % de tokens. Installée avec--use-leanproxy.garmin-mcp-auth— outil d'authentification OAuth (tokens stockés dans~/.garminconnect/)
Composants installés¶
garmin-mcp est épinglé à un commit précis (GARMIN_MCP_REF dans install.sh). Une installation existante qui n'est pas à ce commit
(par exemple installée sans pin, ou à un commit plus récent installé à la main) est réalignée sur le commit revu par le projet par
./install.sh : uv tool install re-résout alors les dépendances transitives, ce qui apporte leurs correctifs de sécurité. Vos tokens
ne sont pas touchés. Une origine personnalisée (chemin local, autre fork) n'est jamais écrasée ; /coach-doctor (garmin_mcp_pin)
signale l'écart. Relancer ./install.sh quand le commit est déjà le bon ne re-résout rien : pour rafraîchir les dépendances
transitives tout en gardant le commit épinglé, lancez uv tool upgrade garmin-mcp (le commit épinglé est conservé).
| Composant | Rôle | Installation |
|---|---|---|
uv |
Gestionnaire Python | curl -LsSf https://astral.sh/uv/install.sh \| sh |
garmin-mcp |
Serveur MCP Garmin | uv tool install --python 3.12 git+https://github.com/Taxuspt/garmin_mcp@cfc5d799ab0f165e837f1188a1d093c65838aaf7 |
garmin-mcp-auth |
Authentification OAuth | via uv run garmin-mcp-auth |
leanproxy-mcp |
Passerelle MCP (optionnel) | brew tap mmornati/leanproxy-mcp && brew install leanproxy-mcp |
Mode direct (défaut)¶
Le script d'installation enregistre le serveur MCP garmin dans votre IDE avec la liste blanche d'outils :
{
"mcpServers": {
"garmin": {
"command": "garmin-mcp",
"args": ["stdio"],
"env": {
"GARMIN_ENABLED_TOOLS": "get_activities,get_activities_by_date,get_activity,get_activity_fit_data,get_activity_splits,get_activity_typed_splits,get_activity_split_summaries,get_sleep_data,get_hrv_data,get_rhr_day,get_training_readiness,get_calendar_events,get_courses,get_workouts,get_workout_by_id,get_scheduled_workouts,schedule_workouts,schedule_week,upload_workout,upload_course,create_strength_workout,delete_workout,unschedule_workout,unschedule_workouts,download_activity_file,get_stats,get_lactate_threshold,get_training_status,get_gear,get_activity_gear,add_gear_to_activity,get_daily_weigh_ins,get_weigh_ins"
}
}
}
}
Pourquoi une liste blanche ?
garmin-mcp expose ~151 outils. Les agents de ce projet n'en utilisent qu'une vingtaine. La liste blanche (GARMIN_ENABLED_TOOLS) réduit fortement la taxe de contexte de chaque requête. Vous pouvez l'ajuster dans install.sh (variable GARMIN_TOOL_WHITELIST).
Mode passerelle (optionnel — power user)¶
Installez avec --use-leanproxy :
./install.sh --use-leanproxy
Le script configure deux fichiers dans ~/.config/leanproxy/ :
config.yaml¶
server:
host: "127.0.0.1"
port: 8080
timeout: 300s
max_batch_size: 100
optimization:
lazy_loading:
enabled: true
stub_tokens: 54
cache_ttl: 24h
namespaces:
sport:
description: "Sport tools"
servers:
- garmin
allowed_clients:
- "*"
logging:
level: "info"
file: ""
leanproxy_servers.yaml¶
version: "1.0"
servers:
- name: garmin
enabled: true
transport: stdio
stdio:
command: garmin-mcp
args:
- stdio
env:
- GARMIN_ENABLED_TOOLS: "get_activities,get_activities_by_date,get_activity,get_activity_fit_data,get_activity_splits,get_activity_typed_splits,get_activity_split_summaries,get_sleep_data,get_hrv_data,get_rhr_day,get_training_readiness,get_calendar_events,get_courses,get_workouts,get_workout_by_id,get_scheduled_workouts,schedule_workouts,schedule_week,upload_workout,upload_course,create_strength_workout,delete_workout,unschedule_workout,unschedule_workouts,download_activity_file,get_stats,get_lactate_threshold,get_training_status,get_gear,get_activity_gear,add_gear_to_activity,get_daily_weigh_ins,get_weigh_ins"
cwd: .
timeout: 300s
connect_timeout: 10s
idle_timeout: ""
Config existante
Le script ne remplace pas une configuration existante. Si config.yaml ou leanproxy_servers.yaml existent déjà, ils sont conservés.
Liste blanche déjà installée avant un ajout d'outil
Conséquence directe de la note ci-dessus : une installation leanproxy déjà
en place ne reçoit pas automatiquement un outil ajouté plus tard à
GARMIN_TOOL_WHITELIST (ex. get_stats/get_lactate_threshold/
get_training_status, story #65) — ~/.config/leanproxy_servers.yaml
n'est réécrit que s'il est absent. Éditez sa ligne GARMIN_ENABLED_TOOLS
à la main pour y ajouter le nouvel outil, plutôt que de réinstaller :
grep -n GARMIN_ENABLED_TOOLS ~/.config/leanproxy_servers.yaml
# ajoutez le(s) nouveau(x) outil(s) à la fin de la liste, séparés par une virgule
Appelez ensuite les nouveaux outils via
leanproxy_invoke_tool(server="garmin", tool="get_stats", arguments={...})
(voir skills/garmin-sync-efficiency/SKILL.md), pas directement.
Suivi du cycle menstruel (opt-in, #166)¶
Les outils get_menstrual_data_for_date et get_menstrual_calendar_data ne figurent pas dans
la liste blanche ci-dessus. install.sh les y ajoute uniquement avec
[health].cycle_tracking = "garmin" (ou ./install.sh --cycle-tracking garmin, qui écrit la
clé) ; repasser à off et relancer l'installation les retire. En mode passerelle,
leanproxy_servers.yaml n'étant réécrit que s'il est absent, ajoutez-les à la main à sa ligne
GARMIN_ENABLED_TOOLS. Détail : Cycle menstruel.
Apports vers Garmin Connect (opt-in, #167)¶
Les outils get_custom_foods, get_custom_food_serving_units, get_nutrition_daily_food_log,
get_nutrition_daily_meals, get_hydration_data (lecture) et create_custom_food,
log_custom_food, log_food, add_hydration_data (écriture, « oui » explicite, jamais en
headless) ne figurent pas dans la liste blanche ci-dessus. install.sh les y ajoute uniquement
avec [nutrition].garmin_sync = "ask" (ou ./install.sh --nutrition-sync ask, qui écrit la clé) ;
repasser à off et relancer l'installation les retire. Mode direct uniquement : refusé avec
--use-leanproxy (écritures non filtrables en headless) — ne les ajoutez pas à la main à
leanproxy_servers.yaml. Détail : Apports vers Garmin.
Synchronisation du matériel Garmin¶
Garmin Connect gère son propre matériel (attribution automatique par sport, seuils de retraite).
Trois outils sont dans la liste blanche : get_gear et get_activity_gear (lecture) et
add_gear_to_activity (écriture côté Garmin — le coach ne l'appelle qu'après votre
confirmation explicite dans la conversation, jamais en synchronisation automatique).
- Association, une seule fois. Au premier
get_gearqui montre un matériel Garmin sans puce correspondante, le coach vous propose, pour chacun, de l'associer à une puce existante de### Chaussures(ajout du segmentgarmin: <uuid>) ou d'en créer une (alerte← seuil Garmin,depuis← date de début,(retirée)← statut retiré). Jamais d'association devinée ; sans réponse, le matériel n'est simplement pas attribué. Le total Garmin d'une paire qui précède votre suivi peut alimenter sondépart(départ = total Garmin − kilomètres déjà comptés par vos séances, jamais négatif : aucun double comptage). Pour l'historique déjà dans le workspace, voir Rattraper le matériel de l'historique. - Retraite décidée dans Garmin. Quand vous retirez une paire dans Garmin Connect, le coach la
traite comme retirée dès qu'il relit
get_gear(en conversation, ou une fois par jour par la synchronisation automatique) : plus d'alerte de seuil ni de rappel d'inspection, même si sa puce ne dit pas encore(retirée). Le tableau de bord l'affiche « retirée (Garmin) ». Le coach vous propose ensuite, une fois et seulement en conversation, d'écrire(retirée AAAA-MM-JJ)sur la puce (date de fin Garmin) ; la synchronisation automatique ne modifie jamais le profil. L'inverse (retirée au profil, active dans Garmin) est signalé, jamais annulé : le profil prime. Une paire(par défaut)retirée à une date connue garde les séances jusqu'à cette date. Commande :python3 scripts/arc_index.py garmin-gear-status [--garmin-gear-json <fichier>|-] [--mark-retired <id>]; instantané dérivé.arc/garmin_gear.json. - Priorité d'attribution. Votre déclaration en chat > matériel attaché par la montre
à la séance (un seul
get_activity_gearpar séance nouvelle) >(par défaut). Si Garmin dit A et que vous dites B, vous gagnez et le coach le signale une fois. Un matériel Garmin sans puce n'est jamais attribué en silence ni crédité à la paire par défaut (gear_source: garmin_unmapped) ; une puce- <nom Garmin> — garmin: <uuid> (ignorée)fait taire propositions et alertes. La provenance est tracée dansgear_source(garmin/chat/garmin_unmapped) ; règle exécutée parpython3 scripts/arc_index.py gear-attribution. - Synchronisation automatique.
scripts/daily-sync.shpasse--disallowedToolspouradd_gear_to_activityetremove_gear_from_activity, ainsi que pour les outils d'écriture de séances et de parcours (schedule_workouts,upload_workout,delete_workout…) : le run non surveillé ne peut pas écrire chez Garmin. Limite : en mode passerelle l'appel passe par l'outil uniquemcp__leanproxy__invoke_tool, qui ne peut pas être filtré par sous-outil — seule la consigne du skill protège alors ; préférez le mode direct pour un run non surveillé. - Retour vers Garmin (facultatif). Une attribution faite en chat peut être poussée vers Garmin si vous le confirmez ; sans confirmation, rien n'est écrit.
- Installations existantes. Relancez
./install.sh: la liste blanche de.mcp.jsonest mise à jour. En mode passerelle, éditez à la mainGARMIN_ENABLED_TOOLSde~/.config/leanproxy_servers.yaml(voir l'avertissement plus haut) pour y ajouterget_gear,get_activity_gear,add_gear_to_activity./coach-doctor(gear_sync) signale une liste blanche trop ancienne et les paires du profil sansgarmin:— sans jamais contacter Garmin. - Source intervals.icu. Voir Configuration Intervals.icu.
Poids lu dans Garmin Connect (#222)¶
Sans terminal — L'application macOS : un questionnaire à la place des lignes de commande, le chat intégré ou votre assistant habituel, des données qui restent chez vous, une synchronisation qui n'écrit jamais chez Garmin, et la pesée du matin lue en lecture seule.
Si vous vous pesez avec une balance Garmin (Index S2…) ou saisissez votre poids dans Garmin
Connect, vous n'avez plus à le redonner au coach. Deux outils de lecture sont dans la liste
blanche : get_daily_weigh_ins (pesées d'un jour) et get_weigh_ins (pesées d'une plage de dates).
- Quand. Pendant le bilan matinal et la synchronisation automatique, la pesée du jour est lue et
écrite dans
weight_kgdu fichier santé du jour (medical/AAAA-MM-JJ_health.md), avecweight_origin: "garmin". Le fichier santé du jour sans poids est relu à chaque passage : une pesée faite après la première synchronisation du matin est prise au passage suivant. - Le jour de la pesée seulement. Un jour sans pesée Garmin n'a pas de poids : la valeur de la veille n'est jamais recopiée. Le modèle de dépense énergétique reprend déjà la dernière pesée connue à la date de chaque séance. Plusieurs pesées le même jour : la plus ancienne (celle du matin) est retenue.
- Votre déclaration prime. Un poids que vous donnez en chat le même jour (
weight_origin: "chat") n'est jamais remplacé par Garmin. Si les deux diffèrent de plus de 1 kg, le coach le signale une seule fois (la pesée Garmin écartée est gardée dansweight_garmin_kg). Si votre profil demande un rappel de pesée hebdomadaire, il est sauté quand Garmin a déjà le poids du jour. - Rattrapage (facultatif, à la demande). Un seul appel
get_weigh_inssur une plage de dates remplit les fichiers santé existants qui n'ont pas de poids — aucun fichier n'est créé pour cela. - Lecture seule.
add_weigh_in,add_weigh_in_with_timestamps,delete_weigh_insetadd_body_compositionne sont jamais exposés, etscripts/daily-sync.shles retire en plus. La composition corporelle (get_body_composition) n'est pas lue. Les pesées avant/après séance (weight_pre_kg,weight_post_kg) restent déclaratives. - Règles exécutées par un script.
python3 scripts/arc_weight_sync.py plandécide quoi écrire (pesée retenue, priorité, signalement) ; l'agent écrit ce qu'il rend, sans recalculer. - Installations existantes. Relancez
./install.shpour mettre à jour la liste blanche de.mcp.json. En mode passerelle, ajoutezget_daily_weigh_ins,get_weigh_insà la main àGARMIN_ENABLED_TOOLSde~/.config/leanproxy_servers.yaml. - Sources intervals.icu, Strava et COROS. Rien n'est lu : le poids reste celui que vous déclarez.
Rattraper le matériel de l'historique¶
Le matériel attaché par la montre n'est attribué qu'aux séances nouvelles (get_activity_gear à la
synchronisation). Un historique déjà dans activities/ reste sans gear_id : la vue « Matériel » du tableau de bord est vide
alors que Garmin Connect connaît la paire de chaque séance. Le script scripts/garmin_gear_backfill.py (#145)
les rattrape avec un appel Garmin par paire de chaussures (get_gear_activities), jamais un par séance.
# 1. Simulation (par défaut) : rien n'est écrit
python3 scripts/garmin_gear_backfill.py
# 2. Après relecture du rapport : écriture
python3 scripts/garmin_gear_backfill.py --apply
Extrait d'un rapport de simulation (noms et identifiants fictifs, format réel) :
RATTRAPAGE DU MATÉRIEL GARMIN — simulation (rien n'est écrit)
Workspace : 190 fichier(s) d'activité, 187 avec garmin_activity_id, période 2024-08-15 → 2026-09-29
PAIRES (4 retenue(s), 12 hors période masquée(s) — --all-shoes pour les proposer)
- Hoka Speedgoat 5 [puce à ajouter]
puce proposée : - Hoka Speedgoat 5 — depuis 2025-08-11 — alerte 800 km — id: hoka-speedgoat-5 — garmin: 3f9c2a7e…
séances rattachées : 49 (à écrire 49, déjà attribuées 0, conflits 0, ambiguës 0)
km : 919.8 dans le workspace · 948.2 au total chez Garmin (51 séance(s))
départ : aucun kilométrage antérieur au premier fichier du workspace ; non comptée(s) : 2 dans la période
du workspace (trous, à importer par la synchronisation)
- Nike Pegasus 40 [puce à ajouter] (retirée)
puce proposée : - Nike Pegasus 40 — depuis 2024-04-25 — alerte 644 km — départ 239 km — id: nike-pegasus-40 — garmin: 7a1e4c9b… (retirée)
séances rattachées : 10 (à écrire 10, déjà attribuées 0, conflits 0, ambiguës 0)
départ : 239 km = 20 séance(s) Garmin de la paire antérieures au premier fichier du workspace (2024-08-15)
…
PAIRES PAR DÉFAUT CHEZ GARMIN (non reprises : `(par défaut)` n'est jamais posé automatiquement) : Hoka Speedgoat 5
AMBIGUËS — revendiquées par deux paires chez Garmin, jamais attribuées (4)
SÉANCES GARMIN ABSENTES DU WORKSPACE (185, 2314 km)
- 58 (685 km) antérieures au premier fichier du workspace — comptées dans « départ » des puces nouvelles
- 127 (1629 km) dans la période du workspace (trous) — non comptées, jamais réimportées ici
FICHIERS SANS garmin_activity_id : 3 — non rattachables automatiquement (déclarer la paire dans le chat)
BILAN : 4 puce(s) à ajouter, 0 segment(s) garmin: à ajouter à une puce existante, 108 séance(s) à renseigner, 0 conflit(s), 4 ambiguë(s).
Simulation seulement. Pour écrire : relancer avec --apply.
Après --apply, la dernière ligne résume ce qui a été écrit (Appliqué : profil mis à jour, N séance(s)
écrite(s), 0 échec(s)…) et l'index est reconstruit : la vue Matériel
affiche aussitôt le kilométrage de chaque paire. Sur un serveur avec le tableau de bord en conteneur,
reconstruisez l'image après la mise à jour du moteur (scripts/update-docker.sh, voir
Docker).
Options : --since AAAA-MM-JJ (séances du workspace à partir de cette date), --gear <uuid> (une seule paire),
--all-shoes (propose aussi les paires sans séance dans la période du workspace — les anciennes paires
retirées, en (retirée)), --json, --workspace, --tokens-dir. Le script est idempotent : une seconde
exécution ne change rien.
Paires retirées depuis dans Garmin. Une puce déjà liée (garmin: <uuid>) dont la paire a été retirée
dans Garmin Connect est listée « → retirée dans Garmin » : --apply ajoute alors seulement
(retirée AAAA-MM-JJ) à la puce (date de fin Garmin) et rafraîchit l'instantané .arc/garmin_gear.json.
- Dépendance. Comme
download_fit.py, il utilisegarminconnectet les jetons locaux (~/.garminconnect, ouGARMINTOKENSde.mcp.json) : c'est la seule exception à « bibliothèque standard seule » ; il se relance seul avec le Python degarmin-mcp(GARMIN_PYTHONpour en imposer un autre). La connexion Garmin peut prendre une à deux minutes. - Rapport de simulation. Par paire : la puce
### Chaussuresproposée, le nombre de séances rattachées, les km du workspace comparés au total Garmin ; puis les conflits, les séances ambiguës, les séances Garmin absentes du workspace et le nombre de fichiers sansgarmin_activity_id(non rattachables : déclarez la paire dans le chat). - Priorité athlète. Une séance qui porte déjà un
gear_id(déclaré en chat, ou attribué par une synchronisation antérieure) n'est jamais écrasée : la divergence est seulement listée. Seul ungear_source: "garmin_unmapped"sansgear_idest remplacé (uniquement la valeur degear_source, le reste du blocarcest conservé octet pour octet). Une paire(ignorée)n'est jamais attribuée ; une séance revendiquée par deux paires chez Garmin est ambiguë et n'est attribuée à aucune. Toutes les paires sont lues même avec--gear(qui ne restreint que ce qui est proposé et écrit), pour que l'ambiguïté soit toujours détectée. Si une paire est en erreur ou tronquée, elle peut cacher une ambiguïté :--applyest refusé (code 1, rien n'est écrit) ; la simulation la liste (section INCOMPLET). - Fichiers particuliers. Plusieurs fichiers portant le même
garmin_activity_id(ex._running.mdet_running_2.md) sont signalés comme doublons et jamais écrits (à trier à la main). Un fichier avecgear_sourcemais sansgear_id(invalide) est laissé tel quel et signalé. Un fichier déjà hors contrat (avant le passage du script) n'est pas réécrit et est rapporté à part (« voir /arc-backfill ») sans compter comme un échec. Les écritures se font en octets : fins de ligne (CRLF) et permissions conservées, et un fichier refusé après écriture est restauré à l'identique. - Puces proposées.
- <nom> — depuis <date> — alerte N km — départ N km — id: <slug> — garmin: <uuid> (retirée):alertevient demaximumMeters(si > 0),(retirée)du statut Garmin, le nom dedisplayName, à défautcustomMakeModel, à défaut « Chaussure Garmin». Une puce existante avec le même garmin:est réutilisée (songear_idsert) et jamais modifiée. Une puce existante sansgarmin:dont le nom (ou l'id) correspond à la paire n'est pas dupliquée : le rapport propose d'y ajouter le segmentgarmin: <uuid>et--applyl'ajoute — c'est la seule modification jamais faite à une puce existante (nom ambigu : rien n'est attribué). L'idd'une puce nouvelle n'est jamais celui d'ungear_iddéjà présent dans vos séances (déclaré en chat, sans puce) : il reçoit un suffixe et le rapport signale la correspondance de nom pour que vous décidiez.(par défaut)n'est jamais posé : le rapport liste seulement les paires par défaut de Garmin. départsans double comptage. Seule une puce nouvelle en reçoit un : la somme des km Garmin des séances de la paire datées strictement avant le premier fichier du workspace (identifiées paractivityId). Les séances déjà dans le workspace sont comptées par leurs fichiers ; celles postérieures au dernier fichier seront importées par la synchronisation ; celles qui tombent dans la période sans fichier (trous) ne sont pas comptées non plus (choix prudent : un fichier sans identifiant peut les représenter). Ces trois catégories sont listées séparément au rapport. Le départ n'est pas proposé (raison donnée) avec--since, ni si la liste Garmin est tronquée ou en erreur. Sans trou, km du workspace + départ = total Garmin.--apply. Ajoute les puces manquantes sous### Chaussures(sous-section créée dans## Matériel & lieuxsi absente), écritgear_id+gear_source: "garmin"dans le blocarcdes séances (le reste du fichier est conservé tel quel), valide chaque fichier avec le contrat (un fichier refusé est restauré) puis réindexe.- Codes de sortie. 0 = succès ; 1 = succès partiel (paire injoignable, fichier refusé) ; 2 = usage,
garminconnectabsent ou authentification impossible ; 3 =--applysans profil athlète.
Le coach vous propose ce rattrapage une fois, en conversation seulement, toujours en simulation d'abord, et
n'écrit qu'après votre « oui » sur le rapport (la simulation dure 1 à 2 minutes de connexion plus un appel par paire :
lancez-la avec un long délai ou en arrière-plan). La synchronisation automatique (garmin-daily-sync, sans
surveillance) ne le lance jamais et n'en parle pas : c'est /coach-doctor (gear_history) qui le signale, sans
contacter Garmin, quand plus de la moitié des séances (au moins 5) portant un garmin_activity_id n'ont pas de
gear_id.
Authentification¶
Les tokens Garmin sont stockés dans ~/.garminconnect/ et sont valides environ 6 mois.
Droits du dossier de tokens¶
garmin_tokens.json contient le jeton de rafraîchissement : il ne doit être lisible que par vous (avis GHSA-wjhr-76vg-2hvc sur
garminconnect 0.3.2, version figée par garmin-mcp ; correctif amont en 0.3.5, non validé par garmin-mcp). Les versions récentes
de garmin-mcp-auth créent déjà le dossier en 700 et les fichiers en 600, mais des jetons créés par une version antérieure de
garmin-mcp, par un autre outil ou par une connexion garminconnect directe peuvent rester en 644 (le client réécrit un fichier
existant sans en changer le mode). install.sh resserre donc, comme filet de sécurité, ~/.garminconnect à 700, ses fichiers à
600, ainsi que ~/.garminconnect_base64 et un éventuel dossier personnalisé (GARMINTOKENS de l'entrée garmin de .mcp.json),
à chaque exécution (aussi lors d'un /update-coach, et après l'authentification) ; le daily-sync le refait après chaque run
(un fichier recréé par une reconnexion naît au umask), et /coach-doctor (garmin_token_perms) vérifie le résultat. À la main :
chmod 700 ~/.garminconnect && find ~/.garminconnect -type f -exec chmod 600 {} + && chmod 600 ~/.garminconnect_base64
Vérifier les tokens¶
uv run garmin-mcp-auth --verify
Renouveler l'authentification¶
uv run garmin-mcp-auth
Un dossier de jetons par workspace (plusieurs workspaces, même utilisateur)¶
Par défaut, tous les workspaces d'un utilisateur partagent ~/.garminconnect/ : deux athlètes
sur la même machine se partageraient donc le même compte Garmin. Pour donner à un workspace ses
propres jetons :
./install.sh --workspace ~/coach-alice --garmin-tokens ~/.garminconnect-alice
L'option écrit GARMINTOKENS dans l'env du serveur garmin du .mcp.json du workspace (et
de ses configurations Cursor, Gemini et Windsurf), crée le dossier en 700 et lance
garmin-mcp-auth --token-path sur ce dossier. Elle est mémorisée : un ./install.sh sans
l'option conserve GARMINTOKENS (jamais retiré), et une installation qui n'utilise pas l'option
ne change pas. Le dossier est aussi noté dans [credentials].garmin_tokens de
config/workspace.user.toml (propre au workspace) : il survit à un passage par une autre source
(--source intervals puis retour à garmin). La configuration OpenCode globale
(~/.config/opencode/opencode.json) est partagée par tous les workspaces : elle n'est pas modifiée
dans ce cas. OpenCode interactif ne lit pas le .mcp.json mais opencode.json, fusionné avec celui
de la racine du projet (documentation OpenCode) : l'installateur
écrit donc l'entrée garmin dans <workspace>/opencode.json (fusionnée sans toucher à vos autres
clés, ajoutée au .gitignore du workspace). Valable seulement avec --source garmin, et
incompatible avec le mode passerelle (--use-leanproxy, y compris mémorisé) : la passerelle
lance garmin-mcp sans cet environnement et lit ~/.garminconnect ; l'installation s'arrête avec un
message plutôt que d'écrire une configuration sans effet.
Le même dossier est ensuite utilisé partout, dans l'ordre : --tokens-dir d'un script, puis
GARMINTOKENS du .mcp.json du workspace, puis GARMINTOKENS de l'environnement, puis
GARMIN_TOKENS_DIR, puis ~/.garminconnect — /coach-doctor, la surveillance garmin_watch.py,
download_fit.py et garmin_gear_backfill.py partagent cette résolution
(scripts/arc_credentials.py). python3 scripts/coach_doctor.py indique la source retenue
(tokens_dir_source en JSON). Pour renouveler : uv run garmin-mcp-auth --token-path <dossier>.
Données accessibles¶
Les agents accèdent aux outils Garmin directement (mode direct) ou via leanproxy_invoke_tool(server="garmin", tool="...") (mode passerelle) :
- Activités : liste, détails, fichiers FIT
- Santé : HRV, sommeil, stress, fréquence cardiaque au repos
- Poids : pesées du jour ou d'une plage de dates (lecture seule, #222)
- Calendrier : séances planifiées, push d'entraînements
- Planification : création de séances (course, fractionné, renforcement)
Dépannage¶
| Problème | Solution |
|---|---|
garmin-mcp introuvable |
uv tool install --python 3.12 git+https://github.com/Taxuspt/garmin_mcp@cfc5d799ab0f165e837f1188a1d093c65838aaf7 |
| Tokens expirés | uv run garmin-mcp-auth |
leanproxy-mcp introuvable (mode passerelle) |
brew tap mmornati/leanproxy-mcp && brew install leanproxy-mcp |
| Erreur de connexion | Vérifiez que garmin-mcp fonctionne : garmin-mcp stdio |
Voir aussi la page Dépannage.
Pas de montre Garmin ?
./install.sh --source intervals remplace tout ce qui précède par
Intervals.icu (Suunto, Polar, Apple...) — voir
Configuration Intervals.icu. Montre COROS :
Montres COROS.
