chore: project scaffolding and design docs
This commit is contained in:
1005
docs/superpowers/plans/2026-05-17-mcp-garmin.md
Normal file
1005
docs/superpowers/plans/2026-05-17-mcp-garmin.md
Normal file
File diff suppressed because it is too large
Load Diff
126
docs/superpowers/specs/2026-05-17-mcp-garmin-design.md
Normal file
126
docs/superpowers/specs/2026-05-17-mcp-garmin-design.md
Normal file
@@ -0,0 +1,126 @@
|
||||
# MCP Garmin Server — Design Spec
|
||||
|
||||
**Date:** 2026-05-17
|
||||
**Status:** Approved
|
||||
|
||||
---
|
||||
|
||||
## Overview
|
||||
|
||||
A local MCP server that exposes Garmin Connect data to Claude Desktop via the `garminconnect` Python package. The server runs as a single-file FastMCP stdio server, authenticated via environment variables, targeting personal use with Claude Desktop as the sole client.
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
**Approach:** Single-file FastMCP (Option A)
|
||||
|
||||
```
|
||||
mcp-garmin/
|
||||
├── server.py # FastMCP server — all tools and startup logic
|
||||
├── pyproject.toml # Dependencies: mcp[cli], garminconnect
|
||||
└── .env # GARMIN_EMAIL, GARMIN_PASSWORD (not committed)
|
||||
```
|
||||
|
||||
`server.py` initializes a `FastMCP("garmin")` instance, registers all tools, and serves via stdio. A module-level `Garmin` client instance is shared across all tool calls — no re-authentication per call.
|
||||
|
||||
**Claude Desktop config** (`~/Library/Application Support/Claude/claude_desktop_config.json`):
|
||||
```json
|
||||
{
|
||||
"mcpServers": {
|
||||
"garmin": {
|
||||
"command": "python",
|
||||
"args": ["/path/to/mcp-garmin/server.py"],
|
||||
"env": {
|
||||
"GARMIN_EMAIL": "your@email.com",
|
||||
"GARMIN_PASSWORD": "yourpassword"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Tools
|
||||
|
||||
All tools return JSON-serializable dicts. Dates are accepted as `YYYY-MM-DD` strings and default to today when omitted.
|
||||
|
||||
### Authentication
|
||||
| Tool | Parameters | Description |
|
||||
|------|-----------|-------------|
|
||||
| `authenticate()` | — | Initiates login from env vars. Returns `"Authenticated"` on success, or the MFA prompt (URL or code instruction) if Garmin requires MFA. |
|
||||
| `complete_mfa(code)` | `code: str` | Accepts the MFA code and completes login, caching the session in `~/.garth`. |
|
||||
|
||||
### Activities
|
||||
| Tool | Parameters | Description |
|
||||
|------|-----------|-------------|
|
||||
| `get_activities(start_date, end_date, limit)` | `start_date: str`, `end_date: str`, `limit: int = 20` | List of activities with type, distance, duration, average HR. |
|
||||
| `get_activity_details(activity_id)` | `activity_id: str` | Full detail for a single activity: splits, laps, all metrics. |
|
||||
|
||||
### Health Stats
|
||||
| Tool | Parameters | Description |
|
||||
|------|-----------|-------------|
|
||||
| `get_sleep(date)` | `date: str = today` | Sleep score, stages (deep/light/REM/awake), total duration. |
|
||||
| `get_heart_rate(date)` | `date: str = today` | Resting HR and daily HR timeline. |
|
||||
| `get_stress(date)` | `date: str = today` | Stress level timeline throughout the day. |
|
||||
| `get_body_battery(date)` | `date: str = today` | Body battery charge/drain values throughout the day. |
|
||||
| `get_hrv(date)` | `date: str = today` | HRV status and nightly average. |
|
||||
| `get_spo2(date)` | `date: str = today` | Blood oxygen readings. |
|
||||
|
||||
### Steps & Daily Metrics
|
||||
| Tool | Parameters | Description |
|
||||
|------|-----------|-------------|
|
||||
| `get_steps(date)` | `date: str = today` | Step count, daily goal, and distance. |
|
||||
| `get_daily_stats(date)` | `date: str = today` | Full daily summary: calories, floors, intensity minutes, active time. |
|
||||
|
||||
### Gear & Devices
|
||||
| Tool | Parameters | Description |
|
||||
|------|-----------|-------------|
|
||||
| `get_devices()` | — | List of paired Garmin devices with model and firmware version. |
|
||||
| `get_gear()` | — | Gear items (shoes, bikes) with mileage/usage stats. |
|
||||
|
||||
### Profile
|
||||
| Tool | Parameters | Description |
|
||||
|------|-----------|-------------|
|
||||
| `get_user_profile()` | — | Display name, age, weight, HR zones. |
|
||||
|
||||
---
|
||||
|
||||
## Authentication & Session Management
|
||||
|
||||
- `garminconnect` uses `garth` under the hood, which caches OAuth tokens in `~/.garth` after first login.
|
||||
- **Startup:** The server attempts a silent login using cached `~/.garth` tokens. If valid, all tools are ready immediately. If no cache exists, tools return `"Not authenticated. Ask Claude to call authenticate() first."` until auth is completed.
|
||||
- **First-time setup:** The user calls `authenticate()` from Claude Desktop chat. If Garmin requires MFA, the prompt (URL or email code instruction) is returned as a string visible in the chat. The user then calls `complete_mfa(code)` with the received code. On success, garth caches the session — subsequent server restarts skip MFA entirely.
|
||||
- **MFA URL handling:** If garth surfaces a URL as part of the MFA flow, it is returned verbatim in the `authenticate()` response so Claude Desktop renders it as a clickable link.
|
||||
|
||||
---
|
||||
|
||||
## Error Handling
|
||||
|
||||
| Scenario | Behavior |
|
||||
|----------|----------|
|
||||
| Missing `GARMIN_EMAIL` or `GARMIN_PASSWORD` env vars | Fail at startup with a clear message; do not start server |
|
||||
| No cached session and no auth attempted | Tools return `"Not authenticated. Call authenticate() first."` |
|
||||
| `GarminConnectAuthenticationError` | Return readable error string to the LLM |
|
||||
| No data for requested date | Return `"No <data type> found for <date>"` |
|
||||
| Network error | Catch and return readable error string |
|
||||
|
||||
No custom retry logic — garth handles token refresh automatically.
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
- `mcp[cli]` — FastMCP framework
|
||||
- `garminconnect` — Garmin Connect API wrapper (uses `garth` for auth)
|
||||
- Python 3.14 (existing venv)
|
||||
|
||||
---
|
||||
|
||||
## Out of Scope
|
||||
|
||||
- Write operations (creating workouts, updating data)
|
||||
- Multi-user support
|
||||
- Hosting / remote deployment
|
||||
- GPS track/polyline data (raw GPX export)
|
||||
Reference in New Issue
Block a user