intervals-icu-mcp-server 0.2.0 → 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/dist/client.d.ts CHANGED
@@ -32,6 +32,60 @@ export declare const ActivitySchema: z.ZodObject<{
32
32
  feel: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
33
33
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
34
34
  trainer: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
35
+ decoupling: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
36
+ icu_efficiency_factor: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
37
+ icu_power_hr: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
38
+ icu_variability_index: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
39
+ icu_pm_cp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
40
+ icu_rolling_ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
41
+ polarization_index: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
42
+ icu_zone_times: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
43
+ id: z.ZodString;
44
+ secs: z.ZodNumber;
45
+ }, "strip", z.ZodTypeAny, {
46
+ id: string;
47
+ secs: number;
48
+ }, {
49
+ id: string;
50
+ secs: number;
51
+ }>, "many">>>;
52
+ icu_hr_zone_times: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
53
+ total_elevation_loss: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
54
+ max_speed: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
55
+ min_altitude: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
56
+ max_altitude: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
57
+ icu_joules: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
58
+ icu_hrr: z.ZodOptional<z.ZodNullable<z.ZodObject<{
59
+ hrr: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
60
+ start_bpm: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
61
+ end_bpm: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
62
+ }, "strip", z.ZodTypeAny, {
63
+ hrr?: number | null | undefined;
64
+ start_bpm?: number | null | undefined;
65
+ end_bpm?: number | null | undefined;
66
+ }, {
67
+ hrr?: number | null | undefined;
68
+ start_bpm?: number | null | undefined;
69
+ end_bpm?: number | null | undefined;
70
+ }>>>;
71
+ strain_score: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
72
+ hr_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
73
+ power_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
74
+ gear: z.ZodOptional<z.ZodNullable<z.ZodObject<{
75
+ id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
76
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
77
+ }, "strip", z.ZodTypeAny, {
78
+ id?: string | null | undefined;
79
+ name?: string | null | undefined;
80
+ }, {
81
+ id?: string | null | undefined;
82
+ name?: string | null | undefined;
83
+ }>>>;
84
+ device_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
85
+ power_meter: z.ZodOptional<z.ZodNullable<z.ZodString>>;
86
+ source: z.ZodOptional<z.ZodNullable<z.ZodString>>;
87
+ compliance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
88
+ icu_chat_id: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
35
89
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
36
90
  id: z.ZodString;
37
91
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
@@ -61,6 +115,60 @@ export declare const ActivitySchema: z.ZodObject<{
61
115
  feel: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
62
116
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
63
117
  trainer: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
118
+ decoupling: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
119
+ icu_efficiency_factor: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
120
+ icu_power_hr: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
121
+ icu_variability_index: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
122
+ icu_pm_cp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
123
+ icu_rolling_ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
124
+ polarization_index: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
125
+ icu_zone_times: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
126
+ id: z.ZodString;
127
+ secs: z.ZodNumber;
128
+ }, "strip", z.ZodTypeAny, {
129
+ id: string;
130
+ secs: number;
131
+ }, {
132
+ id: string;
133
+ secs: number;
134
+ }>, "many">>>;
135
+ icu_hr_zone_times: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
136
+ total_elevation_loss: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
137
+ max_speed: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
138
+ min_altitude: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
139
+ max_altitude: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
140
+ icu_joules: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
141
+ icu_hrr: z.ZodOptional<z.ZodNullable<z.ZodObject<{
142
+ hrr: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
143
+ start_bpm: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
144
+ end_bpm: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
145
+ }, "strip", z.ZodTypeAny, {
146
+ hrr?: number | null | undefined;
147
+ start_bpm?: number | null | undefined;
148
+ end_bpm?: number | null | undefined;
149
+ }, {
150
+ hrr?: number | null | undefined;
151
+ start_bpm?: number | null | undefined;
152
+ end_bpm?: number | null | undefined;
153
+ }>>>;
154
+ strain_score: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
155
+ hr_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
156
+ power_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
157
+ gear: z.ZodOptional<z.ZodNullable<z.ZodObject<{
158
+ id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
159
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
160
+ }, "strip", z.ZodTypeAny, {
161
+ id?: string | null | undefined;
162
+ name?: string | null | undefined;
163
+ }, {
164
+ id?: string | null | undefined;
165
+ name?: string | null | undefined;
166
+ }>>>;
167
+ device_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
168
+ power_meter: z.ZodOptional<z.ZodNullable<z.ZodString>>;
169
+ source: z.ZodOptional<z.ZodNullable<z.ZodString>>;
170
+ compliance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
171
+ icu_chat_id: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
64
172
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
65
173
  id: z.ZodString;
