@indaco/garmin-personal-mcp 0.1.1 → 0.3.0
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.
- package/README.md +121 -95
- package/dist/dashboard.html +7 -7
- package/dist/index.js +3163 -546
- package/package.json +1 -1
- package/prompts/dashboard-language.md +3 -0
- package/prompts/dashboard-setup.md +21 -3
- package/prompts/dashboard-widget.md +6 -1
- package/prompts/training-dashboard-freeform.md +15 -0
- package/prompts/training-dashboard-update.md +12 -0
- package/prompts/training-dashboard.md +39 -4
package/README.md
CHANGED
|
@@ -18,49 +18,63 @@
|
|
|
18
18
|
|
|
19
19
|
<p align="center">
|
|
20
20
|
<b><a href="#quick-start">Quick start</a></b> ·
|
|
21
|
-
<b><a href="#
|
|
22
|
-
<b><a href="#dashboard-setup">Dashboard setup</a></b> ·
|
|
21
|
+
<b><a href="#what-you-can-ask">What you can ask</a></b> ·
|
|
23
22
|
<b><a href="#tools">Tools</a></b> ·
|
|
24
|
-
<b><a href="#
|
|
25
|
-
<b><a href="guide/dashboard.md">Dashboard guide</a></b> ·
|
|
23
|
+
<b><a href="#dashboard">Dashboard</a></b> ·
|
|
26
24
|
<b><a href="guide/how-it-works.md">How it works</a></b> ·
|
|
27
25
|
<b><a href="guide/troubleshooting.md">Troubleshooting</a></b>
|
|
28
26
|
</p>
|
|
29
27
|
|
|
28
|
+
<p align="center">
|
|
29
|
+
An MCP server that lets your assistant read your Garmin data: activities, laps, strength sets,
|
|
30
|
+
sleep, HRV and more. Ask questions in the chat, or let the server build a training dashboard.
|
|
31
|
+
</p>
|
|
32
|
+
|
|
30
33
|
<p align="center">
|
|
31
34
|
<img src="assets/dashboard.gif" alt="The training dashboard: the All board, load against recovery, the Run board, strength trends, edit mode (drag a widget to a new place, hide a widget, add widgets from the catalogue to an empty board), and the light and high-contrast themes" width="800">
|
|
32
35
|
</p>
|
|
33
36
|
<p align="center">
|
|
34
|
-
<sub><i>
|
|
37
|
+
<sub><i>One thing you can build: the training dashboard, with demo data.</i></sub>
|
|
35
38
|
</p>
|
|
36
39
|
|
|
37
|
-
|
|
40
|
+
## What you can ask
|
|
41
|
+
|
|
42
|
+
With this server, you can ask your assistant:
|
|
43
|
+
|
|
44
|
+
- Activities: "List my last 5 activities, with pace and heart rate."
|
|
45
|
+
- Activities: "How much time did I spend in each HR zone on my runs this month?"
|
|
46
|
+
- Activities: "How did my sessions named Tempo 5k and Long run change over the last 2 months?"
|
|
47
|
+
- Laps: "Show the laps of my last run."
|
|
48
|
+
- Strength: "Compare my sets of this week with the week before."
|
|
49
|
+
- Strength: "Which muscles did I train most this week?"
|
|
50
|
+
- Workouts: "Did I do the reps and rests my workout planned?"
|
|
51
|
+
- Recovery: "How did I sleep this week, and how was my HRV?"
|
|
52
|
+
- Recovery: "Show my steps, stress and Body Battery for the last 7 days."
|
|
53
|
+
- Recovery: "Did my Body Battery recover overnight this week, and which days drained it most?"
|
|
54
|
+
- Body: "How has my weight changed over the last 3 months?"
|
|
55
|
+
- All together: "My run on Saturday felt hard. Compare it with my sleep and HRV of the nights
|
|
56
|
+
before."
|
|
38
57
|
|
|
39
58
|
## Features
|
|
40
59
|
|
|
41
60
|
- **Official and read-only**: uses the Garmin Connect Personal API. It writes nothing back.
|
|
42
61
|
- **Nothing to install**: runs with `npx`.
|
|
43
|
-
- **Laps and strength sets**: read from the original .FIT files.
|
|
44
|
-
- **Recovery data**: HRV, sleep and
|
|
45
|
-
- **
|
|
46
|
-
|
|
47
|
-
[let the assistant design the whole page](#presets-or-freeform).
|
|
48
|
-
- **Your layout stays**: [training-dashboard-update](#training-dashboard-update) adds only the
|
|
49
|
-
new data.
|
|
50
|
-
- **A page for you or for your coach**: [dashboard-setup](#dashboard-setup) makes a personal page,
|
|
51
|
-
or a page to share with your coach or personal trainer. You select the sports and the data. The
|
|
52
|
-
data that you do not select is not in the file.
|
|
53
|
-
- **Extend it**: [dashboard-widget](#dashboard-widget) makes a new widget from your idea.
|
|
54
|
-
[dashboard-language](#dashboard-language) adds a language.
|
|
62
|
+
- **Laps and strength sets**: read from the original .FIT files, with the muscles of each set.
|
|
63
|
+
- **Recovery data**: HRV, sleep, heart rate, stress and Body Battery.
|
|
64
|
+
- **All of the Personal API**: [`garminGet`](#tools) reads the endpoints that have no tool of
|
|
65
|
+
their own.
|
|
55
66
|
- **All stdio clients**: Claude Desktop, Claude Code, Codex and all other MCP clients that use
|
|
56
67
|
stdio. Tested with Claude Desktop and Claude Code.
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
-
|
|
62
|
-
|
|
63
|
-
|
|
68
|
+
- **Dashboard in less than a minute**: [training-dashboard](#training-dashboard) shows your
|
|
69
|
+
training load next to recovery, in widgets that you can move, resize, hide and add.
|
|
70
|
+
[training-dashboard-update](#training-dashboard-update) adds only the new data, and your layout
|
|
71
|
+
stays.
|
|
72
|
+
- **Dashboard for you or for your coach**: [dashboard-setup](#dashboard-setup) makes a page with
|
|
73
|
+
only the sports and the data that you select. [dashboard-language](#dashboard-language) adds a
|
|
74
|
+
language.
|
|
75
|
+
- **Your own widgets**: [dashboard-widget](#dashboard-widget) makes a widget from your idea. Your
|
|
76
|
+
widgets stay on your computer in your widget library, and each page that you make gets them, in
|
|
77
|
+
the languages of the page.
|
|
64
78
|
|
|
65
79
|
## Quick start
|
|
66
80
|
|
|
@@ -136,15 +150,47 @@ show MCP prompts. In these clients, ask for the dashboard in your own words. The
|
|
|
136
150
|
Ask "list my last 5 activities". The first time that a garmin-personal tool asks for permission, answer
|
|
137
151
|
**Allow always** in Claude Desktop. In Claude Code, use `/permissions` and add `mcp__garmin-personal`.
|
|
138
152
|
|
|
139
|
-
##
|
|
153
|
+
## Tools
|
|
140
154
|
|
|
141
|
-
|
|
142
|
-
|
|
155
|
+
| Tool | What it gives |
|
|
156
|
+
| -------------------------- | ------------------------------------------------------------------------------ |
|
|
157
|
+
| `listActivities` | each activity with pace, HR, load and effect, by date, type or name |
|
|
158
|
+
| `getActivity` | the details of one activity |
|
|
159
|
+
| `getActivityLaps` | the laps of an activity, from its .FIT file |
|
|
160
|
+
| `getActivitySets` | the strength sets of an activity, with the muscles, from its .FIT file |
|
|
161
|
+
| `getActivityWorkouts` | the planned workout of an activity: steps, targets and notes |
|
|
162
|
+
| `downloadActivityFit` | saves the .FIT file of an activity in the data folder |
|
|
163
|
+
| `getHrvRange` | HRV during the night |
|
|
164
|
+
| `getDailyHeartRate` | the heart rate of a day, with the resting HR |
|
|
165
|
+
| `getSleep` | the sleep of a night, or of up to 14 nights |
|
|
166
|
+
| `getWeight` | weight and body composition for a range of dates |
|
|
167
|
+
| `getBodyBattery` | how Body Battery charged and drained, for up to 14 days |
|
|
168
|
+
| `getHeartRateZones` | your HR zones |
|
|
169
|
+
| `getFitnessAge` | fitness age against actual age |
|
|
170
|
+
| `getDailySummary` | steps, stress and Body Battery, for a day or a range |
|
|
171
|
+
| `getDashboardData` | all the data of the dashboard in one call, with a local cache |
|
|
172
|
+
| `writeDashboard` | writes the dashboard page |
|
|
173
|
+
| `editDashboard` | changes the layout, the custom widgets and the languages of the page |
|
|
174
|
+
| `scheduleDashboardRefresh` | updates a dashboard page automatically, at the times you say in your own words |
|
|
175
|
+
| `garminGet` | all other GET endpoints of the Personal API |
|
|
143
176
|
|
|
144
|
-
|
|
177
|
+
[Tools](guide/tools.md) gives the endpoints, the details of each tool and the data that the
|
|
178
|
+
Personal API does not have.
|
|
145
179
|
|
|
146
|
-
|
|
147
|
-
|
|
180
|
+
## Dashboard
|
|
181
|
+
|
|
182
|
+
The server makes a training dashboard with these prompts. In Claude Desktop, the prompts are in
|
|
183
|
+
the **+** menu of the message box, under _garmin-personal_. In Claude Code, they are slash commands.
|
|
184
|
+
|
|
185
|
+
| Prompt | What it does | Claude Code example |
|
|
186
|
+
| ------------------------------------------------------- | -------------------------------------- | --------------------------------------------------- |
|
|
187
|
+
| [training-dashboard](#training-dashboard) | makes the page | `/garmin-personal:training-dashboard 8` |
|
|
188
|
+
| [training-dashboard-update](#training-dashboard-update) | adds the new data, your layout stays | `/garmin-personal:training-dashboard-update` |
|
|
189
|
+
| [dashboard-setup](#dashboard-setup) | makes a page for you or for your coach | `/garmin-personal:dashboard-setup` |
|
|
190
|
+
| [dashboard-widget](#dashboard-widget) | makes a new widget from your idea | `/garmin-personal:dashboard-widget my longest ride` |
|
|
191
|
+
| [dashboard-language](#dashboard-language) | adds a language to the page | `/garmin-personal:dashboard-language German` |
|
|
192
|
+
|
|
193
|
+
The prompts remove all spaces around an argument, also the no-break space from a phone keyboard.
|
|
148
194
|
|
|
149
195
|
### training-dashboard
|
|
150
196
|
|
|
@@ -161,18 +207,24 @@ The page is one HTML file, `garmin-dashboard.html` in the data folder. It works
|
|
|
161
207
|
- `freeform` lets the assistant design the whole page. This takes much longer, and each page looks
|
|
162
208
|
different.
|
|
163
209
|
|
|
164
|
-
| Client | How to run it |
|
|
165
|
-
| -------------- | --------------------------------------------------------------------------- |
|
|
166
|
-
| Claude Desktop | **+** → _garmin-personal_ → `training-dashboard` → set the arguments → send |
|
|
167
|
-
| Claude Code | `/garmin-personal:training-dashboard 8` |
|
|
168
|
-
|
|
169
210
|
In Claude Code, the arguments are in order and separated by spaces: first `weeks`, then `layout`.
|
|
170
211
|
You can also give only the layout: `/garmin-personal:training-dashboard freeform`.
|
|
171
212
|
|
|
213
|
+
With `preset` and `blank`, the assistant first asks for the title and the headline (the line under
|
|
214
|
+
the title) of the page. Keep them or type your own. Updates and the automatic update keep them.
|
|
215
|
+
|
|
172
216
|
The assistant gives you the path of the page and the command to open it. The page has a board for
|
|
173
|
-
all your training, a Recovery board and a board for each sport, with 11 themes
|
|
174
|
-
|
|
175
|
-
|
|
217
|
+
all your training, a Recovery board and a board for each sport, with 11 themes, in English and the
|
|
218
|
+
language of your Garmin profile. If the dashboard does not have the language of your profile (for
|
|
219
|
+
example Russian), the page shows English, and the assistant tells you and offers to add the
|
|
220
|
+
language. The assistant asks if you want one more language. The page uses
|
|
221
|
+
the training load, HR zones and training effect from Garmin. It labels each value that it
|
|
222
|
+
calculates as an estimate, and a missing value shows as "n/a". Distances, paces,
|
|
223
|
+
elevation and weights use the units of your Garmin profile: metric, or miles and pounds for
|
|
224
|
+
Statute US and Statute UK (Statute UK keeps elevation in metres).
|
|
225
|
+
|
|
226
|
+
To follow a training plan, choose its activity names above the boards: the page then shows only
|
|
227
|
+
those activities, in the weeks of the window.
|
|
176
228
|
|
|
177
229
|
[The dashboard guide](guide/dashboard.md) tells what each board shows and how to change the layout.
|
|
178
230
|
[The widget catalogue](guide/widgets.md) lists every widget.
|
|
@@ -190,14 +242,15 @@ your languages stay. Reload the page to see the new data.
|
|
|
190
242
|
In Claude Code: `/garmin-personal:training-dashboard-update coach.html` updates `coach.html`. A
|
|
191
243
|
value that ends in `.html` is the file, also in the first place.
|
|
192
244
|
|
|
193
|
-
| Client | How to run it |
|
|
194
|
-
| -------------- | -------------------------------------------------------------- |
|
|
195
|
-
| Claude Desktop | **+** → _garmin-personal_ → `training-dashboard-update` → send |
|
|
196
|
-
| Claude Code | `/garmin-personal:training-dashboard-update` |
|
|
197
|
-
|
|
198
245
|
The first call sends approximately 35 requests to Garmin. Later calls use the local cache and send
|
|
199
246
|
approximately 8.
|
|
200
247
|
|
|
248
|
+
To update the page automatically, tell your assistant when, in your own words and in any language,
|
|
249
|
+
for example "update my dashboard every Monday at 7". When it makes a page, the assistant also asks:
|
|
250
|
+
no (the default), every day, weekdays or every Monday at 07:00, or your own words. The automatic
|
|
251
|
+
update replaces the data and removes the coach notes. See
|
|
252
|
+
[Update the dashboard on a schedule](guide/dashboard.md#update-the-dashboard-on-a-schedule).
|
|
253
|
+
|
|
201
254
|
### dashboard-setup
|
|
202
255
|
|
|
203
256
|
The assistant asks you some questions, then writes a page with your answers. First, it asks who the
|
|
@@ -213,18 +266,14 @@ is not in the file, so you can send the file safely. A personal page and a share
|
|
|
213
266
|
files side by side. Each page keeps its settings on each update. The argument `weeks` is optional
|
|
214
267
|
(default 12).
|
|
215
268
|
|
|
216
|
-
| Client | How to run it |
|
|
217
|
-
| -------------- | ---------------------------------------------------- |
|
|
218
|
-
| Claude Desktop | **+** → _garmin-personal_ → `dashboard-setup` → send |
|
|
219
|
-
| Claude Code | `/garmin-personal:dashboard-setup` |
|
|
220
|
-
|
|
221
269
|
[Page settings](guide/dashboard.md#page-settings) tells more.
|
|
222
270
|
|
|
223
271
|
### dashboard-widget
|
|
224
272
|
|
|
225
273
|
This prompt makes a new widget from your idea, for example "my longest ride of each month". The
|
|
226
|
-
assistant writes a small widget, and `editDashboard` stores it in the page
|
|
227
|
-
|
|
274
|
+
assistant writes a small widget, and `editDashboard` stores it in the page and in your widget
|
|
275
|
+
library (`widgets.json` in the data folder). The widget stays after each update, and each new page
|
|
276
|
+
gets it too. The argument `idea` is required. The argument `path` is optional: it is the file of the
|
|
228
277
|
page, for example `coach.html`. In Claude Code:
|
|
229
278
|
`/garmin-personal:dashboard-widget my longest ride each month coach.html`. Reload the page to see
|
|
230
279
|
the widget.
|
|
@@ -240,28 +289,21 @@ text without a translation shows in English. To remove an added language, ask yo
|
|
|
240
289
|
remove it: `editDashboard` with `removeLanguages`.
|
|
241
290
|
[Languages](guide/languages.md) tells more.
|
|
242
291
|
|
|
243
|
-
|
|
292
|
+
### Presets or freeform
|
|
244
293
|
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
| `getActivityLaps` | the laps of an activity, from its .FIT file |
|
|
250
|
-
| `getActivitySets` | the strength sets of an activity, with the muscles, from its .FIT file |
|
|
251
|
-
| `downloadActivityFit` | saves the .FIT file of an activity in the data folder |
|
|
252
|
-
| `getHrvRange` | HRV during the night |
|
|
253
|
-
| `getDailyHeartRate` | the heart rate of a day, with the resting HR |
|
|
254
|
-
| `getSleep` | the sleep of a night, or of up to 14 nights |
|
|
255
|
-
| `getHeartRateZones` | your HR zones |
|
|
256
|
-
| `getFitnessAge` | fitness age against actual age |
|
|
257
|
-
| `getDailySummary` | steps, stress and Body Battery, for a day or a range |
|
|
258
|
-
| `getDashboardData` | all the data of the dashboard in one call, with a local cache |
|
|
259
|
-
| `writeDashboard` | writes the dashboard page |
|
|
260
|
-
| `editDashboard` | changes the layout, the custom widgets and the languages of the page |
|
|
261
|
-
| `garminGet` | all other GET endpoints of the Personal API |
|
|
294
|
+
In many setup guides for Claude and Garmin, Claude reads the data and writes the whole dashboard
|
|
295
|
+
page. With a preset, the server writes the page from a tested template, and Claude writes only the
|
|
296
|
+
coach notes. My measurements for a first build, with Claude Code and Opus
|
|
297
|
+
(other clients and models give other times and costs):
|
|
262
298
|
|
|
263
|
-
|
|
264
|
-
|
|
299
|
+
| First build | Time | Cost |
|
|
300
|
+
| ---------------------- | ------------ | ------------ |
|
|
301
|
+
| Preset | 34 s | $0.16 |
|
|
302
|
+
| Claude writes the page | 24 to 35 min | $6.6 to $9.2 |
|
|
303
|
+
|
|
304
|
+
For a design of your own, use `layout` = `freeform`: Claude writes the page, as in those guides.
|
|
305
|
+
|
|
306
|
+
[Presets or freeform](guide/presets.md) gives the measurements and the limits of the presets.
|
|
265
307
|
|
|
266
308
|
## Configuration
|
|
267
309
|
|
|
@@ -285,22 +327,6 @@ In Claude Code, add `--env GARMIN_DATA_DIR=/path/to/garmin-data` to `claude mcp
|
|
|
285
327
|
[The data folder](guide/tools.md#the-data-folder) lists the files that the server keeps and its
|
|
286
328
|
log.
|
|
287
329
|
|
|
288
|
-
## Presets or freeform
|
|
289
|
-
|
|
290
|
-
In many setup guides for Claude and Garmin, Claude reads the data and writes the whole dashboard
|
|
291
|
-
page. With a preset, the server writes the page from a tested template, and Claude writes only the
|
|
292
|
-
coach notes. My measurements for a first build, with Claude Code and Opus
|
|
293
|
-
(other clients and models give other times and costs):
|
|
294
|
-
|
|
295
|
-
| First build | Time | Cost |
|
|
296
|
-
| ---------------------- | ------------ | ------------ |
|
|
297
|
-
| Preset | 34 s | $0.16 |
|
|
298
|
-
| Claude writes the page | 24 to 35 min | $6.6 to $9.2 |
|
|
299
|
-
|
|
300
|
-
For a design of your own, use `layout` = `freeform`: Claude writes the page, as in those guides.
|
|
301
|
-
|
|
302
|
-
[Presets or freeform](guide/presets.md) gives the measurements and the limits of the presets.
|
|
303
|
-
|
|
304
330
|
## Security
|
|
305
331
|
|
|
306
332
|
The server is read-only. It sends the API key only to the Garmin token endpoint, and it never logs
|
|
@@ -339,17 +365,17 @@ To build a demo site with a year of sample data, run `pnpm build`, then
|
|
|
339
365
|
The idea comes from [apratico/garmin-mcp](https://github.com/apratico/garmin-mcp) by Alessandro
|
|
340
366
|
Praticò: a Java MCP server for the Garmin Personal API, where Claude writes the dashboard. I
|
|
341
367
|
tested it in a fork, [indaco/garmin-mcp](https://github.com/indaco/garmin-mcp), and then made this
|
|
342
|
-
server as a different solution
|
|
343
|
-
|
|
344
|
-
- **No Java**: the server runs with `npx`. You do not need Java 21 and a jar file.
|
|
345
|
-
- **The server writes the page**: in garmin-mcp, Claude writes all of the dashboard HTML on each run. Here the server fills a tested template, and Claude writes only the coach notes. A first build takes seconds, not minutes ([measurements](#presets-or-freeform)).
|
|
346
|
-
- **Updates keep your page**: [training-dashboard-update](#training-dashboard-update) adds only the new data, and your layout stays.
|
|
347
|
-
- **Widgets that you control**: charts for training load, recovery, running and strength. In the page, you drag, resize, hide and add widgets, and select a theme.
|
|
348
|
-
- **Setup by sport**: [dashboard-setup](#dashboard-setup) makes a page with only the sports and the data that you select, for you or for your coach.
|
|
349
|
-
- **Languages and custom widgets**: [dashboard-language](#dashboard-language) and [dashboard-widget](#dashboard-widget) extend the page.
|
|
368
|
+
server as a different solution. It runs with `npx`, without Java, and it writes the dashboard page
|
|
369
|
+
from a tested template.
|
|
350
370
|
|
|
351
371
|
This server uses the same key file as indaco/garmin-mcp and can share its data folder.
|
|
352
372
|
|
|
373
|
+
## How this was built
|
|
374
|
+
|
|
375
|
+
AI agents in Claude Code wrote the code, tests and docs of this project. I chose the design,
|
|
376
|
+
reviewed each change and tested the server with my own Garmin data. The rules that the agents
|
|
377
|
+
follow are in [AGENTS.md](AGENTS.md).
|
|
378
|
+
|
|
353
379
|
## License
|
|
354
380
|
|
|
355
381
|
This project uses the [MIT License](LICENSE). `dist/index.js` and the dashboard page include
|