Skip to content

Garmin MCP — the localhost-only bridge to Garmin Connect

Container garmin-mcp-server, built from the checkout ~/garmin-mcp (upstream Taxuspt/garmin_mcp) with the untracked compose.server.yaml (bind-mounts tokens ~/.local/share/garmin-mcp/tokens and ~/garmin-data). Serves http://127.0.0.1:8000/mcp with /healthz. Localhost only — nothing off-box can reach it, which is why the training scheduler runs as local cron and not as a claude.ai cloud routine.

Why this shape

Garmin credentials and tokens stay on the box. Consumers are all local: Claude Code's garmin MCP server, training-sync, and claude-hub.

Shape

  • Health: curl -fsS http://127.0.0.1:8000/healthz (training-sync waits up to 5 min for it, ~/.local/bin/training-sync:39-45).
  • Consumers: Claude Code MCP garmin (150+ tools) · training-sync (three cron passes) · claude-hub/app.py (GARMIN_URL; live :8090 runs the sandbox-tested code since 2026-10-17, deploy = copy from ~/claude-hub-sandbox, rollback dir ~/claude-hub.pre-golive-20261017-2157; also takes Apple Health uploads at /apple → POST /api/apple-export).
  • garmin-tunnel.service (user unit) is an OpenAI/ChatGPT tunnel via ~/.local/bin/tunnel-client; it is not reusable for Claude cloud routines.
  • Adaptive-plan workout_uuids change overnight for the same workout — match by name + sport + duration, never by uuid alone.

Updating

cd ~/garmin-mcp && git pull --ff-only origin main && docker compose -f compose.server.yaml build && docker compose -f compose.server.yaml up -d, then curl -fsS http://127.0.0.1:8000/healthz and one real tool call. Last done 2026-10-17 (87 commits, to 202913f; garminconnect 0.3.2). Rollback image: garmin-mcp-garmin-mcp:pre-update. The MCP get_race_predictions takes no dates; the hub reads Garmin's daily history through docker exec -i garmin-mcp-server python - (see claude-hub import_prediction_history).

Connected to

If you change this

  • Hits: training-sync (hard dependency; aborts garmin-down) · claude-hub summaries · the Claude Code garmin MCP config.
  • Does not hit: anything in the torrentvpn stack; the array.

Surfaces

Surface Role
docker ps → garmin-mcp-server (healthy) liveness
hub.lan/api/summary claude-hub's view of it

See

  • Source: ~/garmin-mcp/docker-compose.yml · ~/garmin-mcp/README.md

Live race/training release (2026-10-22)

claude-hub.service on :8090 now runs committed race/training code from ~/claude-hub-sandbox, branch sandbox/race-lab-20261022, runtime commit 3d1606f. Owner authorized promotion via “Continue with recommendations.” Source doc checkpoint 7f24444. Includes prediction comparisons, actual race setup and local run GPX, explicit result confirmation/scoring, four race strategies and Training direction. Existing 15-minute sync handles evidence/forecasts; Coach cache is four hours/new local day. Page reads use local cache, refreshing every five minutes/foreground. No new timer or Garmin mutations.

claude-hub-sandbox.service stays on :8091 with automatic sync/refresh disabled. Live SQLite was retained; only new feature data was merged. Original activity/health/Apple/history tables passed before/after fingerprints and integrity checks. Release pointer: ~/claude-hub/.race-lab-release.json. Scoped deploy/code-only rollback: ~/claude-hub-sandbox/deploy_race_lab.py; latest backup ~/claude-hub-releases/20261023T034805Z-3d1606f4, prior full-feature backup …/20261023T034219Z-417d0209. Never restore an old DB over newer health data for a code rollback. Optional Open-Meteo calls send location/date only. Current implementation, tests, remaining data inputs and rollback chain: projects/claude-hub and repo RACE-LAB.md.