66
174
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
@@ -90,6 +198,60 @@ export declare const ActivitySchema: z.ZodObject<{
90
198
  feel: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
91
199
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
92
200
  trainer: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
201
+ decoupling: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
202
+ icu_efficiency_factor: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
203
+ icu_power_hr: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
204
+ icu_variability_index: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
205
+ icu_pm_cp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
206
+ icu_rolling_ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
207
+ polarization_index: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
208
+ icu_zone_times: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
209
+ id: z.ZodString;
210
+ secs: z.ZodNumber;
211
+ }, "strip", z.ZodTypeAny, {
212
+ id: string;
213
+ secs: number;
214
+ }, {
215
+ id: string;
216
+ secs: number;
217
+ }>, "many">>>;
218
+ icu_hr_zone_times: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
219
+ total_elevation_loss: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
220
+ max_speed: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
221
+ min_altitude: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
222
+ max_altitude: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
223
+ icu_joules: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
224
+ icu_hrr: z.ZodOptional<z.ZodNullable<z.ZodObject<{
225
+ hrr: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
226
+ start_bpm: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
227
+ end_bpm: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
228
+ }, "strip", z.ZodTypeAny, {
229
+ hrr?: number | null | undefined;
230
+ start_bpm?: number | null | undefined;
231
+ end_bpm?: number | null | undefined;
232
+ }, {
233
+ hrr?: number | null | undefined;
234
+ start_bpm?: number | null | undefined;
235
+ end_bpm?: number | null | undefined;
236
+ }>>>;
237
+ strain_score: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
238
+ hr_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
239
+ power_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
240
+ gear: z.ZodOptional<z.ZodNullable<z.ZodObject<{
241
+ id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
242
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
243
+ }, "strip", z.ZodTypeAny, {
244
+ id?: string | null | undefined;
245
+ name?: string | null | undefined;
246
+ }, {
247
+ id?: string | null | undefined;
248
+ name?: string | null | undefined;
249
+ }>>>;
250
+ device_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
251
+ power_meter: z.ZodOptional<z.ZodNullable<z.ZodString>>;
252
+ source: z.ZodOptional<z.ZodNullable<z.ZodString>>;
253
+ compliance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
254
+ icu_chat_id: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
93
255
  }, z.ZodTypeAny, "passthrough">>;
94
256
  export type Activity = z.infer<typeof ActivitySchema>;
95
257
  export declare const WellnessSchema: z.ZodObject<{
@@ -115,6 +277,24 @@ export declare const WellnessSchema: z.ZodObject<{
115
277
  bodyFat: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
116
278
  spO2: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
117
279
  comments: z.ZodOptional<z.ZodNullable<z.ZodString>>;
280
+ rampRate: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
281
+ avgSleepingHR: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
282
+ sportInfo: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
283
+ type: z.ZodOptional<z.ZodString>;
284
+ eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
285
+ wPrime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
286
+ pMax: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
287
+ }, "strip", z.ZodTypeAny, {
288
+ type?: string | undefined;
289
+ eftp?: number | null | undefined;
290
+ wPrime?: number | null | undefined;
291
+ pMax?: number | null | undefined;
292
+ }, {
293
+ type?: string | undefined;
294
+ eftp?: number | null | undefined;
295
+ wPrime?: number | null | undefined;
296
+ pMax?: number | null | undefined;
297
+ }>, "many">>>;
118
298
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
119
299
  id: z.ZodOptional<z.ZodString>;
120
300
  ctl: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -138,6 +318,24 @@ export declare const WellnessSchema: z.ZodObject<{
138
318
  bodyFat: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
139
319
  spO2: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
140
320
  comments: z.ZodOptional<z.ZodNullable<z.ZodString>>;
321
+ rampRate: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
322
+ avgSleepingHR: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
323
+ sportInfo: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
324
+ type: z.ZodOptional<z.ZodString>;
325
+ eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
326
+ wPrime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
327
+ pMax: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
328
+ }, "strip", z.ZodTypeAny, {
329
+ type?: string | undefined;
330
+ eftp?: number | null | undefined;
331
+ wPrime?: number | null | undefined;
332
+ pMax?: number | null | undefined;
333
+ }, {
334
+ type?: string | undefined;
335
+ eftp?: number | null | undefined;
336
+ wPrime?: number | null | undefined;
337
+ pMax?: number | null | undefined;
338
+ }>, "many">>>;
141
339
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
142
340
  id: z.ZodOptional<z.ZodString>;
143
341
  ctl: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -161,6 +359,24 @@ export declare const WellnessSchema: z.ZodObject<{
161
359
  bodyFat: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
162
360
  spO2: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
163
361
  comments: z.ZodOptional<z.ZodNullable<z.ZodString>>;
362
+ rampRate: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
363
+ avgSleepingHR: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
364
+ sportInfo: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
365
+ type: z.ZodOptional<z.ZodString>;
366
+ eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
367
+ wPrime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
368
+ pMax: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
369
+ }, "strip", z.ZodTypeAny, {
370
+ type?: string | undefined;
371
+ eftp?: number | null | undefined;
372
+ wPrime?: number | null | undefined;
373
+ pMax?: number | null | undefined;
374
+ }, {
375
+ type?: string | undefined;
376
+ eftp?: number | null | undefined;
377
+ wPrime?: number | null | undefined;
378
+ pMax?: number | null | undefined;
379
+ }>, "many">>>;
164
380
  }, z.ZodTypeAny, "passthrough">>;
165
381
  export type Wellness = z.infer<typeof WellnessSchema>;
