garmin-mcp
Enables users to access and analyze Garmin Connect data through natural language, supporting multi-user setups, SQLite-backed history, and optional remote access via Cloudflare Tunnel.
README
Garmin MCP Server
Self-hosted Model Context Protocol server for Garmin Connect: multi-user, SQLite-backed history, HTTP/SSE for Claude custom connectors, optional Cloudflare Tunnel, and an agentic “sports companion” layer (bootstrap context, workout prompt, goals, flags).
Architecture
flowchart TD
Claude[ClaudeConnector] --> Tunnel[CloudflareTunnel]
Tunnel --> App[garmin-mcp]
App --> MW[ApiKeyAndRateLimit]
MW --> MCP[FastMCP_SSE]
MCP --> Tools[Tools]
Tools --> DB[(SQLite_WAL)]
Sync[SyncService] --> Garmin[Garmin_API]
Garmin --> Sync
Sync --> DB
Prerequisites
- Docker and Docker Compose
- Garmin account (see Garmin MFA below)
- Cloudflare account if using Tunnel
Quick start
- Clone this repository.
- Copy
config.example.yamltoconfig.yamland fill in credentials, API keys, encryption secrets, and paths. - Set
TUNNEL_TOKENin the environment (e.g..envnext todocker-compose.yml) if using Cloudflare Tunnel. - Run
docker compose up -d(ormake up). - Open Claude → Settings → Connectors → Add custom connector: base URL
https://<your-tunnel-host>/mcp(or your public URL), headerX-API-Key: <user api_key>.
Configuration reference
| Field | Type | Default | Description |
|---|---|---|---|
port |
int | 8765 |
HTTP port |
log_level |
string | info |
Logging level |
sync_interval_minutes |
int | 30 |
Background sync interval |
max_date_range_days |
int | 90 |
Max date span for tools |
users[].name |
string | — | Username (must match /sync/{username}) |
users[].api_key |
string | — | Secret for X-API-Key |
users[].db_path |
path | — | SQLite file |
users[].backup_path |
path | — | Backup directory (default example uses /data/backups/{name}/ outside the repo) |
users[].timezone |
string | — | IANA timezone for display |
users[].rate_limit |
int | 30 |
Requests per minute per user |
users[].initial_sync_days |
int | 365 |
First full history pull |
users[].flag_rules |
object | — | Thresholds for proactive flags |
Multi-user setup
Each users[] entry is isolated: its own Garmin credentials, API key, encrypted token file, SQLite DB, and backups.
Garmin MFA / Two-Factor Authentication
Garmin must have MFA disabled for automated login. Configure your account at:
https://account.garmin.com/account/security/
Rotating an API Key
- Edit
config.yamland update theapi_keyvalue for the relevant user. - Run
make down && make upto restart the container. - Update the
X-API-Keyheader value in the Claude custom connector settings for that user. - Verify with
make logsthat the server restarted cleanly.
Sports companion: custom instructions
Add this to Claude’s custom instructions so every session bootstraps fresh data:
You are my personal sports coach with access to my Garmin data.
At the start of every conversation, call get_my_context to load
my current goals, recent training history, and latest data before
responding to anything.
MCP prompt: analyze_new_workout
Registered as a named prompt. Use when the user asks to analyze the latest workout or last run; it follows the structured steps documented in the server (context → activities → detail → reasoning → suggest → feeling).
Makefile
| Target | Purpose |
|---|---|
make up |
docker compose up -d |
make down |
docker compose down |
make logs |
Follow logs |
make test |
Pytest suite |
make lint |
Ruff check + format check |
make format |
Apply Ruff formatter |
make sync |
scripts/sync_all.py — POST /sync/{user} for each user (server must be running) |
make backup |
POST /backup/all (set GARMIN_API_KEY to any user’s key) |
make shell |
Shell in garmin-mcp container |
make validate |
Compose config + config schema load |
Running tests
python -m venv .venv && .venv/bin/pip install -r requirements.txt
pytest tests/ -v
Troubleshooting
- Token expiry / auth errors: Check Garmin credentials; delete encrypted token file and restart; see logs.
- Port conflicts: Change
portinconfig.yamland compose port mapping. - Tunnel not connecting: Verify
TUNNEL_TOKENand Cloudflare route tohttp://garmin-mcp:8765. make syncfails: The server must be reachable athttp://127.0.0.1:8765(or setGARMIN_MCP_URL). Start withmake upfirst.- Backups in repo: Prefer
backup_pathunder/data/...(Docker volume). If you store backups inside the repo, extend.gitignoreaccordingly.
License
See LICENSE.
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.