garmin-mcp-server
# Garmin Connect MCP Server
A [Model Context Protocol](https://modelcontextprotocol.io/) (MCP) server that connects AI assistants to your Garmin Connect health and fitness data. Ask Claude, ChatGPT, OpenCode, or any MCP-compatible client about your workouts, sleep, heart rate, and more -- using natural language.
Built on [`python-garminconnect`](https://github.com/cyberjunky/python-garminconnect) and the [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk).
## Features
**29 tools** across 6 categories, giving your AI assistant access to:
| Category | Tools | Examples |
|---|---|---|
| **Health** | 5 | Daily summary, heart rate, sleep stages, stress, body battery |
| **Activities** | 4 | Recent workouts, search by date/type, detailed splits |
| **Body** | 3 | Weight trends, body composition, hydration tracking |
| **Fitness** | 6 | Training readiness, VO2 Max, HRV, race predictions, endurance score |
| **Devices** | 6 | Device info, step trends, personal records, SpO2, respiration, goals |
| **Export** | 5 | Download FIT, GPX, TCX, KML, and CSV files |
## Quick Start
### Prerequisites
- **Python 3.10+**
- **[uv](https://docs.astral.sh/uv/)** package manager
- A **Garmin Connect** account with a paired device
### 1. Clone and install
```bash
git clone https://github.com/JohanBellander/garmin-mcp-server.git
cd garmin-mcp-server
uv sync
```
### 2. Authenticate with Garmin
Run the one-time setup to save your OAuth tokens:
```bash
uv run garmin-mcp-setup
```
You'll be prompted for your email, password, and MFA code (if enabled). Tokens are saved to `~/.garminconnect/` and last approximately one year -- you won't need to re-authenticate until they expire.
### 3. Connect to your AI assistant
#### Claude Desktop
Add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
```json
{
"mcpServers": {
"garmin": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/garmin-mcp-server",
"run",
"garmin-mcp-server"
]
}
}
}
```
#### OpenCode
Add to your `.opencode.json` MCP config:
```json
{
"mcp": {
"garmin": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/garmin-mcp-server",
"run",
"garmin-mcp-server"
]
}
}
}
```
#### Any MCP Client
The server uses **STDIO transport**. Point your client at:
```
uv --directory /path/to/garmin-mcp-server run garmin-mcp-server
```
## Example Conversations
Once connected, you can ask your AI assistant things like:
- *"How did I sleep last night?"*
- *"Show me my runs from the past two weeks"*
- *"What's my training readiness today?"*
- *"Compare my resting heart rate over the last 7 days"*
- *"Download the GPX file for my last bike ride"*
- *"What are my race predictions for a half marathon?"*
- *"How many steps have I averaged this month?"*
## Available Tools
### Health Data
| Tool | Description |
|---|---|
| `get_daily_summary` | Steps, distance, calories, floors climbed, active minutes for a date |
| `get_heart_rate` | Resting HR, min/max, heart rate zone breakdown |
| `get_sleep` | Sleep duration, stages (deep/light/REM/awake), sleep score |
| `get_stress` | All-day stress levels, average, duration by category |
| `get_body_battery` | Energy reserve levels throughout the day |
### Activities
| Tool | Description |
|---|---|
| `get_recent_activities` | Most recent workouts with key metrics |
| `get_activities_by_date` | Activities in a date range, filterable by type (running, cycling, etc.) |
| `get_activity_details` | Full detail for a specific activity: pace, HR zones, elevation, training effect |
| `get_activity_splits` | Per-split/lap breakdown: pace, distance, HR, elevation |
### Body Composition
| Tool | Description |
|---|---|
| `get_weight` | Weight measurements, BMI, body fat % |
| `get_body_composition` | Weight, body fat, muscle mass, bone mass, body water |
| `get_hydration` | Daily water intake and progress toward goal |
### Fitness Metrics
| Tool | Description |
|---|---|
| `get_training_readiness` | Readiness score, HRV status, sleep quality, recovery time |
| `get_vo2max` | Estimated VO2 Max for running and cycling |
| `get_training_status` | Training load and status classification |
| `get_race_predictions` | Predicted times for 5K, 10K, half marathon, and marathon |
| `get_hrv` | Heart Rate Variability: status, weekly average, baseline |
| `get_endurance_score` | Aerobic fitness score over time |
### Export & Download
| Tool | Description |
|---|---|
| `download_activity_fit` | Original FIT file (as ZIP) -- raw sensor data |
| `download_activity_gpx` | GPX track -- GPS coordinates for mapping |
| `download_activity_tcx` | TCX file -- GPS + HR + cadence |
| `download_activity_kml` | KML file -- for Google Earth |
| `download_activity_csv` | CSV file -- tabular data for spreadsheets |
### Additional Tools
| Tool | Description |
|---|---|
| `get_devices` | Connected devices: model, firmware, battery, last sync |
| `get_daily_steps` | Step counts per day over a date range |
| `get_personal_records` | Personal bests across all activities |
| `get_respiration` | Breathing rate: waking, sleeping, high, low |
| `get_spo2` | Blood oxygen saturation readings |
| `get_goals` | Active fitness goals and current progress |
## Configuration
| Environment Variable | Default | Description |
|---|---|---|
| `GARMIN_TOKEN_STORE` | `~/.garminconnect` | Directory where OAuth tokens are stored |
| `GARMIN_EXPORT_DIR` | `~/garmin-exports` | Directory for downloaded activity files |
## Development
### Testing with MCP Inspector
```bash
uv run mcp dev src/garmin_mcp/server.py
```
This opens a web UI where you can invoke tools individually and inspect responses.
### Project Structure
```
src/garmin_mcp/
├── server.py # FastMCP server entry point
├── auth.py # OAuth token management + garmin-mcp-setup CLI
└── tools/
├── health.py # Daily health metrics
├── activities.py # Workout listing and details
├── body.py # Weight, body composition, hydration
├── fitness.py # Training metrics, HRV, race predictions
├── devices.py # Devices, steps, records, SpO2, goals
└── export.py # Activity file downloads
```
## Important Notes
- **Unofficial API** -- This uses undocumented Garmin Connect endpoints via `python-garminconnect`. Endpoints may change without warning.
- **Rate Limits** -- Garmin enforces rate limits. Avoid rapid-fire requests; the AI assistant handles this gracefully with error messages.
- **Token Refresh** -- The underlying `garth` library handles token refresh automatically. Tokens typically last ~1 year.
- **STDIO Safety** -- The server never writes to stdout (which would corrupt the MCP transport). All logging goes to stderr.
- **No Interactive Auth** -- The MCP server only uses pre-saved tokens. Run `garmin-mcp-setup` separately to authenticate.
## License
MIT
TDQS
Scored across 29 tools
Most tools map to distinct Garmin data categories, but a few boundaries are fuzzy: get_weight and get_body_composition overlap on weight and body fat, and get_daily_summary overlaps with get_daily_steps and get_heart_rate on daily metrics. Still, an agent can usually select the right tool from the descriptions.
The naming follows a consistent verb_noun pattern: get_* for data retrieval and download_activity_* for file exports. Plural/singular variations are minor and do not affect predictability.
29 tools is excessive for a Garmin data server. Many could be consolidated, such as the five download_activity_format tools into a single exporter, and get_weight/get_body_composition into one body metrics tool. The broad scope helps justify the number, but the surface still feels over-split.
The server covers a comprehensive read-only Garmin domain: activities, daily summaries, body metrics, health metrics, training readiness, sleep, stress, devices, and file downloads. Minor gaps exist, such as lacking date-range endpoints for some metrics (e.g., sleep, stress) and no way to search activities beyond recent/date-based retrieval.