Skip to main content

MCP server for Garmin Connect data and activity analysis

Project description

garmin-mcp

pipeline status coverage report

Read-only MCP server for Garmin Connect: exposes live data tools plus analyze_* tools that cache activity data locally and compute aggregated statistics. Built on the unofficial garminconnect library — see "Unofficial API — risks & rate limits" below. See Privacy for what's read, cached and stored locally.

Tools

Live data

Tool Description
list_activities Recent activities (newest first, pageable), enriched summary metrics
list_activities_by_date Activities in a date range, optional type filter
get_activity_details Deep per-activity data: summary, HR time-in-zones, exercise sets, splits, weather, gear
get_training_readiness Training Readiness score + factors (sleep, recovery, load balance/ACWR, stress, HRV)
get_training_status VO2max, training-status phrase, acute/chronic load + ACWR, load focus, heat acclimation
get_daily_stats Daily summary: steps, calories, resting HR, stress, body battery
get_sleep Sleep summary: total/deep/light/REM/awake, SpO2, respiration
get_hrv HRV summary: last-night average, status, baseline

Analysis (cache + aggregates)

Tool Description
analyze_backfill Backfill the last N days into the local cache; rebuild aggregates. Returns counts
analyze_day Sync one day with deep details; rebuild aggregates; return that day's summary
analyze_brief Refresh today + return the morning brief (yesterday, today's recovery/readiness, 7/14/30-day trends); appends to the dated brief history

list_activities* returns enriched fields per activity: training effect (aerobic/ anaerobic), training load, intensity minutes, HR time-in-zones, moving/elapsed time, speed, elevation, respiration, body-battery delta, lap count and location.

The analyze_* tools cache raw daily data under ~/.garmin-activity/days/ and write aggregated stats (daily/weekly summaries, morning brief + dated history) to GARMIN_OUTPUT_DIR (defaults to ~/.garmin-mcp/output).

Requirements

  • Python >= 3.12 (managed by uv/uvx)
  • A Garmin Connect account
  • Any OS — no platform-specific credential storage

Unofficial API — risks & rate limits

Garmin has no official API for individuals. This server talks to Garmin Connect through the reverse-engineered garminconnect library, which drives the same endpoints the website and mobile app use. That has consequences worth understanding before you rely on it:

  • It can break without warning. Garmin can change or retire these endpoints at any time; when they do, tools may start returning errors until garminconnect (and then this server) is updated. Pin versions if you need stability, and expect occasional breakage.
  • Terms of Service. Automated access to Garmin Connect is not covered by an official individual-developer agreement. Use this only against your own account, for personal use, and review Garmin's Terms of Service — you are responsible for how you use it. Abusive or high-volume use risks account rate-limiting or suspension.
  • Built-in pacing. Bulk history sync (analyze_backfill) sleeps ~0.3s between days to stay gentle on Garmin's servers. Individual live-data tools issue only a few requests per call.
  • Keep request volume modest. Prefer incremental syncs (analyze_day / analyze_brief) over repeatedly backfilling large ranges. Backfill once for history, then refresh a day at a time. Avoid tight loops or scheduling many concurrent syncs — no official rate limit is published, so err on the side of fewer, spaced-out requests.

Setup

1. One-time interactive login

uvx --from rogo-garmin-mcp rogo-garmin-mcp-login

Prompts for your Garmin email, password and the emailed MFA code. Your credentials are used only to obtain OAuth tokens and are never stored; only the resumable tokens are written to ~/.garmin-mcp/tokens (0700). The headless server resumes from those tokens and refreshes them silently, so it never needs your email or password again. Re-run this login if the tokens eventually expire.

2. Add to Claude Code (~/.claude/settings.json)

Installed from PyPI (recommended):

"mcpServers": {
  "garmin": {
    "type": "stdio",
    "command": "uvx",
    "args": ["rogo-garmin-mcp"]
  }
}

Or from a source checkout: uv sync, then use "command": "uv", "args": ["run", "--project", "/path/to/garmin-mcp", "rogo-garmin-mcp"].

Client compatibility

This is a standard stdio MCP server launched with uvx rogo-garmin-mcp, so any MCP client that supports the stdio transport should work. Only the Claude Code setup is documented and exercised here; the others use the same command and are expected to work but are not separately verified.

Client Status Notes
Claude Code Documented / used Config shown in Setup (~/.claude/settings.json), or claude mcp add.
Claude Desktop Expected to work Add the same mcpServers block to claude_desktop_config.json.
Cursor Expected to work Register as an MCP server (stdio): command uvx, args ["rogo-garmin-mcp"].
Antigravity Expected to work Register as an MCP server (stdio): command uvx, args ["rogo-garmin-mcp"].
Generic MCP clients Expected to work Any client speaking the MCP stdio transport; point it at uvx rogo-garmin-mcp.

Usage

Once configured, you talk to your agent in plain language and it picks the right tool. Some prompts that map cleanly onto the tools above:

  • "What were my last few workouts?"list_activities
  • "Show the details of that strength session — reps and heart-rate zones."get_activity_details
  • "How ready am I to train today?"get_training_readiness
  • "What's my VO2max and training status?"get_training_status
  • "How did I sleep last night?"get_sleep
  • "Backfill the last 90 days, then give me my morning brief."analyze_backfill then analyze_brief

Tools return plain JSON. The samples below are trimmed for illustration — real payloads carry more fields (see the tables above). The health-summary tools (get_daily_stats, get_sleep, get_hrv) additionally omit any null fields.

list_activities(limit=2):

[
  {
    "id": 12345678901,
    "name": "Morning Run",
    "type": "running",
    "start": "2026-07-06 19:12:44",
    "duration_min": 41.8,
    "distance_km": 7.35,
    "calories": 512,
    "avg_hr": 152,
    "max_hr": 176,
    "aerobic_te": 3.4,
    "anaerobic_te": 0.6,
    "te_label": "TEMPO",
    "training_load": 118,
    "location": "Riverside"
  },
  {
    "id": 12344556677,
    "name": "Strength Training",
    "type": "strength_training",
    "start": "2026-07-05 08:03:10",
    "duration_min": 24.5,
    "calories": 268,
    "avg_hr": 138,
    "vigorous_intensity_min": 12,
    "training_load": 74
  }
]

get_training_readiness():

{
  "date": "2026-07-07",
  "score": 78,
  "level": "READY",
  "feedback": "READY_TO_TRAIN",
  "recovery_time_min": 180,
  "acute_load": 302,
  "hrv_weekly_avg": 31,
  "factors": {
    "sleep": { "pct": 90, "rating": "GOOD" },
    "recovery_time": { "pct": 100, "rating": "GOOD" },
    "load_balance": { "pct": 65, "rating": "MODERATE" },
    "hrv": { "pct": 80, "rating": "GOOD" }
  }
}

get_daily_stats():

{
  "calendarDate": "2026-07-07",
  "totalSteps": 9432,
  "totalDistanceMeters": 7120,
  "totalKilocalories": 2568,
  "restingHeartRate": 52,
  "averageStressLevel": 34,
  "bodyBatteryMostRecentValue": 61
}

Privacy

Your data stays on your machine. This server only ever reads from Garmin Connect; the analyze_* tools cache what they fetch locally so trends can be computed offline. Nothing is uploaded anywhere, and there is no telemetry.

What is stored, and where:

Path Contents
~/.garmin-mcp/tokens (dir, 0700) Resumable Garmin OAuth tokens. Your email/password are never stored — only these tokens.
~/.garmin-activity/days/YYYY-MM-DD.json Raw per-day cache: activities, sleep, HRV, recovery, stress, readiness.
$GARMIN_OUTPUT_DIR (default ~/.garmin-mcp/output) Aggregated stats: daily/weekly summaries, morning brief and dated brief history.

Set GARMIN_OUTPUT_DIR to relocate the aggregate output (e.g. to a directory your agent reads from).

Retention: files are kept until you delete them. The cache only grows as you backfill or analyze more days; it is never pruned automatically.

How to wipe everything:

rm -rf ~/.garmin-activity ~/.garmin-mcp
# and, if you set a custom output dir:
rm -rf "$GARMIN_OUTPUT_DIR"

Deleting ~/.garmin-mcp/tokens also signs the server out; re-run the interactive login to use it again.

Development

uv run pytest                         # run tests with coverage
uv run pytest --cov-report=html       # HTML coverage report

License

Apache-2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

rogo_garmin_mcp-0.7.0.tar.gz (113.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

rogo_garmin_mcp-0.7.0-py3-none-any.whl (26.6 kB view details)

Uploaded Python 3

File details

Details for the file rogo_garmin_mcp-0.7.0.tar.gz.

File metadata

  • Download URL: rogo_garmin_mcp-0.7.0.tar.gz
  • Upload date:
  • Size: 113.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.2.0 CPython/3.12.12

File hashes

Hashes for rogo_garmin_mcp-0.7.0.tar.gz
Algorithm Hash digest
SHA256 8481f61d089a90432913914a9b7f5dfe65b5452811cff82c4939af3425bbddf3
MD5 a361df10129ea598c05fe1ed2fece3ba
BLAKE2b-256 018a77f717045b9312e609e57c491f432f56f7369299522c59eb2bc9079d1ea7

See more details on using hashes here.

File details

Details for the file rogo_garmin_mcp-0.7.0-py3-none-any.whl.

File metadata

File hashes

Hashes for rogo_garmin_mcp-0.7.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1e7b2701e41a02c729e56db0c416be4b3d033b19d71d037af35bb286b6ca285a
MD5 b294a588d363128c1a167821111d1d4c
BLAKE2b-256 214a17188893023711cfb334a0f1fa6030982f39f2d73ab5ef1f74bfd46918b1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page