Garmin Running MCP
Provides read-only access to a personal Garmin Connect running account, with cached tools for latest runs, run lists/details/charts, comparisons, trends, recovery metrics, training context, and sync status; supports explicit rate-limited refresh of the latest run without modifying Garmin.
Click on "Deploy 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 Running MCPwhat was my latest 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.
Garmin Running MCP
Self-hosted Garmin Connect → ChatGPT/AI-agent integration for a personal running account. No Strava, subscription sync service, or public activity files. Built with a Cloudflare Worker, D1, private R2 and Alchemy. Garmin Connect's consumer API is unofficial and may change. This is an independent project, not affiliated with Garmin.
What it does
Cloudflare Access Managed OAuth limits the
/mcpendpoint to one exact email address. The Worker verifies the signed Access assertion as well. No anonymous data tools or Garmin write actions.Every six hours, the Worker incrementally caches running activities, laps, HR zones and available recovery metrics in D1; original activity downloads go to a private R2 bucket. Historical pagination is bounded (four activities per pass). Activity changes outside the most recent window are not automatically rescanned.
refresh_latest_runis an explicit, rate-limited Garmin read: it checks up to five recent activity summaries, updates the latest cached run and returns it. It is not a full history sync. Full details, charts and originals arrive on the scheduled sync; a newly refreshed run reportsdetails_pending. The tool has a ten-minute cooldown and shares a single-flight lease with cron. Garmin may take time to process a new activity.All other MCP tools are cache-only:
latest_run,list_runs,run_details,run_chart,compare_runs,running_trends,recovery,training_context,sync_status. No agent can modify the Garmin account.Garmin login is interactive on your machine. Password and MFA are not stored. Renewable OAuth tokens are AES-256-GCM encrypted in D1, with the key stored separately as a Worker secret. A revoked session requires repeating the interactive login.
Privacy: The D1 cache includes original Garmin JSON, and private R2 files can contain precise GPS tracks. Protect Cloudflare account access and the encryption key. The MCP tools do not expose the private R2 files or raw chart responses;
run_chartexposes only a bounded allowlist of non-coordinate metrics. Activity names and timestamps may still be identifying.
Related MCP server: hybridlog
Requirements
Node 22+, pnpm 10.17.0, a Cloudflare account with Workers, D1, R2 and Zero Trust Access. R2 may require a billing method. A ChatGPT plan/UI that supports private custom MCP apps and OAuth (or another compatible MCP client).
An Alchemy
defaultCloudflare OAuth profile with access to your account (pnpm exec alchemy profile show). For one-time Garmin-session upload, Wrangler must separately have D1 access (pnpm exec wrangler login). Use the same Cloudflare account in both.Your exact Cloudflare Access login email. If you don't have a Zero Trust organization, choose an available
*.cloudflareaccess.comteam domain; otherwise Alchemy discovers the existing domain without changing the organization.
Deploy
pnpm install
cp .env.example .env.prod
chmod 600 .env.prod
# Edit .env.prod with your CLOUDFLARE_ACCOUNT_ID, ACCESS_EMAIL and
# GARMIN_TOKEN_KEY (generate it with: openssl rand -base64 32).
# Set NEW_ACCESS_TEAM_DOMAIN only if there is no existing Zero Trust organization.
pnpm check && pnpm test
pnpm run plan
pnpm run deployReview the plan before deployment: the Access application must have Managed OAuth enabled, one exact-email allow rule, and your Worker as its destination. Do not connect an unauthenticated Worker to ChatGPT. Deployment prints the /mcp URL. Alchemy creates the Access app/policy, Worker, D1 schema, private R2 bucket and schedule. Keep the encryption key backed up securely; losing it prevents decrypting the Garmin session.
On a machine with an interactive terminal and Wrangler authenticated to the same account:
pnpm garmin:connectEnter your Garmin email, hidden password and MFA code if requested. The bootstrap forces an OAuth1→OAuth2 refresh through the Worker-side client and reads one activity before uploading only encrypted tokens and IV to remote D1. Do not paste credentials, tokens or FIT/GPX data into a GitHub issue or commit them. .env.prod, Alchemy state, Wrangler state and .private/ are gitignored.
Optional unattended Cloudflare API token
Local deployments can use Alchemy's OAuth profile; no Cloudflare API token is needed. For unattended CI, provision an account-scoped token (or use an Alchemy admin profile to mint one) with only the permissions needed for Zero Trust Access organization/IdP and app/policy management, Workers Scripts (including Alchemy state-store bootstrap), D1, R2 and Secrets Store. Minting API tokens requires an additional API Tokens — Write bootstrap credential; do not grant it to routine deployments. Follow the Cloudflare permissions reference and Alchemy CI guide.
Connect and verify
In ChatGPT, enable developer mode and create a private custom MCP app using the deployed
https://…workers.dev/mcpURL with OAuth authentication. Approve the Access email PIN for your allowlisted email. If the client uses a different OAuth callback, add only its exact callback URL todynamicClientRegistration.allowedUrisinalchemy.run.tsand redeploy; do not remove authentication.Ask for
sync_status(status: okafter cron),latest_runandrun_details. Compare distance, time, laps and HR against Garmin Connect. Testlist_runs,running_trendsandrecoverywhere available. After a new run appears on Garmin, explicitly callrefresh_latest_run;updated,no_new_run,cooldownandbusydescribe what happened. Try again after its retry interval if Garmin is still processing the activity.An unauthenticated request to
/mcpmust receive 401. No tool should offer Garmin modification.run_chartis opt-in and paginates up to 100 samples from the first 500 cached chart points; it never returns GPS coordinates or the original ZIP/FIT.
The first scheduled sync runs at minute 17 every six hours (UTC). sync_status.backfill_offset advances only after a successful page; complete means the current archive was paginated. If you later import older runs into Garmin, verify their activity type is Running (GPX uploads can default to Other), verify they appear in Garmin's activity list, then intentionally reset backfill_offset to 0 in D1 so the next scheduled sync rescans history. Do not reset blindly or repeatedly; use a temporary bounded schedule only when supervised, then restore the six-hour cron. Garmin's API and manual imports can lag.
Tool semantics and limits
Dates on runs are Garmin-local dates. Recovery queries currently use UTC calendar dates and device-dependent metrics may be missing (
null, not zero).Pace = moving seconds × 1000 / distance in meters; elapsed time is preserved separately. Cadence uses Garmin's steps-per-minute summary or a moving-time-weighted lap average.
compare_runsreturns newest-minus-older numeric deltas (negative pace is faster). Different distances/intensities may limit comparisons.At most 100 runs per range, 10 comparison IDs, 365 trend days, 100 samples per
run_chartcall.run_detailsexcludes the chart;details_pendingmeans a manual refresh has cached the summary but cron has not enriched it yet.refresh_latest_runis not marked MCP read-only: it reads Garmin and mutates the local cache, never the Garmin account. It won't perform history pagination, recovery calls or original activity downloads. If cron is already running, it returnsbusyinstead of racing token updates.sync_statusseparately tracks cron status and manual refresh status; after a manual failure,refresh_latest_error_stagecontains only a fixed checkpoint and HTTP status (never an exception body), and is cleared on success.training_contextgives a starting goal of sub-30-minute 5K (6:00/km) and eventual 10K. Suggestions are for the runner to review, not medical advice or automatic workout writes.
Failure modes
needs_initial_login / needs_reauthentication: run the interactive bootstrap again and investigate revoked or expired Garmin tokens. rate_limited: wait rather than retrying rapidly. upstream_error: Garmin might be unavailable or its undocumented API may have changed. Do not log third-party exception bodies: they can contain credentials or OAuth tokens. The adapter is isolated in src/garmin.ts and the bootstrap in scripts/connect-garmin.ts for repair or replacement. Back up D1 and R2; keep the key separately.
Local checks: pnpm check && pnpm test; Worker bundle: pnpm exec wrangler deploy src/worker.ts --dry-run --outdir /tmp/garmin-build --compatibility-date 2026-09-20 --compatibility-flags nodejs_compat. Tests and dry-runs cannot prove production Access OAuth or Garmin token renewal; validate against your own account.
This server cannot be deployed
Maintenance
Related MCP Connectors
Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.
Remote streamable-HTTP MCP server running on a single Cloudflare Worker. Your assistant gets live Airbnb, Amazon, Booking.com, Google Flights, Maps and Reddit data, social search on X, Instagram and TikTok, the Meta Ad Library, and image/video generation without any keys. Connect your own accounts to let it send WhatsApp or Telegram messages, work an IMAP inbox, manage Meta Ads campaigns and publish to X and LinkedIn. OAuth 2.1 with PKCE; stored credentials are AES-256-GCM encrypted.
Garmin data in Claude: 135 tools — activities, sleep, HRV, training, workouts. Free, open source.
Ask your AI about your fitness: activities and data from Garmin, COROS, Strava, GPX and more
Related MCP Servers
- FlicenseNot gradedqualityBmaintenanceA stateless MCP server for Cloudflare Workers that exposes read-only Garmin Connect data (activities, health, sleep, training status, HRV, VO2 max) for a single securely linked personal account.-
- AlicenseNot gradedqualityAmaintenanceMCP server that mirrors your Garmin data into a personal database and exposes tools for health summaries, training load, muscle readiness, and race analysis, with optional chat-driven insights via stdio or HTTP.1MIT
- FlicenseNot gradedqualityBmaintenanceRemote MCP server for Garmin Connect on Cloudflare Workers (free tier), providing 139 tools and 5 resources covering activities, health, training, workouts, nutrition, challenges, devices, gear, weight, women's health, courses, FIT-file analysis, and user profile, with OAuth 2.1 login flow.-
- AlicenseNot gradedqualityBmaintenanceEnables reading and analyzing Garmin Connect data—activities, health metrics, FIT files, and challenges—through natural language, for AI assistants like Claude and ChatGPT.MIT