garmin-mcp
Provides access to Garmin account data through the Garmin MCP server, including OAuth authentication, token management, and APIs for interacting with Garmin-linked accounts.
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., "@garmin-mcpWhat was my average heart rate on yesterday's run?"
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.
Gamin-mcp-webui
Le serveur MCP garmin-mcp et une interface web de consultation des comptes, dans un seul dépôt et une seule image Docker.
Le serveur amont, écrit en Go, authentifie plusieurs comptes via OAuth 2.1 en mode remote et
garde leur état dans une base SQLite. Il n'expose aucune page ni API d'administration : impossible
de savoir, depuis le serveur lui-même, qui a créé un compte ni quand ce compte s'est connecté pour
la dernière fois. Ce dépôt ajoute cette vue et fait tourner les deux ensemble.
Le serveur amont est vendorisé dans garmin-mcp/ par git subtree : c'est une copie versionnée
du dépôt public, mettable à jour d'une commande (voir « Suivre l'amont »), et non un simple
téléchargement au moment du build.

conteneur unique
┌───────────────────────────────────────────────┐
│ garmin-mcp serve ──écrit──► /data/garmin.db│ :8180 endpoint MCP + login OAuth
│ (Go, OAuth 2.1) (SQLite, WAL) │
│ ▲ │
│ interface web ──────lit (RO)───────┘ │ :8080 interface + API JSON
│ (FastAPI) │
└───────────────────────────────────────────────┘
/data : base + clé maîtresse + TLS (volume)Les deux processus tournent sous le même compte de service, condition nécessaire pour qu'une base SQLite en mode WAL soit lisible par le second. Le conteneur s'arrête dès que l'un des deux s'arrête, pour que la politique de redémarrage de Docker s'applique à l'ensemble.
Ce que l'interface affiche
Colonne | Origine |
Compte |
|
Garmin lié | présence de |
Compte créé le |
|
Dernière connexion | dérivée (voir ci-dessous). |
Signal retenu | le fait horodaté qui porte la date affichée. |
Clients / familles |
|
Le détail d'un compte ajoute la liste complète des signaux, les clients OAuth autorisés avec leurs portées, les familles de jetons et, si la table est alimentée, les événements d'audit.
Related MCP server: mcp-server-garmin
Comment la « dernière connexion » est calculée
Le schéma de garmin-mcp n'a pas de colonne « dernière connexion ». Il stocke des faits horodatés ; l'interface prend le plus récent d'entre eux et indique lequel a gagné.
Signal | Source | Ce qu'il prouve |
Rafraîchissement des jetons Garmin |
| usage réel : les jetons Garmin sont réécrits à chaque rafraîchissement. |
Émission d'un jeton MCP |
| le client MCP a obtenu un jeton d'accès ou l'a fait tourner. |
Autorisation dans le navigateur |
| passage complet par la page de login. |
Consentement accordé |
| consentement donné à un client MCP. |
Événement d'audit |
| table présente dans le schéma, sans écrivain dans les versions 0.0.x. |
Mise à jour du compte |
| repli, retenu seulement s'il est postérieur à |
Un compte dont aucun signal ne dépasse sa date de création est classé jamais connecté —
updated_at vaut alors created_at et ne prouve aucune connexion.
États dérivés (seuils configurables) : actif ≤ 7 j, inactif ≤ 30 j, dormant au-delà, jamais connecté sans aucun signal.
Limites à connaître
Rétention. La tâche de nettoyage de garmin-mcp supprime les codes et les jetons expirés. Un compte inactif depuis longtemps peut donc voir sa dernière connexion « reculer » sur un signal plus ancien mais persistant (consentement, jetons Garmin). Les consentements, eux, ne sont jamais supprimés par le nettoyage.
Rien n'est instrumenté côté requête. garmin-mcp n'écrit pas d'horodatage de dernier appel d'outil ; la granularité est donc celle de l'émission des jetons, pas celle de chaque requête MCP. Pour une vraie mesure d'usage, il faudrait un correctif amont alimentant
audit_events— cette interface l'affichera automatiquement si la table se remplit.Identité Garmin. Le nom Garmin du compte est chiffré dans la base (
garmin_identity_sealed) et n'est déchiffrable qu'avec la clé maître du serveur. L'interface ne la demande pas et n'affiche donc que l'e-mail.
Sécurité
Ce qui suit concerne l'interface web. Le modèle de menace du serveur MCP lui-même — isolation des
comptes, chiffrement des jetons, gestion des clés — est celui du projet amont, décrit dans
garmin-mcp/docs/threat-model.md.
Lecture seule, sans exception. Chaque connexion SQLite est ouverte en
mode=roavecPRAGMA query_only, et un test vérifie qu'unDELETEéchoue. L'interface ne peut pas corrompre la base que le serveur MCP écrit à côté d'elle.Conteneur non privilégié. L'entrypoint n'est root que le temps d'ajuster l'appartenance de
/data, puis redescend sur un compte de service viasetpriv. La racine du système de fichiers peut rester en lecture seule (read_only: truedans le compose),/dataest en0700, et les deux ports servis sont publiés sur la boucle locale.Deux ports, deux publics.
8180est l'endpoint MCP et les pages de login OAuth, destinés aux utilisateurs ;8080est l'interface d'exploitation, qui affiche leurs adresses e-mail. Ne les exposez pas au même public.Aucun secret ne sort. Les colonnes
*_hash(empreintes) et*_sealed(enveloppes chiffrées) ne sont jamais sélectionnées ni renvoyées ; un test parcourt les réponses de l'API pour s'en assurer.Authentification obligatoire. Le service refuse de démarrer sans
WEBUI_PASSWORDniWEBUI_API_TOKEN, saufWEBUI_ALLOW_ANONYMOUS=1assumé explicitement. Les comparaisons de secrets passent parsecrets.compare_digest.Données personnelles. L'interface affiche des adresses e-mail : exposez-la sur une adresse privée, derrière un reverse proxy en TLS, et activez
WEBUI_MASK_EMAILS=1si un affichage partiel suffit. La page envoienoindex, nofollow.
Démarrage rapide
cp .env.example .env # renseignez au minimum WEBUI_PASSWORD et l'URL publique
docker compose up -d --buildL'image compile le serveur Go depuis garmin-mcp/ puis l'embarque avec l'interface web.
L'interface écoute sur 127.0.0.1:8080, l'endpoint MCP sur 127.0.0.1:8180. Au premier
démarrage, le serveur crée sa clé maîtresse, migre sa base et commence à servir ; l'interface
affiche « base introuvable » les quelques secondes qui précèdent.
Essai sur un poste, sans reverse proxy
Le serveur d'autorisation refuse de nommer un émetteur en clair : l'URL publique doit être
https, et aucun override ne change cela (allow-insecure-http ne lève que le contrôle sur
l'écoute et l'origine). Pour un essai local, laissez le conteneur terminer le TLS avec un
certificat auto-signé :
GARMIN_MCP_SELF_SIGNED_TLS=1 \
GARMIN_MCP_PUBLIC_URL=https://127.0.0.1:8180/mcp \
GARMIN_MCP_BIND_ADDRESS=127.0.0.1:8180 \
GARMIN_MCP_OAUTH_CLIENTS='[{"id":"claude-desktop","name":"Claude Desktop","redirect-uris":["http://127.0.0.1:33418/callback"],"scopes":["garmin:read"],"resources":["https://127.0.0.1:8180/mcp"],"public":true}]' \
WEBUI_PASSWORD=demo \
docker compose up --buildLe certificat est écrit une fois dans /data/tls et n'est jamais remplacé. Il est fait pour un
essai, pas pour une mise en production : un client MCP refusera une autorité inconnue.
En production
Mettez un reverse proxy TLS devant, et donnez au serveur l'URL publique de ce proxy :
Réglage | Valeur |
|
|
|
|
| le réseau du proxy, sans quoi aucun en-tête |
| au moins un client ; il n'y a pas d'enregistrement dynamique. |
Alternative sans proxy : montez vos propres GARMIN_MCP_TLS_CERT_FILE et
GARMIN_MCP_TLS_KEY_FILE, le serveur termine alors le TLS lui-même.
Sauvegarde. La base et la clé maîtresse sont les deux moitiés d'une même sauvegarde : une base
sans sa clé est illisible. Sauvegardez /data en entier, avec le processus arrêté ou via la
sauvegarde en ligne de SQLite. Voir garmin-mcp/docs/operations.md.
Ne lancer qu'un service
RUN_SERVICES vaut les-deux (défaut), mcp ou webui. Deux conteneurs issus de la même image,
l'un en mcp et l'autre en webui sur le même volume, sont une configuration valide — le second
bascule alors sur une copie temporaire de la base si le volume lui est monté en lecture seule.
En local, sans conteneur
python -m venv .venv && source .venv/bin/activate
pip install -r requirements-dev.txt
# Pour essayer l'interface sans base de production :
python scripts/demo_database.py /tmp/demo.db
WEBUI_DATABASE_PATH=/tmp/demo.db WEBUI_PASSWORD=demo python -m app
# http://127.0.0.1:8080 — identifiants : admin / demoLe serveur MCP seul se compile comme n'importe quel programme Go :
cd garmin-mcp && go build ./cmd/garmin-mcp && ./garmin-mcp tools list | grep ' tools:'Configuration
Serveur MCP
Chaque réglage de garmin-mcp a une variable d'environnement : la clé en majuscules, tirets
remplacés par des soulignés, préfixée GARMIN_MCP_. La liste complète est dans
garmin-mcp/docs/configuration.md. Les principales pour cette image :
Variable | Défaut dans l'image | Rôle |
| — | Obligatoire. URL publique de l'endpoint MCP. Doit être |
| — | Obligatoire. Registre des clients OAuth, en JSON. |
|
| écoute dans le conteneur. |
|
| autorise une écoute et une origine en clair hors boucle locale. Ne rend jamais un émetteur en clair acceptable. |
| vide | réseaux dont les en-têtes |
| — | le serveur termine le TLS lui-même. |
|
| ajout de cette image : fabrique un certificat auto-signé dans |
|
| base SQLite, partagée avec l'interface. |
|
| la valeur sélectionne le répertoire ; le nom de fichier appartient au serveur. |
|
| état hors base. |
|
| outils d'écriture (nécessite aussi la portée OAuth correspondante). |
Conteneur
Variable | Défaut | Rôle |
|
|
|
|
| compte de service auquel l'entrypoint redescend après avoir ajusté |
Interface web
Toutes les variables sont facultatives sauf le secret d'accès.
Variable | Défaut | Rôle |
|
| base SQLite de garmin-mcp (sa clé |
|
| identifiant HTTP Basic. |
| — | mot de passe HTTP Basic. Obligatoire (voir |
| — | jeton porteur pour l'API JSON ( |
|
| ouvre l'interface sans authentification. À réserver à un proxy qui authentifie déjà. |
|
| masque les e-mails ( |
|
| seuil « actif », en jours. |
|
| seuil « inactif », en jours. Doit dépasser |
|
| durée de validité de la copie quand la lecture directe échoue. |
|
| titre affiché. |
|
| écoute HTTP. |
|
| niveau de log uvicorn. |
API
Toutes les routes /api sauf /api/health exigent une authentification.
Route | Description |
| l'interface. |
| sonde publique : |
| chemin, taille et mode d'accès de la base, seuils, libellés des signaux. |
| compteurs agrégés (total, liés à Garmin, actifs, vus sous 24 h…). |
| liste paginée. Paramètres : |
| même liste au format CSV, mêmes filtres. |
| détail d'un compte : signaux, consentements, familles de jetons, audit. |
| documentation OpenAPI générée. |
curl -u admin:motdepasse 'http://127.0.0.1:8080/api/accounts?status=dormant'
curl -H "Authorization: Bearer $WEBUI_API_TOKEN" http://127.0.0.1:8080/api/statsDéveloppement
pip install -r requirements-dev.txt
ruff check . && ruff format --check .
pytest -q # interface web
cd garmin-mcp && go test ./... # serveur MCP (suite amont)
shellcheck docker/entrypoint.sh
docker build -t gamin-mcp-webui:test .La CI fait les quatre : lint et tests Python sur 3.11 et 3.12, compilation du serveur Go,
shellcheck sur l'entrypoint, puis construction de l'image et démarrage réel du conteneur jusqu'à
ce que sa sonde de santé passe.
Les tests construisent une base SQLite au schéma de garmin-mcp (tests/schema.sql) peuplée de
cas limites : compte actif, inactif, dormant, jamais connecté, compte dont les jetons ont été
purgés. tests/schema.sql reproduit les tables et colonnes lues par app/queries.py ; si le
schéma amont évolue, c'est le fichier à mettre à jour — un test échouera alors immédiatement.
Suivre l'amont
garmin-mcp/ est un git subtree du dépôt public. Pour récupérer une version plus récente :
git remote add garmin-mcp-upstream https://github.com/tamcore/garmin-mcp.git # une seule fois
git fetch garmin-mcp-upstream master
git subtree pull --prefix=garmin-mcp garmin-mcp-upstream master --squashLe sous-répertoire reste modifiable comme le reste du dépôt ; git subtree push renvoie ces
modifications vers un fork amont si vous en tenez un. Après une mise à jour, vérifiez que
tests/schema.sql correspond toujours aux migrations amont — c'est ce que testent les tests de
l'interface.
Compatibilité
Vérifié contre le schéma de garmin-mcp après les migrations 0001_initial et
0002_oauth_contract (serveur 0.0.x). L'interface ne dépend que des tables principals,
garmin_token_sets, consents, oauth_clients, auth_codes, token_families, mcp_tokens
et audit_events, et ne lit aucune colonne chiffrée.
Licence
MIT pour ce dépôt. garmin-mcp/ est une copie du projet amont de Philipp Born, sous licence MIT
également : sa licence et ses notices d'origine voyagent avec le code, dans garmin-mcp/LICENSE et
garmin-mcp/THIRD_PARTY_NOTICES.md. Ce dépôt n'est pas un produit officiel du projet amont.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
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 Connectors
Remote MCP server for training, nutrition, wellness, and performance data with OAuth 2.0.
Hosted MCP server with managed OAuth for 15+ toolkits: Google Workspace, Fitbit, Oura, Kalshi, etc.
Multi-tenant hosted MCP server for Oura Ring — 21 read-only tools, OAuth per user.
OAuth MCP for Google, Meta, X and LinkedIn Ads, Search Console, GA4 and GoHighLevel.
Related MCP Servers
- AlicenseNot gradedqualityBmaintenanceConnects MCP clients to Garmin Connect data, enabling queries about activities, sleep, heart rate, body battery, and training status.MIT
- AlicenseNot gradedqualityBmaintenanceMCP server for Garmin Connect that enables users to access and manage their personal health and fitness data, including daily summaries, heart rate, sleep, HRV, stress, body composition, activities, and training readiness, with secure per-user authentication.Apache 2.0
- FlicenseAqualityCmaintenanceProvides read-only access to your Garmin Connect health data, including sleep, HRV, body battery, stress, training readiness, and activities, through an MCP server.14-
- AlicenseNot gradedqualityBmaintenanceExposes Garmin Connect data through MCP, enabling retrieval of activities, health metrics, training status, and workouts, with OAuth authentication and confirmed write operations.MIT
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/frankkubler/Gamin-mcp-webui'
If you have feedback or need assistance with the MCP directory API, please join our Discord server