Skip to main content
Glama

garmin-coach

A local stdio MCP server that gives Claude Code read access to your Garmin Connect account, plus a gated, allow-listed path for creating and scheduling workouts. Intended as the data layer for an AI training/fat-loss coach.

Architecture

Claude Code
    ↓  MCP (stdio, local subprocess — no network)
garmin_mcp.server          25 read-only tools (+6 when writes are enabled)
    ↓
garmin_mcp.client          token-only auth, error normalisation
    ↓  python-garminconnect 0.3.11
Garmin Connect (HTTPS)
    ↓  device sync
Garmin Forerunner 970

Everything runs on your Mac. The only network traffic is normal HTTPS to Garmin. Nothing is sent to a third party.

Related MCP server: Garmin Health MCP Server

Install

cd ~/Developer/garmin-coach
uv sync

Python is pinned to 3.12 via .python-version. garminconnect requires ≥3.12.

Initial Garmin login — run this yourself

Credentials are only ever entered interactively, in your own terminal:

cd ~/Developer/garmin-coach
uv run python scripts/garmin_login.py

It prompts for your email, then your password via getpass (hidden, never in shell history), and handles an MFA code if Garmin asks. On success it mints OAuth tokens and does a small harmless read to prove the session works.

If Garmin starts rate limiting, the script stops and tells you to wait — it does not retry in a loop, which is what gets accounts throttled harder.

Token storage and security

  • Tokens live in ~/.garmin-coach/tokensoutside the project, so they can never be swept into git.

  • The directory is forced to 0700, every file inside to 0600.

  • Your password is used exactly once, to mint tokens. It is never stored, never written to .env, never in MCP config, never in the repo.

  • Token contents are never logged. Logging goes to stderr only (stdout is the MCP protocol channel).

  • Override the location with GARMIN_TOKENSTORE=/some/path.

Treat ~/.garmin-coach/tokens as equivalent to your password. Anyone with those files has full read/write access to your Garmin account.

Test the MCP

uv run python scripts/smoke_test.py

Stage 1 runs without any Garmin auth — it exercises the stdio transport, tool discovery, the bundled exercise catalog, the workout builder, and the error paths. Stage 2 runs the live read tools, and is skipped automatically until you have logged in.

Connect to Claude Code

Already registered user-scoped (available in every project):

claude mcp add --scope user garmin -- \
  /opt/homebrew/bin/uv run --directory ~/Developer/garmin-coach \
  python -m garmin_mcp.server

claude mcp get garmin     # check status

uv run --directory resolves the project's own virtualenv, so you never need to activate anything manually.

Tools

Healthgarmin_today, garmin_sleep, garmin_hrv, garmin_stress, garmin_body_battery, garmin_heart_rate, garmin_recovery

Traininggarmin_training_readiness, garmin_training_status, garmin_hr_zones, garmin_performance_metrics, garmin_recent_activities, garmin_activities_by_date, garmin_activity, garmin_strength_sets, garmin_exercise_history

Workout library (read-only)garmin_workouts, garmin_workout, garmin_scheduled_workouts, garmin_search_exercises, garmin_exercise_categories, garmin_resolve_exercise, garmin_workout_step_formats, garmin_devices, garmin_preview_strength_workout

All dates are ISO YYYY-MM-DD and default to today. Responses are normalised and compact; a value Garmin did not return is omitted rather than guessed, so "field absent" and "value is zero" stay distinguishable.

Write tools (disabled by default)

Not registered at all unless GARMIN_MCP_ENABLE_WRITES=1 is in the server environment, and independently re-checked at call time:

garmin_create_strength_workout, garmin_create_cardio_workout, garmin_update_workout, garmin_schedule_workout, garmin_unschedule_workout, garmin_push_workout_to_device

This is an allow-list, not a passthrough. Deleting activities, gear, or profile data is not exposed. garmin_unschedule_workout additionally requires confirm=true.

To enable:

claude mcp remove garmin -s user
claude mcp add --scope user garmin -e GARMIN_MCP_ENABLE_WRITES=1 -- \
  /opt/homebrew/bin/uv run --directory ~/Developer/garmin-coach \
  python -m garmin_mcp.server

Use garmin_preview_strength_workout first — it builds and renders the exact payload without uploading. Verify the structure before anything reaches your calendar or watch.

Known Garmin limitations

The unofficial API does not expose everything the watch shows. The full matrix — what's on the watch vs in Garmin Connect vs reachable via python-garminconnect — is in docs/forerunner-970.md.

The ones that shape the coaching design:

  • No RIR/RPE field exists. Garmin has nowhere to put it.

  • Garmin stores one concrete rep target per set, not a range. A "5–8 @ 1 RIR" prescription cannot round-trip — push the concrete target (e.g. 6) and keep the programming rule in the coaching layer. Garmin is the execution interface, not the source of truth for the program.

  • Per-set heart rate is not available; HR is session-level only.

  • Auto-detected reps are often wrong for machines/cables until corrected in Garmin Connect.

  • Use garmin_hr_zones, never computed zones. Zone 2 is a heart-rate range from your Garmin profile, not a hard-coded pace.

Re-authenticate or revoke

rm -rf ~/.garmin-coach/tokens              # revoke locally
uv run python scripts/garmin_login.py      # re-authenticate

Tokens auto-refresh, so this is only needed if the refresh token expires or you revoke it. To revoke server-side, change your Garmin password — that invalidates the tokens.

Remove from Claude Code

claude mcp remove garmin -s user

That only unregisters the server. To fully remove: also delete ~/.garmin-coach and ~/Developer/garmin-coach.

Troubleshooting

Symptom

Cause / fix

No Garmin tokens found in …

Run scripts/garmin_login.py

Saved Garmin tokens were rejected

Refresh token expired/revoked — log in again

Garmin is rate limiting this account

Wait 15–30 min. Do not retry in a loop

Could not reach Garmin Connect

Network down, or Garmin maintenance

Tool returns available: false

Garmin genuinely has no data for that date

MCP not detected

claude mcp get garmin; check uv path is absolute

Set GARMIN_MCP_LOG_LEVEL=DEBUG for verbose stderr logging.

Garmin-MCP

F
license - not found
B
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    A
    quality
    D
    maintenance
    Enables Claude Desktop to access and analyze Garmin wearable health data including sleep, HRV, Body Battery, and activity metrics. Users can query their health trends, track recovery, and generate interactive HTML dashboards using natural language.
    9
    6
    MIT
  • F
    license
    Not graded
    quality
    C
    maintenance
    Connects Garmin watch data to Claude Desktop, allowing users to ask natural language questions about their health and activity data from Garmin Connect.
  • A
    license
    A
    quality
    C
    maintenance
    Enables users to analyze their own Garmin Connect data—activities, sleep, HRV, Body Battery, training readiness—directly inside Claude Desktop.
    13
    2
    MIT

View all related MCP servers

Related MCP Connectors

  • Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.

  • Garmin data in Claude: 135 tools — activities, sleep, HRV, training, workouts. Free, open source.

  • WHOOP recovery, strain, sleep and workouts in Claude via official WHOOP OAuth. Free, open source.

View all MCP Connectors

Latest Blog Posts

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/Nahom101-1/Garmin-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server