intervals-icu-mcp-server 0.2.1 → 0.4.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
@@ -85,6 +85,20 @@ export declare const ActivitySchema: z.ZodObject<{
85
85
  power_meter: z.ZodOptional<z.ZodNullable<z.ZodString>>;
86
86
  source: z.ZodOptional<z.ZodNullable<z.ZodString>>;
87
87
  compliance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
88
+ icu_chat_id: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
89
+ coasting_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
90
+ ss_cp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
91
+ ss_w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
92
+ ss_p_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
93
+ icu_pm_ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
94
+ icu_w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
95
+ p_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
96
+ icu_max_wbal_depletion: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
97
+ icu_joules_above_ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
98
+ icu_weight: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
99
+ carbs_used: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
100
+ carbs_ingested: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
101
+ avg_lr_balance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
88
102
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
89
103
  id: z.ZodString;
90
104
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
@@ -167,6 +181,20 @@ export declare const ActivitySchema: z.ZodObject<{
167
181
  power_meter: z.ZodOptional<z.ZodNullable<z.ZodString>>;
168
182
  source: z.ZodOptional<z.ZodNullable<z.ZodString>>;
169
183
  compliance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
184
+ icu_chat_id: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
185
+ coasting_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
186
+ ss_cp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
187
+ ss_w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
188
+ ss_p_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
189
+ icu_pm_ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
190
+ icu_w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
191
+ p_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
192
+ icu_max_wbal_depletion: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
193
+ icu_joules_above_ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
194
+ icu_weight: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
195
+ carbs_used: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
196
+ carbs_ingested: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
197
+ avg_lr_balance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
170
198
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
171
199
  id: z.ZodString;
172
200
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
@@ -249,6 +277,20 @@ export declare const ActivitySchema: z.ZodObject<{
249
277
  power_meter: z.ZodOptional<z.ZodNullable<z.ZodString>>;
250
278
  source: z.ZodOptional<z.ZodNullable<z.ZodString>>;
251
279
  compliance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
280
+ icu_chat_id: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
281
+ coasting_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
282
+ ss_cp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
283
+ ss_w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
284
+ ss_p_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
285
+ icu_pm_ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
286
+ icu_w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
287
+ p_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
288
+ icu_max_wbal_depletion: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
289
+ icu_joules_above_ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
290
+ icu_weight: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
291
+ carbs_used: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
292
+ carbs_ingested: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
293
+ avg_lr_balance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
252
294
  }, z.ZodTypeAny, "passthrough">>;
253
295
  export type Activity = z.infer<typeof ActivitySchema>;
254
296
  export declare const WellnessSchema: z.ZodObject<{
@@ -274,6 +316,24 @@ export declare const WellnessSchema: z.ZodObject<{
274
316
  bodyFat: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
275
317
  spO2: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
276
318
  comments: z.ZodOptional<z.ZodNullable<z.ZodString>>;
319
+ rampRate: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
320
+ avgSleepingHR: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
321
+ sportInfo: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
322
+ type: z.ZodOptional<z.ZodString>;
323
+ eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
324
+ wPrime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
325
+ pMax: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
326
+ }, "strip", z.ZodTypeAny, {
327
+ type?: string | undefined;
328
+ eftp?: number | null | undefined;
329
+ wPrime?: number | null | undefined;
330
+ pMax?: number | null | undefined;
331
+ }, {
332
+ type?: string | undefined;
333
+ eftp?: number | null | undefined;
334
+ wPrime?: number | null | undefined;
335
+ pMax?: number | null | undefined;
336
+ }>, "many">>>;
277
337
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
278
338
  id: z.ZodOptional<z.ZodString>;
279
339
  ctl: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -297,6 +357,24 @@ export declare const WellnessSchema: z.ZodObject<{
297
357
  bodyFat: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
298
358
  spO2: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
299
359
  comments: z.ZodOptional<z.ZodNullable<z.ZodString>>;
360
+ rampRate: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
361
+ avgSleepingHR: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
362
+ sportInfo: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
363
+ type: z.ZodOptional<z.ZodString>;
364
+ eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
365
+ wPrime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
366
+ pMax: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
367
+ }, "strip", z.ZodTypeAny, {
368
+ type?: string | undefined;
369
+ eftp?: number | null | undefined;
370
+ wPrime?: number | null | undefined;
371
+ pMax?: number | null | undefined;
372
+ }, {
373
+ type?: string | undefined;
374
+ eftp?: number | null | undefined;
375
+ wPrime?: number | null | undefined;
376
+ pMax?: number | null | undefined;
377
+ }>, "many">>>;
300
378
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
301
379
  id: z.ZodOptional<z.ZodString>;
302
380
  ctl: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -320,6 +398,24 @@ export declare const WellnessSchema: z.ZodObject<{
320
398
  bodyFat: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
321
399
  spO2: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
322
400
  comments: z.ZodOptional<z.ZodNullable<z.ZodString>>;
401
+ rampRate: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
402
+ avgSleepingHR: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
403
+ sportInfo: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
404
+ type: z.ZodOptional<z.ZodString>;
405
+ eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
406
+ wPrime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
407
+ pMax: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
408
+ }, "strip", z.ZodTypeAny, {
409
+ type?: string | undefined;
410
+ eftp?: number | null | undefined;
411
+ wPrime?: number | null | undefined;
412
+ pMax?: number | null | undefined;
413
+ }, {
414
+ type?: string | undefined;
415
+ eftp?: number | null | undefined;
416
+ wPrime?: number | null | undefined;
417
+ pMax?: number | null | undefined;
418
+ }>, "many">>>;
323
419
  }, z.ZodTypeAny, "passthrough">>;
324
420
  export type Wellness = z.infer<typeof WellnessSchema>;
325
421
  export declare const EventSchema: z.ZodObject<{
@@ -332,6 +428,11 @@ export declare const EventSchema: z.ZodObject<{
332
428
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
333
429
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
334
430
  color: z.ZodOptional<z.ZodNullable<z.ZodString>>;
431
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
432
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
433
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
434
+ icu_intensity: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
435
+ paired_activity_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
335
436
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
336
437
  id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
337
438
  date: z.ZodOptional<z.ZodString>;
@@ -342,6 +443,11 @@ export declare const EventSchema: z.ZodObject<{
342
443
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
343
444
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
344
445
  color: z.ZodOptional<z.ZodNullable<z.ZodString>>;
446
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
447
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
448
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
449
+ icu_intensity: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
450
+ paired_activity_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
345
451
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
346
452
  id: z.ZodUnion<[z.ZodString, z.ZodNumber]>;
347
453
  date: z.ZodOptional<z.ZodString>;
@@ -352,6 +458,11 @@ export declare const EventSchema: z.ZodObject<{
352
458
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
353
459
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
354
460
  color: z.ZodOptional<z.ZodNullable<z.ZodString>>;
461
+ type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
462
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
463
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
464
+ icu_intensity: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
465
+ paired_activity_id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
355
466
  }, z.ZodTypeAny, "passthrough">>;
356
467
  export type Event = z.infer<typeof EventSchema>;
357
468
  export declare const IntervalSchema: z.ZodObject<{
@@ -423,6 +534,10 @@ export declare const SportSettingsSchema: z.ZodObject<{
423
534
  hr_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
424
535
  pace_zones: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
425
536
  pace_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
537
+ w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
538
+ sweet_spot_min: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
539
+ sweet_spot_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
540
+ best_effort_distances: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
426
541
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
427
542
  types: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
428
543
  ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -435,6 +550,10 @@ export declare const SportSettingsSchema: z.ZodObject<{
435
550
  hr_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
436
551
  pace_zones: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
437
552
  pace_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
553
+ w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
554
+ sweet_spot_min: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
555
+ sweet_spot_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
556
+ best_effort_distances: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
438
557
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
439
558
  types: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
440
559
  ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -447,6 +566,10 @@ export declare const SportSettingsSchema: z.ZodObject<{
447
566
  hr_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
448
567
  pace_zones: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
449
568
  pace_zone_names: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodString, "many">>>;
569
+ w_prime: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
570
+ sweet_spot_min: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
571
+ sweet_spot_max: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
572
+ best_effort_distances: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
450
573
  }, z.ZodTypeAny, "passthrough">>;
451
574
  export type SportSettings = z.infer<typeof SportSettingsSchema>;
452
575
  export declare const WorkoutSchema: z.ZodObject<{
@@ -455,18 +578,27 @@ export declare const WorkoutSchema: z.ZodObject<{
455
578
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
456
579
  type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
457
580
  updated: z.ZodOptional<z.ZodNullable<z.ZodString>>;
581
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
582
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
583
+ joules: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
458
584
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
459
585
  id: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
460
586
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
461
587
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
462
588
  type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
463
589
  updated: z.ZodOptional<z.ZodNullable<z.ZodString>>;
590
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
591
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
592
+ joules: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
464
593
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
465
594
  id: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodNumber]>>;
466
595
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
467
596
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
468
597
  type: z.ZodOptional<z.ZodNullable<z.ZodString>>;
469
598
  updated: z.ZodOptional<z.ZodNullable<z.ZodString>>;
599
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
600
+ icu_training_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
601
+ joules: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
470
602
  }, z.ZodTypeAny, "passthrough">>;
471
603
  export type Workout = z.infer<typeof WorkoutSchema>;
472
604
  export interface WorkoutInput {
@@ -530,6 +662,8 @@ export declare const MessageSchema: z.ZodObject<{
530
662
  export type Message = z.infer<typeof MessageSchema>;
531
663
  export declare function getActivityMessages(config: ClientConfig, activityId: string): Promise<Message[]>;
532
664
  export declare function addActivityMessage(config: ClientConfig, activityId: string, content: string): Promise<void>;
665
+ export declare function deleteActivityMessage(config: ClientConfig, activityId: string, messageId: number): Promise<void>;
666
+ export declare function updateActivityMessage(config: ClientConfig, activityId: string, messageId: number, content: string): Promise<void>;
533
667
  export declare function getWellness(config: ClientConfig, params: {
534
668
  startDate: string;
535
669
  endDate: string;
@@ -564,6 +698,10 @@ export declare const AthleteFitnessSchema: z.ZodObject<{
564
698
  eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
565
699
  eftpPerKg: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
566
700
  weight: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
701
+ count: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
702
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
703
+ calories: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
704
+ distance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
567
705
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
568
706
  date: z.ZodOptional<z.ZodString>;
569
707
  fitness: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -574,6 +712,10 @@ export declare const AthleteFitnessSchema: z.ZodObject<{
574
712
  eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
575
713
  eftpPerKg: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
576
714
  weight: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
715
+ count: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
716
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
717
+ calories: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
718
+ distance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
577
719
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
578
720
  date: z.ZodOptional<z.ZodString>;
579
721
  fitness: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
@@ -584,6 +726,10 @@ export declare const AthleteFitnessSchema: z.ZodObject<{
584
726
  eftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
585
727
  eftpPerKg: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
586
728
  weight: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
729
+ count: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
730
+ moving_time: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
731
+ calories: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
732
+ distance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
587
733
  }, z.ZodTypeAny, "passthrough">>;
588
734
  export type AthleteFitness = z.infer<typeof AthleteFitnessSchema>;
589
735
  export declare function getAthleteFitness(config: ClientConfig, params: {
package/dist/client.js CHANGED
@@ -83,6 +83,20 @@ export const ActivitySchema = z.object({
83
83
  power_meter: z.string().nullable().optional(),
84
84
  source: z.string().nullable().optional(),
85
85
  compliance: z.number().nullable().optional(),
86
+ icu_chat_id: z.number().nullable().optional(),
87
+ coasting_time: z.number().nullable().optional(),
88
+ ss_cp: z.number().nullable().optional(),
89
+ ss_w_prime: z.number().nullable().optional(),
90
+ ss_p_max: z.number().nullable().optional(),
91
+ icu_pm_ftp: z.number().nullable().optional(),
92
+ icu_w_prime: z.number().nullable().optional(),
93
+ p_max: z.number().nullable().optional(),
94
+ icu_max_wbal_depletion: z.number().nullable().optional(),
95
+ icu_joules_above_ftp: z.number().nullable().optional(),
96
+ icu_weight: z.number().nullable().optional(),
97
+ carbs_used: z.number().nullable().optional(),
98
+ carbs_ingested: z.number().nullable().optional(),
99
+ avg_lr_balance: z.number().nullable().optional(),
86
100
  }).passthrough();
87
101
  export const WellnessSchema = z.object({
88
102
  id: z.string().optional(),
@@ -107,6 +121,14 @@ export const WellnessSchema = z.object({
107
121
  bodyFat: z.number().nullable().optional(),
108
122
  spO2: z.number().nullable().optional(),
109
123
  comments: z.string().nullable().optional(),
124
+ rampRate: z.number().nullable().optional(),
125
+ avgSleepingHR: z.number().nullable().optional(),
126
+ sportInfo: z.array(z.object({
127
+ type: z.string().optional(),
128
+ eftp: z.number().nullable().optional(),
129
+ wPrime: z.number().nullable().optional(),
130
+ pMax: z.number().nullable().optional(),
131
+ })).nullable().optional(),
110
132
  }).passthrough();
111
133
  export const EventSchema = z.object({
112
134
  id: z.union([z.string(), z.number()]),
@@ -118,6 +140,11 @@ export const EventSchema = z.object({
118
140
  name: z.string().nullable().optional(),
119
141
  description: z.string().nullable().optional(),
120
142
  color: z.string().nullable().optional(),
143
+ type: z.string().nullable().optional(),
144
+ moving_time: z.number().nullable().optional(),
145
+ icu_training_load: z.number().nullable().optional(),
146
+ icu_intensity: z.number().nullable().optional(),
147
+ paired_activity_id: z.string().nullable().optional(),
121
148
  }).passthrough();
122
149
  export const IntervalSchema = z.object({
123
150
  icu_intervals: z.array(z.record(z.unknown())).nullable().optional(),
@@ -147,6 +174,10 @@ export const SportSettingsSchema = z.object({
147
174
  hr_zone_names: z.array(z.string()).nullable().optional(),
148
175
  pace_zones: z.array(z.number()).nullable().optional(),
149
176
  pace_zone_names: z.array(z.string()).nullable().optional(),
177
+ w_prime: z.number().nullable().optional(),
178
+ sweet_spot_min: z.number().nullable().optional(),
179
+ sweet_spot_max: z.number().nullable().optional(),
180
+ best_effort_distances: z.array(z.number()).nullable().optional(),
150
181
  }).passthrough();
151
182
  export const WorkoutSchema = z.object({
152
183
  id: z.union([z.string(), z.number()]).optional(),
@@ -154,6 +185,9 @@ export const WorkoutSchema = z.object({
154
185
  description: z.string().nullable().optional(),
155
186
  type: z.string().nullable().optional(),
156
187
  updated: z.string().nullable().optional(),
188
+ moving_time: z.number().nullable().optional(),
189
+ icu_training_load: z.number().nullable().optional(),
190
+ joules: z.number().nullable().optional(),
157
191
  }).passthrough();
158
192
  // ---- API methods ---- //
159
193
  export async function getActivities(config, params) {
@@ -184,6 +218,20 @@ export async function getActivityMessages(config, activityId) {
184
218
  export async function addActivityMessage(config, activityId, content) {
185
219
  await mutate("POST", `/activity/${activityId}/messages`, config, { content });
186
220
  }
221
+ // Intervals.icu has no endpoint to edit a message's content in place — only
222
+ // delete and re-add. Callers wanting an "edit" should use updateActivityMessage,
223
+ // which does both and leaves the old message showing as deleted.
224
+ export async function deleteActivityMessage(config, activityId, messageId) {
225
+ const activity = await getActivityDetails(config, activityId);
226
+ const chatId = activity.icu_chat_id;
227
+ if (chatId == null)
228
+ throw new Error(`Activity ${activityId} has no chat/messages.`);
229
+ await mutate("DELETE", `/chats/${chatId}/messages/${messageId}`, config);
230
+ }
231
+ export async function updateActivityMessage(config, activityId, messageId, content) {
232
+ await deleteActivityMessage(config, activityId, messageId);
233
+ await addActivityMessage(config, activityId, content);
234
+ }
187
235
  export async function getWellness(config, params) {
188
236
  const data = await request(`/athlete/${config.athleteId}/wellness`, config, { oldest: params.startDate, newest: params.endDate });
189
237
  if (Array.isArray(data)) {
@@ -303,6 +351,10 @@ export const AthleteFitnessSchema = z.object({
303
351
  eftp: z.number().nullable().optional(),
304
352
  eftpPerKg: z.number().nullable().optional(),
305
353
  weight: z.number().nullable().optional(),
354
+ count: z.number().nullable().optional(),
355
+ moving_time: z.number().nullable().optional(),
356
+ calories: z.number().nullable().optional(),
357
+ distance: z.number().nullable().optional(),
306
358
  }).passthrough();
307
359
  export async function getAthleteFitness(config, params) {
308
360
  const data = await request(`/athlete/${config.athleteId}/athlete-summary.json`, config, { start: params.startDate, end: params.endDate });
package/dist/format.js CHANGED
@@ -23,7 +23,9 @@ export function formatActivity(a) {
23
23
  "Power:",
24
24
  ` Avg: ${n(a.icu_average_watts, " W")} | Weighted Avg: ${n(a.icu_weighted_avg_watts, " W")} | FTP: ${n(a.icu_ftp, " W")}`,
25
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"}`,
26
+ ` Critical Power: ${n(a.icu_pm_cp, " W")} | Rolling FTP: ${n(a.icu_rolling_ftp, " W")} | Activity eFTP: ${n(a.icu_pm_ftp, " W")}`,
27
+ ` Energy: ${a.icu_joules != null ? `${Math.round(a.icu_joules / 1000)} kJ` : "N/A"} | Above FTP: ${a.icu_joules_above_ftp != null ? `${Math.round(a.icu_joules_above_ftp / 1000)} kJ` : "N/A"}`,
28
+ ` W': ${n(a.icu_w_prime, " J")} | Pmax: ${n(a.p_max, " W")} | W'bal Drop: ${a.icu_max_wbal_depletion != null ? `${(a.icu_max_wbal_depletion / 1000).toFixed(1)} kJ` : "N/A"}`,
27
29
  "",
28
30
  "Heart Rate:",
29
31
  ` Avg: ${n(a.average_heartrate, " bpm")} | Max: ${n(a.max_heartrate, " bpm")}`,
@@ -41,21 +43,21 @@ export function formatActivity(a) {
41
43
  lines.push(` HR: ${a.icu_hr_zone_times.map((secs, i) => `Z${i + 1} ${fmtDuration(secs)}`).join(" | ")}`);
42
44
  }
43
45
  }
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"}`);
46
+ 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"} | Coasting: ${fmtDuration(a.coasting_time)}`, ` RPE: ${n(a.icu_rpe ?? a.perceived_exertion)}/10 | Feel: ${n(a.feel)}/5 | S-RPE: ${n(a.session_rpe)}`, ` L/R Balance: ${a.avg_lr_balance != null ? `${(100 - a.avg_lr_balance).toFixed(0)}/${a.avg_lr_balance.toFixed(0)}` : "N/A"}`, "", "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)}`, ` SS CP: ${n(a.ss_cp, " W")} | SS W': ${n(a.ss_w_prime)} | SS Pmax: ${n(a.ss_p_max)}`, ` Weight: ${n(a.icu_weight, " kg")} | CHO Used: ${n(a.carbs_used, " g")} | CHO In: ${n(a.carbs_ingested, " g")}`, "", "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"}`);
45
47
  if (a.description)
46
48
  lines.push("", `Description: ${a.description}`);
47
49
  return lines.join("\n");
48
50
  }
49
51
  export function formatWellness(date, w) {
50
52
  const sleepHours = w.sleepSecs != null ? (w.sleepSecs / 3600).toFixed(1) + " h" : "N/A";
51
- return [
53
+ const lines = [
52
54
  `**${date}**`,
53
55
  "",
54
56
  "Training:",
55
- ` CTL: ${n(w.ctl)} | ATL: ${n(w.atl)}`,
57
+ ` CTL: ${n(w.ctl)} | ATL: ${n(w.atl)} | Ramp Rate: ${n(w.rampRate)}`,
56
58
  "",
57
59
  "Vitals:",
58
- ` Weight: ${n(w.weight, " kg")} | Resting HR: ${n(w.restingHR, " bpm")}`,
60
+ ` Weight: ${n(w.weight, " kg")} | Resting HR: ${n(w.restingHR, " bpm")} | Avg Sleeping HR: ${n(w.avgSleepingHR, " bpm")}`,
59
61
  ` HRV: ${n(w.hrv)} | HRV SDNN: ${n(w.hrvSDNN)}`,
60
62
  ` SpO2: ${n(w.spO2, "%")} | VO2max: ${n(w.vo2max)} | Body Fat: ${n(w.bodyFat, "%")}`,
61
63
  "",
@@ -69,11 +71,13 @@ export function formatWellness(date, w) {
69
71
  "",
70
72
  "Nutrition:",
71
73
  ` Calories: ${n(w.kcalConsumed, " kcal")} | Steps: ${n(w.steps)}`,
72
- w.comments ? `\nComments: ${w.comments}` : "",
73
- ]
74
- .filter((l) => l !== undefined)
75
- .join("\n")
76
- .trimEnd();
74
+ ];
75
+ if (w.sportInfo?.length) {
76
+ 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")}`));
77
+ }
78
+ if (w.comments)
79
+ lines.push("", `Comments: ${w.comments}`);
80
+ return lines.join("\n").trimEnd();
77
81
  }
78
82
  export function formatEvent(e) {
79
83
  const category = e.category ?? "";
@@ -88,14 +92,19 @@ export function formatEvent(e) {
88
92
  const dateLabel = e.end_date_local && e.end_date_local !== e.start_date_local
89
93
  ? `${start} to ${e.end_date_local}`
90
94
  : start;
91
- return [
95
+ const lines = [
92
96
  `**${e.name ?? "Unnamed"}** (${e.id})`,
93
97
  `Type: ${type} | Date: ${dateLabel}`,
94
98
  e.category ? `Category: ${e.category}` : "",
95
- e.description ? `Description: ${e.description}` : "",
96
- ]
97
- .filter(Boolean)
98
- .join("\n");
99
+ ];
100
+ if (e.type || e.moving_time != null || e.icu_training_load != null || e.icu_intensity != null) {
101
+ 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)}`);
102
+ }
103
+ if (e.paired_activity_id)
104
+ lines.push(`Completed as: ${e.paired_activity_id}`);
105
+ if (e.description)
106
+ lines.push(`Description: ${e.description}`);
107
+ return lines.filter(Boolean).join("\n");
99
108
  }
100
109
  export function formatMessage(m) {
101
110
  const when = m.created ? new Date(m.created).toLocaleString() : "Unknown time";
@@ -146,6 +155,13 @@ export function formatSportZones(s) {
146
155
  const range = z.to != null ? `${z.from}-${z.to} m/s` : `${z.from}+ m/s`;
147
156
  lines.push(` ${z.name}: ${range}`);
148
157
  }
158
+ lines.push("");
159
+ }
160
+ if (s.w_prime != null || s.sweet_spot_min != null) {
161
+ lines.push(`Power Model: W' ${n(s.w_prime, " J")} | Sweet Spot ${n(s.sweet_spot_min, "%")}-${n(s.sweet_spot_max, "%")}`);
162
+ }
163
+ if (s.best_effort_distances?.length) {
164
+ lines.push(`Best Effort Distances: ${s.best_effort_distances.join(", ")} m`);
149
165
  }
150
166
  return lines.join("\n").trimEnd();
151
167
  }
@@ -160,10 +176,13 @@ export function formatIntervalRow(interval, idx) {
160
176
  const avgHr = interval["average_heartrate"] ?? 0;
161
177
  const maxHr = interval["max_heartrate"] ?? 0;
162
178
  const tl = interval["training_load"] ?? 0;
179
+ const intensity = interval["intensity"];
180
+ const vi = interval["w5s_variability"];
181
+ const decoupling = interval["decoupling"];
163
182
  return [
164
183
  `[${idx}] ${label} (${type})`,
165
184
  ` Duration: ${elapsed}s | Distance: ${distance}m`,
166
- ` Power: avg ${avgW}W, w.avg ${wAvg}W, max ${maxW}W | TL: ${tl}`,
167
- ` HR: avg ${avgHr}, max ${maxHr} bpm`,
185
+ ` Power: avg ${avgW}W, w.avg ${wAvg}W, max ${maxW}W | TL: ${tl} | Intensity: ${n(intensity)} | VI: ${n(vi)}`,
186
+ ` HR: avg ${avgHr}, max ${maxHr} bpm | Decoupling: ${n(decoupling, "%")}`,
168
187
  ].join("\n");
169
188
  }
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.1",
4
- "description": "MCP server for Intervals.icu — 24 tools for activities, wellness, calendar events, workouts and more",
3
+ "version": "0.4.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"