garmin-mcp-server 0.1.1__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,34 @@
1
+ # ---------------------------------------------------------------------------
2
+ # Garmin Connect MCP server configuration
3
+ # ---------------------------------------------------------------------------
4
+ # Copy this file to ".env" and fill in your values. The ".env" file is
5
+ # git-ignored and will NEVER be committed.
6
+ #
7
+ # cp .env.example .env
8
+ #
9
+ # RECOMMENDED: do NOT store your password here. Instead run the one-time
10
+ # interactive login which handles MFA and caches OAuth tokens locally:
11
+ #
12
+ # garmin-mcp-login
13
+ #
14
+ # After that, the server logs in using the cached tokens only — no password
15
+ # is ever needed at runtime.
16
+ # ---------------------------------------------------------------------------
17
+
18
+ # Your Garmin Connect account email (only needed for the initial login).
19
+ GARMIN_EMAIL=
20
+
21
+ # Your Garmin Connect password (optional; prefer token-based auth above).
22
+ # If your account has MFA enabled, password-only login will fail in the
23
+ # server context — use `garmin-mcp-login` instead.
24
+ GARMIN_PASSWORD=
25
+
26
+ # Directory where OAuth tokens are cached (garth token store).
27
+ # Defaults to ~/.garminconnect when unset. GARMIN_TOKEN_DIR is also accepted.
28
+ GARMINTOKENS=~/.garminconnect
29
+
30
+ # Set to "true" if your account is registered on garmin.cn (China).
31
+ GARMIN_IS_CN=false
32
+
33
+ # Optional: logging verbosity for the server (DEBUG, INFO, WARNING, ERROR).
34
+ GARMIN_MCP_LOG_LEVEL=INFO
@@ -0,0 +1,37 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: [main]
6
+ pull_request:
7
+
8
+ jobs:
9
+ test:
10
+ runs-on: ubuntu-latest
11
+ strategy:
12
+ fail-fast: false
13
+ matrix:
14
+ python-version: ["3.10", "3.11", "3.12"]
15
+ steps:
16
+ - uses: actions/checkout@v4
17
+
18
+ - name: Install uv
19
+ uses: astral-sh/setup-uv@v5
20
+
21
+ - name: Set up Python ${{ matrix.python-version }}
22
+ run: uv python install ${{ matrix.python-version }}
23
+
24
+ # Create a venv pinned to the matrix Python. Without this, `uv pip
25
+ # install --system` would target the runner's system interpreter and
26
+ # ignore the matrix version entirely.
27
+ - name: Create virtual environment
28
+ run: uv venv --python ${{ matrix.python-version }}
29
+
30
+ - name: Install dependencies
31
+ run: uv pip install -e ".[dev]"
32
+
33
+ - name: Lint (ruff)
34
+ run: uv run ruff check garmin_mcp tests
35
+
36
+ - name: Test (pytest)
37
+ run: uv run pytest
@@ -0,0 +1,121 @@
1
+ name: Release
2
+
3
+ # On a version tag (e.g. v0.1.0):
4
+ # 1. lint + test + build sdist/wheel,
5
+ # 2. publish a GitHub Release with auto-generated notes + artifacts,
6
+ # 3. publish to PyPI via Trusted Publishing (OIDC - no API tokens stored).
7
+ #
8
+ # git tag -a v0.1.0 -m "v0.1.0"
9
+ # git push origin v0.1.0
10
+ #
11
+ # One-time PyPI setup (see README "Releasing"): register this repo + the
12
+ # "pypi" environment as a Trusted Publisher at
13
+ # https://pypi.org/manage/account/publishing/
14
+
15
+ on:
16
+ push:
17
+ tags:
18
+ - "v*"
19
+
20
+ jobs:
21
+ build:
22
+ name: Build & test
23
+ runs-on: ubuntu-latest
24
+ permissions:
25
+ contents: write # create the GitHub Release
26
+ steps:
27
+ - uses: actions/checkout@v4
28
+ with:
29
+ fetch-depth: 0 # full history so we can diff against the previous tag
30
+
31
+ - name: Install uv
32
+ uses: astral-sh/setup-uv@v5
33
+
34
+ - name: Set up Python
35
+ run: uv python install 3.12
36
+
37
+ - name: Create virtual environment
38
+ run: uv venv --python 3.12
39
+
40
+ - name: Install project (with dev extras)
41
+ run: uv pip install -e ".[dev]" build
42
+
43
+ - name: Lint
44
+ run: uv run ruff check garmin_mcp tests
45
+
46
+ - name: Test
47
+ run: uv run pytest
48
+
49
+ - name: Build sdist and wheel
50
+ run: uv run python -m build
51
+
52
+ - name: Verify version matches the tag
53
+ run: |
54
+ TAG="${GITHUB_REF_NAME#v}"
55
+ PKG="$(uv run python -c 'import garmin_mcp; print(garmin_mcp.__version__)')"
56
+ echo "tag=$TAG package=$PKG"
57
+ if [ "$TAG" != "$PKG" ]; then
58
+ echo "::error::Tag ($TAG) does not match package version ($PKG)"
59
+ exit 1
60
+ fi
61
+
62
+ - name: Generate release notes
63
+ run: |
64
+ set -euo pipefail
65
+ CURRENT="${GITHUB_REF_NAME}"
66
+ PREV="$(git describe --tags --abbrev=0 "${CURRENT}^" 2>/dev/null || true)"
67
+ {
68
+ echo "## What's changed in ${CURRENT}"
69
+ echo
70
+ if [ -n "$PREV" ]; then
71
+ echo "Changes since ${PREV}:"
72
+ echo
73
+ git log --pretty=format:'- %s (%h)' "${PREV}..${CURRENT}"
74
+ echo
75
+ echo
76
+ echo "**Full diff:** https://github.com/${GITHUB_REPOSITORY}/compare/${PREV}...${CURRENT}"
77
+ else
78
+ echo "First release."
79
+ echo
80
+ git log --pretty=format:'- %s (%h)'
81
+ fi
82
+ } > RELEASE_NOTES.md
83
+ echo "Generated release notes:"
84
+ cat RELEASE_NOTES.md
85
+
86
+ - name: Upload build artifacts
87
+ uses: actions/upload-artifact@v4
88
+ with:
89
+ name: dist
90
+ path: dist/*
91
+
92
+ - name: Publish GitHub Release
93
+ uses: softprops/action-gh-release@v2
94
+ with:
95
+ body_path: RELEASE_NOTES.md
96
+ files: |
97
+ dist/*.whl
98
+ dist/*.tar.gz
99
+ fail_on_unmatched_files: true
100
+
101
+ pypi-publish:
102
+ name: Publish to PyPI
103
+ needs: build
104
+ runs-on: ubuntu-latest
105
+ environment:
106
+ name: pypi
107
+ url: https://pypi.org/p/garmin-mcp-server
108
+ steps:
109
+ - name: Download build artifacts
110
+ uses: actions/download-artifact@v4
111
+ with:
112
+ name: dist
113
+ path: dist
114
+
115
+ - name: Publish to PyPI
116
+ uses: pypa/gh-action-pypi-publish@release/v1
117
+ with:
118
+ password: ${{ secrets.PYPI_API_TOKEN }}
119
+ # Attestations require OIDC (id-token: write); disable them when
120
+ # authenticating with an API token instead of Trusted Publishing.
121
+ attestations: false
@@ -0,0 +1,88 @@
1
+ # ---------------------------------------------------------------------------
2
+ # SECURITY: never commit credentials or Garmin auth tokens
3
+ # ---------------------------------------------------------------------------
4
+ .env
5
+ .env.*
6
+ !.env.example
7
+ *.env
8
+ secrets.*
9
+ credentials.*
10
+
11
+ # Garmin Connect OAuth token stores (garth dumps oauth1/oauth2 tokens here)
12
+ .garminconnect/
13
+ .garth/
14
+ tokens/
15
+ *.garth
16
+ oauth1_token.json
17
+ oauth2_token.json
18
+ garmin_tokens/
19
+
20
+ # Downloaded activity files (may contain GPS / personal data)
21
+ downloads/
22
+ *.fit
23
+ *.tcx
24
+ *.gpx
25
+ *.zip
26
+
27
+ # ---------------------------------------------------------------------------
28
+ # Python
29
+ # ---------------------------------------------------------------------------
30
+ __pycache__/
31
+ *.py[cod]
32
+ *$py.class
33
+ *.so
34
+ .Python
35
+ build/
36
+ develop-eggs/
37
+ dist/
38
+ eggs/
39
+ .eggs/
40
+ lib64/
41
+ parts/
42
+ sdist/
43
+ var/
44
+ wheels/
45
+ *.egg-info/
46
+ .installed.cfg
47
+ *.egg
48
+ MANIFEST
49
+
50
+ # Virtual environments
51
+ .venv/
52
+ venv/
53
+ env/
54
+ ENV/
55
+ .python-version
56
+
57
+ # Test / coverage
58
+ .pytest_cache/
59
+ .coverage
60
+ .coverage.*
61
+ htmlcov/
62
+ .tox/
63
+ .nox/
64
+ coverage.xml
65
+ *.cover
66
+ .cache/
67
+
68
+ # Type checkers / linters
69
+ .mypy_cache/
70
+ .dmypy.json
71
+ .ruff_cache/
72
+ .pyright/
73
+
74
+ # IDE / editor
75
+ .idea/
76
+ .vscode/
77
+ *.swp
78
+ *.swo
79
+ *~
80
+ .DS_Store
81
+
82
+ # Logs
83
+ *.log
84
+
85
+ # Local tooling / agent artifacts (not part of the project)
86
+ .claude/
87
+ .tldr/
88
+ .tldrignore
@@ -0,0 +1,53 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [Unreleased]
9
+
10
+ ### Fixed
11
+ - **Auth for garminconnect 0.3.2.** Authentication now delegates entirely to
12
+ garminconnect's own `login(tokenstore)`, which natively loads/refreshes
13
+ Garmin DI session tokens (the `{di_token, di_refresh_token, di_client_id}`
14
+ mobile token format), a token directory, or email/password — and persists
15
+ fresh tokens. Removes the obsolete `.garth` attribute access that broke on
16
+ 0.3.2. `garmin-mcp-login` now uses garminconnect's `prompt_mfa` flow.
17
+ Verified live against a real account (curated + auto-exposed tools).
18
+
19
+ ### Added
20
+ - **Full garminconnect 0.3.2 API coverage.** In addition to the 48 curated
21
+ tools, every remaining public `garminconnect` method is now auto-registered as
22
+ a tool at startup (endurance score, intensity minutes, weekly steps/stress,
23
+ FTP, lactate threshold, running tolerance, nutrition, golf, gear stats,
24
+ scheduled workouts, training plans, badge challenges, and all write/upload/
25
+ delete actions). The set stays in sync with the library automatically — new
26
+ methods become tools on upgrade.
27
+
28
+ ## [0.1.0] - 2026-05-31
29
+
30
+ ### Added
31
+ - Initial release of the Garmin Connect MCP server.
32
+ - 48 MCP tools spanning:
33
+ - **Profile & devices** — user profile, units, registered devices.
34
+ - **Daily health** — daily summary, steps, floors, heart rate, resting HR.
35
+ - **Wellness** — sleep, stress, Body Battery, SpO₂, respiration, HRV,
36
+ hydration, blood pressure.
37
+ - **Training** — readiness, status, VO₂max, fitness age, race predictions,
38
+ Hill Score, progress summary.
39
+ - **Activities** — list/by-date, summary, details, splits, weather, HR zones,
40
+ rename, download (FIT/TCX/GPX/CSV/KML), count.
41
+ - **Body** — body composition, weigh-ins, add weigh-in.
42
+ - **Records & more** — personal records, goals, badges, gear, workouts,
43
+ menstrual data, and a raw `connect_api` passthrough.
44
+ - Token-based authentication with MFA support via a one-time `garmin-mcp-login`.
45
+ - Resilient client: lazy auth, thread-safe, transparent re-authentication on
46
+ session expiry, friendly date inputs (`today`/`yesterday`/`-7`/ISO).
47
+ - Automatic trimming of large time-series payloads to stay context-friendly.
48
+ - Unit-test suite (mocked, offline) and a live integration script.
49
+ - GitHub Actions CI (lint + tests across Python 3.10–3.12) and a tag-driven
50
+ release workflow that builds artifacts and publishes auto-generated notes.
51
+
52
+ [Unreleased]: https://github.com/stitrace/garmin-mcp-server/compare/v0.1.0...HEAD
53
+ [0.1.0]: https://github.com/stitrace/garmin-mcp-server/releases/tag/v0.1.0
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 stitrace
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.