166
382
  export declare const EventSchema: z.ZodObject<{
@@ -173,6 +389,11 @@ export declare const EventSchema: z.ZodObject<{
173
389
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
174
390
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
175
391
  color: z.ZodOptional<z.ZodNullable<z.ZodString>>;
392
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
393
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
394
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
395
+ icu_intensity: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
396
+ paired_activity_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
176
397
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
177
398
  id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
178
399
  date: z.ZodOptional<z.ZodString>;
@@ -183,6 +404,11 @@ export declare const EventSchema: z.ZodObject<{
183
404
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
184
405
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
185
406
  color: z.ZodOptional<z.ZodNullable<z.ZodString>>;
407
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
408
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
409
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
410
+ icu_intensity: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
411
+ paired_activity_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
186
412
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
187
413
  id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
188
414
  date: z.ZodOptional<z.ZodString>;
@@ -193,6 +419,11 @@ export declare const EventSchema: z.ZodObject<{
193
419
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
194
420
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
195
421
  color: z.ZodOptional<z.ZodNullable<z.ZodString>>;
422
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
423
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
424
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
425
+ icu_intensity: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
426
+ paired_activity_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
196
427
  }, z.ZodTypeAny, "passthrough">>;
197
428
  export type Event = z.infer<typeof EventSchema>;
198
429
  export declare const IntervalSchema: z.ZodObject<{
@@ -264,6 +495,10 @@ export declare const SportSettingsSchema: z.ZodObject<{
264
495
  hr_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
265
496
  pace_zones: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
266
497
  pace_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
498
+ w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
499
+ sweet_spot_min: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
500
+ sweet_spot_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
501
+ best_effort_distances: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
267
502
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
268
503
  types: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
269
504
  ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -276,6 +511,10 @@ export declare const SportSettingsSchema: z.ZodObject<{
276
511
  hr_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
277
512
  pace_zones: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
278
513
  pace_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
514
+ w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
515
+ sweet_spot_min: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
516
+ sweet_spot_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
517
+ best_effort_distances: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
279
518
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
280
519
  types: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
281
520
  ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -288,6 +527,10 @@ export declare const SportSettingsSchema: z.ZodObject<{
288
527
  hr_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
289
528
  pace_zones: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
290
529
  pace_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
530
+ w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
531
+ sweet_spot_min: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
532
+ sweet_spot_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
533
+ best_effort_distances: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
291
534
  }, z.ZodTypeAny, "passthrough">>;
292
535
  export type SportSettings = z.infer<typeof SportSettingsSchema>;
293
536
  export declare const WorkoutSchema: z.ZodObject<{
@@ -296,18 +539,27 @@ export declare const WorkoutSchema: z.ZodObject<{
296
539
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
297
540
  type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
298
541
  updated: z.ZodOptional<z.ZodNullable<z.ZodString>>;
542
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
543
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
544
+ joules: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
299
545
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
300
546
  id: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
301
547
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
302
548
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
303
549
  type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
304
550
  updated: z.ZodOptional<z.ZodNullable<z.ZodString>>;
551
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
552
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
553
+ joules: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
305
554
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
306
555
  id: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
307
556
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
308
557
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
309
558
  type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
310
559
  updated: z.ZodOptional<z.ZodNullable<z.ZodString>>;
560
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
561
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
562
+ joules: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
311
563
  }, z.ZodTypeAny, "passthrough">>;
312
564
  export type Workout = z.infer<typeof WorkoutSchema>;
313
565
  export interface WorkoutInput {
@@ -371,6 +623,8 @@ export declare const MessageSchema: z.ZodObject<{
371
623
  export type Message = z.infer<typeof MessageSchema>;
372
624
  export declare function getActivityMessages(config: ClientConfig, activityId: string): Promise<Message[]>;
373
625
  export declare function addActivityMessage(config: ClientConfig, activityId: string, content: string): Promise<void>;
626
+ export declare function deleteActivityMessage(config: ClientConfig, activityId: string, messageId: number): Promise<void>;
627
+ export declare function updateActivityMessage(config: ClientConfig, activityId: string, messageId: number, content: string): Promise<void>;
374
628
  export declare function getWellness(config: ClientConfig, params: {
375
629
  startDate: string;
376
630
  endDate: string;
@@ -405,6 +659,10 @@ export declare const AthleteFitnessSchema: z.ZodObject<{
405
659
  eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
406
660
  eftpPerKg: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
407
661
  weight: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
662
+ count: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
663
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
664
+ calories: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
665
+ distance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
408
666
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
409
667
  date: z.ZodOptional<z.ZodString>;
410
668
  fitness: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -415,6 +673,10 @@ export declare const AthleteFitnessSchema: z.ZodObject<{
415
673
  eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
416
674
  eftpPerKg: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
417
675
  weight: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
676
+ count: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
677
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
678
+ calories: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
679
+ distance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
418
680
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
419
681
  date: z.ZodOptional<z.ZodString>;
420
682
  fitness: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -425,6 +687,10 @@ export declare const AthleteFitnessSchema: z.ZodObject<{
425
687
  eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
426
688
  eftpPerKg: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
427
689
  weight: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
690
+ count: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
691
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
692
+ calories: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
693
+ distance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
428
694
  }, z.ZodTypeAny, "passthrough">>;
429
695
  export type AthleteFitness = z.infer<typeof AthleteFitnessSchema>;
430
696
  export declare function getAthleteFitness(config: ClientConfig, params: {
package/dist/client.js CHANGED
@@ -53,6 +53,37 @@ export const ActivitySchema = z.object({
53
53
  feel: z.number().nullable().optional(),
54
54
  description: z.string().nullable().optional(),
55
55
  trainer: z.boolean().nullable().optional(),
56
+ decoupling: z.number().nullable().optional(),
57
+ icu_efficiency_factor: z.number().nullable().optional(),
58
+ icu_power_hr: z.number().nullable().optional(),
59
+ icu_variability_index: z.number().nullable().optional(),
60
+ icu_pm_cp: z.number().nullable().optional(),
61
+ icu_rolling_ftp: z.number().nullable().optional(),
62
+ polarization_index: z.number().nullable().optional(),
63
+ icu_zone_times: z.array(z.object({ id: z.string(), secs: z.number() })).nullable().optional(),
64
+ icu_hr_zone_times: z.array(z.number()).nullable().optional(),
65
+ total_elevation_loss: z.number().nullable().optional(),
66
+ max_speed: z.number().nullable().optional(),
67
+ min_altitude: z.number().nullable().optional(),
68
+ max_altitude: z.number().nullable().optional(),
69
+ icu_joules: z.number().nullable().optional(),
70
+ icu_hrr: z.object({
71
+ hrr: z.number().nullable().optional(),
72
+ start_bpm: z.number().nullable().optional(),
73
+ end_bpm: z.number().nullable().optional(),
74
+ }).nullable().optional(),
75
+ strain_score: z.number().nullable().optional(),
76
+ hr_load: z.number().nullable().optional(),
77
+ power_load: z.number().nullable().optional(),
78
+ gear: z.object({
79
+ id: z.string().nullable().optional(),
80
+ name: z.string().nullable().optional(),
81
+ }).nullable().optional(),
82
+ device_name: z.string().nullable().optional(),
83
+ power_meter: z.string().nullable().optional(),
84
+ source: z.string().nullable().optional(),
85
+ compliance: z.number().nullable().optional(),
86
+ icu_chat_id: z.number().nullable().optional(),
56
87
  }).passthrough();
57
88
  export const WellnessSchema = z.object({
58
89
  id: z.string().optional(),
@@ -77,6 +108,14 @@ export const WellnessSchema = z.object({
77
108
  bodyFat: z.number().nullable().optional(),
78
109
  spO2: z.number().nullable().optional(),
79
110
  comments: z.string().nullable().optional(),
111
+ rampRate: z.number().nullable().optional(),
112
+ avgSleepingHR: z.number().nullable().optional(),
113
+ sportInfo: z.array(z.object({
114
+ type: z.string().optional(),
115
+ eftp: z.number().nullable().optional(),
116
+ wPrime: z.number().nullable().optional(),
117
+ pMax: z.number().nullable().optional(),
118
+ })).nullable().optional(),
80
119
  }).passthrough();
81
120
  export const EventSchema = z.object({
82
121
  id: z.union([z.string(), z.number()]),
@@ -88,6 +127,11 @@ export const EventSchema = z.object({
88
127
  name: z.string().nullable().optional(),
89
128
  description: z.string().nullable().optional(),
90
129
  color: z.string().nullable().optional(),
130
+ type: z.string().nullable().optional(),
131
+ moving_time: z.number().nullable().optional(),
132
+ icu_training_load: z.number().nullable().optional(),
133
+ icu_intensity: z.number().nullable().optional(),
134
+ paired_activity_id: z.string().nullable().optional(),
91
135
  }).passthrough();
92
136
  export const IntervalSchema = z.object({
93
137
  icu_intervals: z.array(z.record(z.unknown())).nullable().optional(),
@@ -117,6 +161,10 @@ export const SportSettingsSchema = z.object({
117
161
  hr_zone_names: z.array(z.string()).nullable().optional(),
118
162
  pace_zones: z.array(z.number()).nullable().optional(),
119
163
  pace_zone_names: z.array(z.string()).nullable().optional(),
164
+ w_prime: z.number().nullable().optional(),
165
+ sweet_spot_min: z.number().nullable().optional(),
166
+ sweet_spot_max: z.number().nullable().optional(),
167
+ best_effort_distances: z.array(z.number()).nullable().optional(),
120
168
  }).passthrough();
121
169
  export const WorkoutSchema = z.object({
122
170
  id: z.union([z.string(), z.number()]).optional(),
@@ -124,6 +172,9 @@ export const WorkoutSchema = z.object({
124
172
  description: z.string().nullable().optional(),
125
173
  type: z.string().nullable().optional(),
126
174
  updated: z.string().nullable().optional(),
175
+ moving_time: z.number().nullable().optional(),
176
+ icu_training_load: z.number().nullable().optional(),
177
+ joules: z.number().nullable().optional(),
127
178
  }).passthrough();
128
179
  // ---- API methods ---- //
129
180
  export async function getActivities(config, params) {
@@ -154,6 +205,20 @@ export async function getActivityMessages(config, activityId) {
154
205
  export async function addActivityMessage(config, activityId, content) {
155
206
  await mutate("POST", `/activity/${activityId}/messages`, config, { content });
156
207
  }
208
+ // Intervals.icu has no endpoint to edit a message's content in place — only
209
+ // delete and re-add. Callers wanting an "edit" should use updateActivityMessage,
210
+ // which does both and leaves the old message showing as deleted.
211
+ export async function deleteActivityMessage(config, activityId, messageId) {
212
+ const activity = await getActivityDetails(config, activityId);
213
+ const chatId = activity.icu_chat_id;
214
+ if (chatId == null)
215
+ throw new Error(`Activity ${activityId} has no chat/messages.`);
216
+ await mutate("DELETE", `/chats/${chatId}/messages/${messageId}`, config);
217
+ }
218
+ export async function updateActivityMessage(config, activityId, messageId, content) {
219
+ await deleteActivityMessage(config, activityId, messageId);
220
+ await addActivityMessage(config, activityId, content);
221
+ }
157
222
  export async function getWellness(config, params) {
158
223
  const data = await request(`/athlete/${config.athleteId}/wellness`, config, { oldest: params.startDate, newest: params.endDate });
159
224
  if (Array.isArray(data)) {
@@ -273,6 +338,10 @@ export const AthleteFitnessSchema = z.object({
273
338
  eftp: z.number().nullable().optional(),
274
339
  eftpPerKg: z.number().nullable().optional(),
275
340
  weight: z.number().nullable().optional(),
341
+ count: z.number().nullable().optional(),
342
+ moving_time: z.number().nullable().optional(),
343
+ calories: z.number().nullable().optional(),
344
+ distance: z.number().nullable().optional(),
276
345
  }).passthrough();
277
346
  export async function getAthleteFitness(config, params) {
278
347
  const data = await request(`/athlete/${config.athleteId}/athlete-summary.json`, config, { start: params.startDate, end: params.endDate });
package/dist/format.js CHANGED
@@ -3,6 +3,13 @@ function n(v, unit = "") {
3
3
  return "N/A";
4
4
  return `${v}${unit}`;
5
5
  }
6
+ function fmtDuration(secs) {
7
+ if (secs == null)
8
+ return "N/A";
9
+ const h = Math.floor(secs / 3600);
10
+ const m = Math.round((secs % 3600) / 60);
11
+ return h > 0 ? `${h}h${m}m` : `${m}m`;
12
+ }
6
13
  export function formatActivity(a) {
7
14
  const startTime = a.start_date_local
8
15
  ? new Date(a.start_date_local).toLocaleString()
@@ -11,37 +18,44 @@ export function formatActivity(a) {
11
18
  `**${a.name ?? "Unnamed"}** (${a.id})`,
12
19
  `Type: ${n(a.type)} | Date: ${startTime}`,
13
20
  `Distance: ${n(a.distance, " m")} | Duration: ${n(a.elapsed_time, " s")} | Moving: ${n(a.moving_time, " s")}`,
14
- `Elevation: ${n(a.total_elevation_gain, " m")}`,
21
+ `Elevation: +${n(a.total_elevation_gain, " m")} / -${n(a.total_elevation_loss, " m")} | Altitude: ${n(a.min_altitude, " m")}-${n(a.max_altitude, " m")}`,
15
22
  "",
16
23
  "Power:",
17
24
  ` Avg: ${n(a.icu_average_watts, " W")} | Weighted Avg: ${n(a.icu_weighted_avg_watts, " W")} | FTP: ${n(a.icu_ftp, " W")}`,
18
- ` Training Load: ${n(a.icu_training_load)} | Intensity: ${n(a.icu_intensity)}`,
25
+ ` Training Load: ${n(a.icu_training_load)} | Intensity: ${n(a.icu_intensity)} | VI: ${n(a.icu_variability_index)}`,
26
+ ` Critical Power: ${n(a.icu_pm_cp, " W")} | Rolling FTP: ${n(a.icu_rolling_ftp, " W")} | Energy: ${a.icu_joules != null ? `${Math.round(a.icu_joules / 1000)} kJ` : "N/A"}`,
19
27
  "",
20
28
  "Heart Rate:",
21
29
  ` Avg: ${n(a.average_heartrate, " bpm")} | Max: ${n(a.max_heartrate, " bpm")}`,
22
- "",
23
- "Other:",
24
- ` Cadence: ${n(a.average_cadence, " rpm")} | Calories: ${n(a.calories)} | Speed: ${n(a.average_speed, " m/s")}`,
25
- ` Temp: ${n(a.average_temp, "°C")} | Trainer: ${a.trainer ? "Yes" : "No"}`,
26
- ` RPE: ${n(a.icu_rpe ?? a.perceived_exertion)}/10 | Feel: ${n(a.feel)}/5`,
27
- "",
28
- "Fitness:",
29
- ` CTL: ${n(a.icu_ctl)} | ATL: ${n(a.icu_atl)} | TRIMP: ${n(a.trimp)}`,
30
+ ` Decoupling: ${n(a.decoupling, "%")} | Efficiency Factor: ${n(a.icu_efficiency_factor)} | Pw:Hr: ${n(a.icu_power_hr)}`,
30
31
  ];
32
+ if (a.icu_hrr?.hrr != null) {
33
+ lines.push(` HR Recovery: -${n(a.icu_hrr.hrr, " bpm")} (${n(a.icu_hrr.start_bpm)} → ${n(a.icu_hrr.end_bpm)} bpm)`);
34
+ }
35
+ if (a.icu_zone_times?.length || a.icu_hr_zone_times?.length) {
36
+ lines.push("", "Zones:");
37
+ if (a.icu_zone_times?.length) {
38
+ lines.push(` Power: ${a.icu_zone_times.map((z) => `${z.id} ${fmtDuration(z.secs)}`).join(" | ")}`);
39
+ }
40
+ if (a.icu_hr_zone_times?.length) {
41
+ lines.push(` HR: ${a.icu_hr_zone_times.map((secs, i) => `Z${i + 1} ${fmtDuration(secs)}`).join(" | ")}`);
42
+ }
43
+ }
44
+ lines.push("", "Other:", ` Cadence: ${n(a.average_cadence, " rpm")} | Calories: ${n(a.calories)} | Speed: ${n(a.average_speed, " m/s")} (max ${n(a.max_speed, " m/s")})`, ` Temp: ${n(a.average_temp, "°C")} | Trainer: ${a.trainer ? "Yes" : "No"}`, ` RPE: ${n(a.icu_rpe ?? a.perceived_exertion)}/10 | Feel: ${n(a.feel)}/5`, "", "Fitness:", ` CTL: ${n(a.icu_ctl)} | ATL: ${n(a.icu_atl)} | TRIMP: ${n(a.trimp)} | Polarization Index: ${n(a.polarization_index)}`, ` Power Load: ${n(a.power_load)} | HR Load: ${n(a.hr_load)} | Strain: ${n(a.strain_score)}`, "", "Equipment:", ` Gear: ${n(a.gear?.name)} | Device: ${n(a.device_name)} | Power Meter: ${n(a.power_meter)}`, ` Source: ${n(a.source)} | Compliance: ${a.compliance != null ? `${a.compliance}%` : "N/A"}`);
31
45
  if (a.description)
32
46
  lines.push("", `Description: ${a.description}`);
33
47
  return lines.join("\n");
34
48
  }
35
49
  export function formatWellness(date, w) {
36
50
  const sleepHours = w.sleepSecs != null ? (w.sleepSecs / 3600).toFixed(1) + " h" : "N/A";
37
- return [
51
+ const lines = [
38
52
  `**${date}**`,
39
53
  "",
40
54
  "Training:",
41
- ` CTL: ${n(w.ctl)} | ATL: ${n(w.atl)}`,
55
+ ` CTL: ${n(w.ctl)} | ATL: ${n(w.atl)} | Ramp Rate: ${n(w.rampRate)}`,
42
56
  "",
43
57
  "Vitals:",
44
- ` Weight: ${n(w.weight, " kg")} | Resting HR: ${n(w.restingHR, " bpm")}`,
58
+ ` Weight: ${n(w.weight, " kg")} | Resting HR: ${n(w.restingHR, " bpm")} | Avg Sleeping HR: ${n(w.avgSleepingHR, " bpm")}`,
45
59
  ` HRV: ${n(w.hrv)} | HRV SDNN: ${n(w.hrvSDNN)}`,
46
60
  ` SpO2: ${n(w.spO2, "%")} | VO2max: ${n(w.vo2max)} | Body Fat: ${n(w.bodyFat, "%")}`,
47
61
  "",
@@ -55,11 +69,13 @@ export function formatWellness(date, w) {
55
69
  "",
56
70
  "Nutrition:",
57
71
  ` Calories: ${n(w.kcalConsumed, " kcal")} | Steps: ${n(w.steps)}`,
58
- w.comments ? `\nComments: ${w.comments}` : "",
59
- ]
60
- .filter((l) => l !== undefined)
61
- .join("\n")
62
- .trimEnd();
72
+ ];
73
+ if (w.sportInfo?.length) {
74
+ lines.push("", "Sport Fitness (eFTP / W' / pMax):", ...w.sportInfo.map((s) => ` ${s.type ?? "Unknown"}: ${n(s.eftp, " W")} / ${n(s.wPrime, " J")} / ${n(s.pMax, " W")}`));
75
+ }
76
+ if (w.comments)
77
+ lines.push("", `Comments: ${w.comments}`);
78
+ return lines.join("\n").trimEnd();
63
79
  }
64
80
  export function formatEvent(e) {
65
81
  const category = e.category ?? "";
@@ -74,14 +90,19 @@ export function formatEvent(e) {
74
90
  const dateLabel = e.end_date_local && e.end_date_local !== e.start_date_local
75
91
  ? `${start} to ${e.end_date_local}`
76
92
  : start;
77
- return [
93
+ const lines = [
78
94
  `**${e.name ?? "Unnamed"}** (${e.id})`,
79
95
  `Type: ${type} | Date: ${dateLabel}`,
80
96
  e.category ? `Category: ${e.category}` : "",
81
- e.description ? `Description: ${e.description}` : "",
82
- ]
83
- .filter(Boolean)
84
- .join("\n");
97
+ ];
98
+ if (e.type || e.moving_time != null || e.icu_training_load != null || e.icu_intensity != null) {
99
+ lines.push(`Sport: ${n(e.type)} | Planned Duration: ${e.moving_time != null ? fmtDuration(e.moving_time) : "N/A"} | Planned Load: ${n(e.icu_training_load)} | Intensity: ${n(e.icu_intensity)}`);
100
+ }
101
+ if (e.paired_activity_id)
102
+ lines.push(`Completed as: ${e.paired_activity_id}`);
103
+ if (e.description)
104
+ lines.push(`Description: ${e.description}`);
105
+ return lines.filter(Boolean).join("\n");
85
106
  }
86
107
  export function formatMessage(m) {
87
108
  const when = m.created ? new Date(m.created).toLocaleString() : "Unknown time";
@@ -132,6 +153,13 @@ export function formatSportZones(s) {
132
153
  const range = z.to != null ? `${z.from}-${z.to} m/s` : `${z.from}+ m/s`;
133
154
  lines.push(` ${z.name}: ${range}`);
134
155
  }
156
+ lines.push("");
157
+ }
158
+ if (s.w_prime != null || s.sweet_spot_min != null) {
159
+ lines.push(`Power Model: W' ${n(s.w_prime, " J")} | Sweet Spot ${n(s.sweet_spot_min, "%")}-${n(s.sweet_spot_max, "%")}`);
160
+ }
161
+ if (s.best_effort_distances?.length) {
162
+ lines.push(`Best Effort Distances: ${s.best_effort_distances.join(", ")} m`);
135
163
  }
136
164
  return lines.join("\n").trimEnd();
137
165
  }
@@ -146,10 +174,13 @@ export function formatIntervalRow(interval, idx) {
146
174
  const avgHr = interval["average_heartrate"] ?? 0;
147
175
  const maxHr = interval["max_heartrate"] ?? 0;
148
176
  const tl = interval["training_load"] ?? 0;
177
+ const intensity = interval["intensity"];
178
+ const vi = interval["w5s_variability"];
179
+ const decoupling = interval["decoupling"];
149
180
  return [
150
181
  `[${idx}] ${label} (${type})`,
151
182
  ` Duration: ${elapsed}s | Distance: ${distance}m`,
152
- ` Power: avg ${avgW}W, w.avg ${wAvg}W, max ${maxW}W | TL: ${tl}`,
153
- ` HR: avg ${avgHr}, max ${maxHr} bpm`,
183
+ ` Power: avg ${avgW}W, w.avg ${wAvg}W, max ${maxW}W | TL: ${tl} | Intensity: ${n(intensity)} | VI: ${n(vi)}`,
184
+ ` HR: avg ${avgHr}, max ${maxHr} bpm | Decoupling: ${n(decoupling, "%")}`,
154
185
  ].join("\n");
155
186
  }
package/dist/index.js CHANGED
@@ -4,7 +4,7 @@ import { Server } from "@modelcontextprotocol/sdk/server/index.js";
4
4
  import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
5
5
  import { CallToolRequestSchema, ListToolsRequestSchema, } from "@modelcontextprotocol/sdk/types.js";
6
6
  import { z } from "zod";
7
- import { getActivities, getActivityDetails, getActivityIntervals, getWellness, getEvents, getEventById, getNotesByDate, createEvent, updateEvent, deleteEvent, getAthleteProfile, getAthleteZones, getAthleteSummary, getWellnessDay, updateWellness, getActivityStreams, getActivityPowerCurves, listWorkouts, createWorkout, bulkCreateEvents, bulkDeleteEvents, getAthleteFitness, getActivityMessages, addActivityMessage, } from "./client.js";
7
+ import { getActivities, getActivityDetails, getActivityIntervals, getWellness, getEvents, getEventById, getNotesByDate, createEvent, updateEvent, deleteEvent, getAthleteProfile, getAthleteZones, getAthleteSummary, getWellnessDay, updateWellness, getActivityStreams, getActivityPowerCurves, listWorkouts, createWorkout, bulkCreateEvents, bulkDeleteEvents, getAthleteFitness, getActivityMessages, addActivityMessage, deleteActivityMessage, updateActivityMessage, } from "./client.js";
8
8
  import { formatActivity, formatWellness, formatEvent, formatIntervalRow, formatSportZones, formatMessage, } from "./format.js";
9
9
  function getConfig(args) {
10
10
  const apiKey = args["api_key"] ?? process.env.API_KEY ?? "";
@@ -309,6 +309,35 @@ const TOOLS = [
309
309
  },
310
310
  },
311
311
  },
312
+ {
313
+ name: "update_activity_message",
314
+ description: "Edit a comment/note on an activity. Intervals.icu has no API to edit message content in place, so this deletes the old message and posts a new one with the updated text — the old message will show as \"(deleted)\" and the edited one will appear as a new message at the current time. Use get_activity_messages to find the message_id.",
315
+ inputSchema: {
316
+ type: "object",
317
+ required: ["activity_id", "message_id", "content"],
318
+ properties: {
319
+ activity_id: { type: "string", description: "The activity ID" },
320
+ message_id: { type: "number", description: "ID of the message to edit (from get_activity_messages)" },
321
+ content: { type: "string", description: "New comment text" },
322
+ athlete_id: { type: "string", description: "Athlete ID (defaults to ATHLETE_ID env var)" },
323
+ api_key: { type: "string", description: "API key (defaults to API_KEY env var)" },
324
+ },
325
+ },
326
+ },
327
+ {
328
+ name: "delete_activity_message",
329
+ description: "Delete a comment/note from an activity's chat thread. The message is soft-deleted (shows as \"(deleted)\") rather than removed entirely. Use get_activity_messages to find the message_id.",
330
+ inputSchema: {
331
+ type: "object",
332
+ required: ["activity_id", "message_id"],
333
+ properties: {
334
+ activity_id: { type: "string", description: "The activity ID" },
335
+ message_id: { type: "number", description: "ID of the message to delete (from get_activity_messages)" },
336
+ athlete_id: { type: "string", description: "Athlete ID (defaults to ATHLETE_ID env var)" },
337
+ api_key: { type: "string", description: "API key (defaults to API_KEY env var)" },
338
+ },
339
+ },
340
+ },
312
341
  {
313
342
  name: "list_workouts",
314
343
  description: "List all workouts in the athlete's workout library.",
@@ -608,6 +637,11 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
608
637
  `ATL (Fatigue): ${summary.fatigue ?? "N/A"}`,
609
638
  `TSB (Form): ${summary.form ?? "N/A"}`,
610
639
  `Ramp Rate: ${summary.rampRate ?? "N/A"}`,
640
+ "",
641
+ "## Last 7 Days",
642
+ "",
643
+ `Activities: ${summary.count ?? "N/A"} | Training Load: ${summary.training_load ?? "N/A"}`,
644
+ `Moving Time: ${summary.moving_time != null ? `${(summary.moving_time / 3600).toFixed(1)}h` : "N/A"} | Distance: ${summary.distance != null ? `${(summary.distance / 1000).toFixed(1)} km` : "N/A"} | Calories: ${summary.calories ?? "N/A"}`,
611
645
  ].join("\n");
612
646
  return { content: [{ type: "text", text }] };
613
647
  }
@@ -667,12 +701,35 @@ server.setRequestHandler(CallToolRequestSchema, async (request) => {
667
701
  await addActivityMessage(config, activityId, content);
668
702
  return { content: [{ type: "text", text: `Comment added to activity ${activityId}.` }] };
669
703
  }
704
+ case "update_activity_message": {
705
+ const activityId = z.string().parse(args["activity_id"]);
706
+ const messageId = z.number().parse(args["message_id"]);
707
+ const content = z.string().parse(args["content"]);
708
+ const config = getConfig(args);
709
+ await updateActivityMessage(config, activityId, messageId, content);
710
+ return { content: [{ type: "text", text: `Message ${messageId} on activity ${activityId} replaced with: "${content}"` }] };
711
+ }
712
+ case "delete_activity_message": {
713
+ const activityId = z.string().parse(args["activity_id"]);
714
+ const messageId = z.number().parse(args["message_id"]);
715
+ const config = getConfig(args);
716
+ await deleteActivityMessage(config, activityId, messageId);
717
+ return { content: [{ type: "text", text: `Message ${messageId} deleted from activity ${activityId}.` }] };
718
+ }
670
719
  case "list_workouts": {
671
720
  const config = getConfig(args);
672
721
  const workouts = await listWorkouts(config);
673
722
  if (!workouts.length)
674
723
  return { content: [{ type: "text", text: "No workouts in library." }] };
675
- const text = workouts.map(w => [`**${w.name ?? "Unnamed"}** (${w.id})`, w.type ? `Type: ${w.type}` : "", w.description ? `${w.description}` : ""].filter(Boolean).join("\n")).join("\n\n---\n\n");
724
+ const text = workouts.map(w => {
725
+ const duration = w.moving_time != null ? `${Math.round(w.moving_time / 60)}min` : "N/A";
726
+ const kj = w.joules != null ? `${Math.round(w.joules / 1000)} kJ` : "N/A";
727
+ return [
728
+ `**${w.name ?? "Unnamed"}** (${w.id})`,
729
+ w.type ? `Type: ${w.type} | Duration: ${duration} | Load: ${w.icu_training_load ?? "N/A"} | Energy: ${kj}` : "",
730
+ w.description ? `${w.description}` : "",
731
+ ].filter(Boolean).join("\n");
732
+ }).join("\n\n---\n\n");
676
733
  return { content: [{ type: "text", text }] };
677
734
  }
678
735
  case "create_workout": {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "intervals-icu-mcp-server",
3
- "version": "0.2.0",
4
- "description": "MCP server for Intervals.icu — 24 tools for activities, wellness, calendar events, workouts and more",
3
+ "version": "0.3.0",
4
+ "description": "MCP server for Intervals.icu — 26 tools for activities, wellness, calendar events, workouts and more",
5
5
  "type": "module",
6
6
  "bin": {
7
7
  "intervals-icu-mcp": "dist/index.js"