garmin-cn-mcp
# Garmin Connect China MCP
A local, read-only MCP server for a **China-region** Garmin Connect account. Every Garmin client is hard-locked to `garmin.cn`; API reads go to `https://connectapi.garmin.cn` and the corresponding China SSO/DI-auth hosts.
This uses Garmin Connect's unofficial consumer web API through `garminconnect`. It is suitable for private personal use, can break when Garmin changes its services, and is not a substitute for the approved Garmin Health API for commercial products.
## Requirements
- Python 3.12+
- [`uv`](https://docs.astral.sh/uv/)
- A Garmin Connect **China** account
## Install and authenticate
From this directory:
```bash
uv sync
uv run garmin-cn-auth
```
The auth command prompts for email, password, and MFA directly in your terminal. Passwords and MFA codes never become MCP arguments. Refreshable tokens are stored by default under `~/.config/garmin-cn-mcp/` with owner-only permissions.
Treat that token directory like a password. If it may have been copied, remove it and revoke account access from Garmin's account/security settings.
## Add to Codex / ChatGPT desktop
With Codex CLI:
```bash
codex mcp add garmin-cn -- \
uv --directory /absolute/path/to/garmincn-mcp run garmin-cn-mcp
```
Or add this to `~/.codex/config.toml`:
```toml
[mcp_servers.garmin-cn]
command = "uv"
args = [
"--directory",
"/absolute/path/to/garmincn-mcp",
"run",
"garmin-cn-mcp",
]
startup_timeout_sec = 20
tool_timeout_sec = 60
```
The ChatGPT desktop app, Codex CLI, and Codex IDE extension share MCP configuration for the same Codex host. In ChatGPT desktop you can also open **Settings → MCP servers → Add server**, select STDIO, and use the same command. Restart the client after adding it, then use `/mcp` to confirm `garmin-cn` is connected.
ChatGPT web does not read local Codex MCP configuration. Web use would require a separately hosted remote MCP/plugin with a multi-user authorization and privacy design; that is intentionally outside this project.
## Tools
- `get_connection_status`
- `get_daily_summary`
- `get_sleep`
- `get_heart_rate`
- `get_hrv`
- `get_training_readiness`
- `get_morning_training_readiness`
- `get_body_battery`
- `list_activities`
- `get_activity_details`
- `get_activity_exercise_sets`
- `get_activity_supplementary`
Every tool is read-only and non-destructive. Date ranges are capped at 31 days and activity lists at 100 results. No raw API-path or Garmin write tool is exposed.
## Custom token-store path
Set `GARMIN_CN_TOKEN_STORE` for both auth and MCP processes, or pass `--token-store` to either command. Keep the path outside a Git repository.
## Development checks
```bash
uv sync --group dev
uv run pytest
uv run ruff check .
uv run mypy
```
Tests use fabricated providers and never contact Garmin.
TDQS
Scored across 12 tools
Each tool targets a distinct data type or granularity: connection status, daily summary, sleep, heart rate, HRV, training readiness (overall vs. morning), body battery, activity list, and three activity-specific detail tools. No two tools have overlapping purposes; even the two training readiness tools are clearly differentiated by scope.
Most tools follow a consistent 'get_' + noun pattern, with clear and descriptive names like get_sleep, get_hrv, and get_activity_details. The only deviation is 'list_activities' which uses 'list' instead of 'get', but this is a minor and sensible variation for a collection-returning operation.
With 12 tools covering wellness metrics, activity lifecycle, and supplementary data, the count is well-scoped for a Garmin data retrieval server. Each tool serves a distinct purpose and none feel redundant or missing, making the set feel appropriately sized.
The server covers the major wellness and activity data categories from Garmin Connect China: daily summaries, sleep, heart rate, HRV, training readiness, body battery, activity lists, and detailed activity breakdowns. Minor gaps like stress or step-specific endpoints are likely covered by the daily summary, so the surface is quite complete for read-only access.