intervals-icu-mcp-server 0.2.0 → 0.2.1

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,59 @@ 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>>;
35
88
  }, "passthrough", z.ZodTypeAny, z.objectOutputType<{
36
89
  id: z.ZodString;
37
90
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
@@ -61,6 +114,59 @@ export declare const ActivitySchema: z.ZodObject<{
61
114
  feel: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
62
115
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
63
116
  trainer: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
117
+ decoupling: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
118
+ icu_efficiency_factor: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
119
+ icu_power_hr: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
120
+ icu_variability_index: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
121
+ icu_pm_cp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
122
+ icu_rolling_ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
123
+ polarization_index: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
124
+ icu_zone_times: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
125
+ id: z.ZodString;
126
+ secs: z.ZodNumber;
127
+ }, "strip", z.ZodTypeAny, {
128
+ id: string;
129
+ secs: number;
130
+ }, {
131
+ id: string;
132
+ secs: number;
133
+ }>, "many">>>;
134
+ icu_hr_zone_times: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
135
+ total_elevation_loss: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
136
+ max_speed: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
137
+ min_altitude: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
138
+ max_altitude: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
139
+ icu_joules: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
140
+ icu_hrr: z.ZodOptional<z.ZodNullable<z.ZodObject<{
141
+ hrr: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
142
+ start_bpm: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
143
+ end_bpm: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
144
+ }, "strip", z.ZodTypeAny, {
145
+ hrr?: number | null | undefined;
146
+ start_bpm?: number | null | undefined;
147
+ end_bpm?: number | null | undefined;
148
+ }, {
149
+ hrr?: number | null | undefined;
150
+ start_bpm?: number | null | undefined;
151
+ end_bpm?: number | null | undefined;
152
+ }>>>;
153
+ strain_score: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
154
+ hr_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
155
+ power_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
156
+ gear: z.ZodOptional<z.ZodNullable<z.ZodObject<{
157
+ id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
158
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
159
+ }, "strip", z.ZodTypeAny, {
160
+ id?: string | null | undefined;
161
+ name?: string | null | undefined;
162
+ }, {
163
+ id?: string | null | undefined;
164
+ name?: string | null | undefined;
165
+ }>>>;
166
+ device_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
167
+ power_meter: z.ZodOptional<z.ZodNullable<z.ZodString>>;
168
+ source: z.ZodOptional<z.ZodNullable<z.ZodString>>;
169
+ compliance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
64
170
  }, z.ZodTypeAny, "passthrough">, z.objectInputType<{
65
171
  id: z.ZodString;
66
172
  name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
@@ -90,6 +196,59 @@ export declare const ActivitySchema: z.ZodObject<{
90
196
  feel: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
91
197
  description: z.ZodOptional<z.ZodNullable<z.ZodString>>;
92
198
  trainer: z.ZodOptional<z.ZodNullable<z.ZodBoolean>>;
199
+ decoupling: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
200
+ icu_efficiency_factor: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
201
+ icu_power_hr: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
202
+ icu_variability_index: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
203
+ icu_pm_cp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
204
+ icu_rolling_ftp: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
205
+ polarization_index: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
206
+ icu_zone_times: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodObject<{
207
+ id: z.ZodString;
208
+ secs: z.ZodNumber;
209
+ }, "strip", z.ZodTypeAny, {
210
+ id: string;
211
+ secs: number;
212
+ }, {
213
+ id: string;
214
+ secs: number;
215
+ }>, "many">>>;
216
+ icu_hr_zone_times: z.ZodOptional<z.ZodNullable<z.ZodArray<z.ZodNumber, "many">>>;
217
+ total_elevation_loss: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
218
+ max_speed: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
219
+ min_altitude: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
220
+ max_altitude: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
221
+ icu_joules: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
222
+ icu_hrr: z.ZodOptional<z.ZodNullable<z.ZodObject<{
223
+ hrr: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
224
+ start_bpm: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
225
+ end_bpm: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
226
+ }, "strip", z.ZodTypeAny, {
227
+ hrr?: number | null | undefined;
228
+ start_bpm?: number | null | undefined;
229
+ end_bpm?: number | null | undefined;
230
+ }, {
231
+ hrr?: number | null | undefined;
232
+ start_bpm?: number | null | undefined;
233
+ end_bpm?: number | null | undefined;
234
+ }>>>;
235
+ strain_score: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
236
+ hr_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
237
+ power_load: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
238
+ gear: z.ZodOptional<z.ZodNullable<z.ZodObject<{
239
+ id: z.ZodOptional<z.ZodNullable<z.ZodString>>;
240
+ name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
241
+ }, "strip", z.ZodTypeAny, {
242
+ id?: string | null | undefined;
243
+ name?: string | null | undefined;
244
+ }, {
245
+ id?: string | null | undefined;
246
+ name?: string | null | undefined;
247
+ }>>>;
248
+ device_name: z.ZodOptional<z.ZodNullable<z.ZodString>>;
249
+ power_meter: z.ZodOptional<z.ZodNullable<z.ZodString>>;
250
+ source: z.ZodOptional<z.ZodNullable<z.ZodString>>;
251
+ compliance: z.ZodOptional<z.ZodNullable<z.ZodNumber>>;
93
252
  }, z.ZodTypeAny, "passthrough">>;
94
253
  export type Activity = z.infer<typeof ActivitySchema>;
95
254
  export declare const WellnessSchema: z.ZodObject<{
package/dist/client.js CHANGED
@@ -53,6 +53,36 @@ 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(),
56
86
  }).passthrough();
57
87
  export const WellnessSchema = z.object({
58
88
  id: z.string().optional(),
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,23 +18,30 @@ 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");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "intervals-icu-mcp-server",
3
- "version": "0.2.0",
3
+ "version": "0.2.1",
4
4
  "description": "MCP server for Intervals.icu — 24 tools for activities, wellness, calendar events, workouts and more",
5
5
  "type": "module",
6
6
  "bin": {