hevy-mcp 1.15.0 → 1.16.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/cli.js CHANGED
@@ -11,7 +11,7 @@ import { z as z6 } from "zod";
11
11
 
12
12
  // package.json
13
13
  var name = "hevy-mcp";
14
- var version = "1.14.4";
14
+ var version = "1.15.0";
15
15
 
16
16
  // src/tools/folders.ts
17
17
  import { z } from "zod";
@@ -165,6 +165,22 @@ function formatExerciseTemplate(template) {
165
165
  isCustom: template.is_custom
166
166
  };
167
167
  }
168
+ function formatExerciseHistoryEntry(entry) {
169
+ return {
170
+ workoutId: entry.workout_id,
171
+ workoutTitle: entry.workout_title,
172
+ workoutStartTime: entry.workout_start_time,
173
+ workoutEndTime: entry.workout_end_time,
174
+ exerciseTemplateId: entry.exercise_template_id,
175
+ weight: entry.weight_kg,
176
+ reps: entry.reps,
177
+ distance: entry.distance_meters,
178
+ duration: entry.duration_seconds,
179
+ rpe: entry.rpe,
180
+ customMetric: entry.custom_metric,
181
+ setType: entry.set_type
182
+ };
183
+ }
168
184
 
169
185
  // src/utils/response-formatter.ts
170
186
  function createJsonResponse(data, options = { pretty: true, indent: 2 }) {
@@ -553,6 +569,139 @@ function registerTemplateTools(server, hevyClient) {
553
569
  return createJsonResponse(template);
554
570
  }, "get-exercise-template")
555
571
  );
572
+ const getExerciseHistorySchema = {
573
+ exerciseTemplateId: z3.string().min(1),
574
+ startDate: z3.string().datetime({ offset: true }).describe("ISO 8601 start date for filtering history").optional(),
575
+ endDate: z3.string().datetime({ offset: true }).describe("ISO 8601 end date for filtering history").optional()
576
+ };
577
+ server.tool(
578
+ "get-exercise-history",
579
+ "Get past sets for a specific exercise template, optionally filtered by start and end dates.",
580
+ getExerciseHistorySchema,
581
+ withErrorHandling(async (args) => {
582
+ if (!hevyClient) {
583
+ throw new Error(
584
+ "API client not initialized. Please provide HEVY_API_KEY."
585
+ );
586
+ }
587
+ const { exerciseTemplateId, startDate, endDate } = args;
588
+ const data = await hevyClient.getExerciseHistory(exerciseTemplateId, {
589
+ ...startDate ? { start_date: startDate } : {},
590
+ ...endDate ? { end_date: endDate } : {}
591
+ });
592
+ const history = data?.exercise_history?.map(
593
+ (entry) => formatExerciseHistoryEntry(entry)
594
+ ) || [];
595
+ if (history.length === 0) {
596
+ return createEmptyResponse(
597
+ `No exercise history found for template ${exerciseTemplateId}`
598
+ );
599
+ }
600
+ return createJsonResponse(history);
601
+ }, "get-exercise-history")
602
+ );
603
+ const createExerciseTemplateSchema = {
604
+ title: z3.string().min(1),
605
+ exerciseType: z3.enum([
606
+ "weight_reps",
607
+ "reps_only",
608
+ "bodyweight_reps",
609
+ "bodyweight_assisted_reps",
610
+ "duration",
611
+ "weight_duration",
612
+ "distance_duration",
613
+ "short_distance_weight"
614
+ ]),
615
+ equipmentCategory: z3.enum([
616
+ "none",
617
+ "barbell",
618
+ "dumbbell",
619
+ "kettlebell",
620
+ "machine",
621
+ "plate",
622
+ "resistance_band",
623
+ "suspension",
624
+ "other"
625
+ ]),
626
+ muscleGroup: z3.enum([
627
+ "abdominals",
628
+ "shoulders",
629
+ "biceps",
630
+ "triceps",
631
+ "forearms",
632
+ "quadriceps",
633
+ "hamstrings",
634
+ "calves",
635
+ "glutes",
636
+ "abductors",
637
+ "adductors",
638
+ "lats",
639
+ "upper_back",
640
+ "traps",
641
+ "lower_back",
642
+ "chest",
643
+ "cardio",
644
+ "neck",
645
+ "full_body",
646
+ "other"
647
+ ]),
648
+ otherMuscles: z3.array(
649
+ z3.enum([
650
+ "abdominals",
651
+ "shoulders",
652
+ "biceps",
653
+ "triceps",
654
+ "forearms",
655
+ "quadriceps",
656
+ "hamstrings",
657
+ "calves",
658
+ "glutes",
659
+ "abductors",
660
+ "adductors",
661
+ "lats",
662
+ "upper_back",
663
+ "traps",
664
+ "lower_back",
665
+ "chest",
666
+ "cardio",
667
+ "neck",
668
+ "full_body",
669
+ "other"
670
+ ])
671
+ ).default([])
672
+ };
673
+ server.tool(
674
+ "create-exercise-template",
675
+ "Create a custom exercise template with title, type, equipment, and muscle groups.",
676
+ createExerciseTemplateSchema,
677
+ withErrorHandling(async (args) => {
678
+ if (!hevyClient) {
679
+ throw new Error(
680
+ "API client not initialized. Please provide HEVY_API_KEY."
681
+ );
682
+ }
683
+ const {
684
+ title,
685
+ exerciseType,
686
+ equipmentCategory,
687
+ muscleGroup,
688
+ otherMuscles
689
+ } = args;
690
+ const response = await hevyClient.createExerciseTemplate({
691
+ exercise: {
692
+ title,
693
+ exercise_type: exerciseType,
694
+ equipment_category: equipmentCategory,
695
+ muscle_group: muscleGroup,
696
+ other_muscles: otherMuscles
697
+ }
698
+ });
699
+ return createJsonResponse({
700
+ id: response?.id,
701
+ message: "Exercise template created successfully"
702
+ });
703
+ }, "create-exercise-template")
704
+ );
556
705
  }
557
706
 
558
707
  // src/tools/webhooks.ts
@@ -776,6 +925,7 @@ function registerWorkoutTools(server, hevyClient) {
776
925
  description: z5.string().optional().nullable(),
777
926
  startTime: z5.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/),
778
927
  endTime: z5.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/),
928
+ routineId: z5.string().optional().nullable(),
779
929
  isPrivate: z5.boolean().default(false),
780
930
  exercises: z5.array(
781
931
  z5.object({
@@ -816,6 +966,7 @@ function registerWorkoutTools(server, hevyClient) {
816
966
  description: description || null,
817
967
  start_time: startTime,
818
968
  end_time: endTime,
969
+ routine_id: args.routineId ?? null,
819
970
  is_private: isPrivate,
820
971
  exercises: exercises.map(
821
972
  (exercise) => ({
@@ -854,6 +1005,7 @@ function registerWorkoutTools(server, hevyClient) {
854
1005
  description: z5.string().optional().nullable(),
855
1006
  startTime: z5.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/),
856
1007
  endTime: z5.string().regex(/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}Z$/),
1008
+ routineId: z5.string().optional().nullable(),
857
1009
  isPrivate: z5.boolean().default(false),
858
1010
  exercises: z5.array(
859
1011
  z5.object({
@@ -893,6 +1045,7 @@ function registerWorkoutTools(server, hevyClient) {
893
1045
  description,
894
1046
  startTime,
895
1047
  endTime,
1048
+ routineId,
896
1049
  isPrivate,
897
1050
  exercises
898
1051
  } = args;
@@ -902,6 +1055,7 @@ function registerWorkoutTools(server, hevyClient) {
902
1055
  description: description || null,
903
1056
  start_time: startTime,
904
1057
  end_time: endTime,
1058
+ routine_id: routineId ?? null,
905
1059
  is_private: isPrivate,
906
1060
  exercises: exercises.map(
907
1061
  (exercise) => ({
@@ -973,15 +1127,15 @@ function assertApiKey(apiKey) {
973
1127
  // src/utils/hevyClientKubb.ts
974
1128
  import axios from "axios";
975
1129
 
976
- // src/generated/client/api/deleteV1WebhookSubscription.ts
1130
+ // src/generated/client/api/getV1ExerciseHistoryExercisetemplateid.ts
977
1131
  import fetch from "@kubb/plugin-client/clients/axios";
978
- function getDeleteV1WebhookSubscriptionUrl() {
979
- const res = { method: "DELETE", url: `/v1/webhook-subscription` };
1132
+ function getGetV1ExerciseHistoryExercisetemplateidUrl(exerciseTemplateId) {
1133
+ const res = { method: "GET", url: `/v1/exercise_history/${exerciseTemplateId}` };
980
1134
  return res;
981
1135
  }
982
- async function deleteV1WebhookSubscription(headers, config = {}) {
1136
+ async function getV1ExerciseHistoryExercisetemplateid(exerciseTemplateId, headers, params, config = {}) {
983
1137
  const { client: request = fetch, ...requestConfig } = config;
984
- const res = await request({ method: "DELETE", url: getDeleteV1WebhookSubscriptionUrl().url.toString(), ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
1138
+ const res = await request({ method: "GET", url: getGetV1ExerciseHistoryExercisetemplateidUrl(exerciseTemplateId).url.toString(), params, ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
985
1139
  return res.data;
986
1140
  }
987
1141
 
@@ -1057,66 +1211,67 @@ async function getV1RoutinesRoutineid(routineId, headers, config = {}) {
1057
1211
  return res.data;
1058
1212
  }
1059
1213
 
1060
- // src/generated/client/api/getV1WebhookSubscription.ts
1061
- import fetch8 from "@kubb/plugin-client/clients/axios";
1062
- function getGetV1WebhookSubscriptionUrl() {
1063
- const res = { method: "GET", url: `/v1/webhook-subscription` };
1064
- return res;
1065
- }
1066
- async function getV1WebhookSubscription(headers, config = {}) {
1067
- const { client: request = fetch8, ...requestConfig } = config;
1068
- const res = await request({ method: "GET", url: getGetV1WebhookSubscriptionUrl().url.toString(), ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
1069
- return res.data;
1070
- }
1071
-
1072
1214
  // src/generated/client/api/getV1Workouts.ts
1073
- import fetch9 from "@kubb/plugin-client/clients/axios";
1215
+ import fetch8 from "@kubb/plugin-client/clients/axios";
1074
1216
  function getGetV1WorkoutsUrl() {
1075
1217
  const res = { method: "GET", url: `/v1/workouts` };
1076
1218
  return res;
1077
1219
  }
1078
1220
  async function getV1Workouts(headers, params, config = {}) {
1079
- const { client: request = fetch9, ...requestConfig } = config;
1221
+ const { client: request = fetch8, ...requestConfig } = config;
1080
1222
  const res = await request({ method: "GET", url: getGetV1WorkoutsUrl().url.toString(), params, ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
1081
1223
  return res.data;
1082
1224
  }
1083
1225
 
1084
1226
  // src/generated/client/api/getV1WorkoutsCount.ts
1085
- import fetch10 from "@kubb/plugin-client/clients/axios";
1227
+ import fetch9 from "@kubb/plugin-client/clients/axios";
1086
1228
  function getGetV1WorkoutsCountUrl() {
1087
1229
  const res = { method: "GET", url: `/v1/workouts/count` };
1088
1230
  return res;
1089
1231
  }
1090
1232
  async function getV1WorkoutsCount(headers, config = {}) {
1091
- const { client: request = fetch10, ...requestConfig } = config;
1233
+ const { client: request = fetch9, ...requestConfig } = config;
1092
1234
  const res = await request({ method: "GET", url: getGetV1WorkoutsCountUrl().url.toString(), ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
1093
1235
  return res.data;
1094
1236
  }
1095
1237
 
1096
1238
  // src/generated/client/api/getV1WorkoutsEvents.ts
1097
- import fetch11 from "@kubb/plugin-client/clients/axios";
1239
+ import fetch10 from "@kubb/plugin-client/clients/axios";
1098
1240
  function getGetV1WorkoutsEventsUrl() {
1099
1241
  const res = { method: "GET", url: `/v1/workouts/events` };
1100
1242
  return res;
1101
1243
  }
1102
1244
  async function getV1WorkoutsEvents(headers, params, config = {}) {
1103
- const { client: request = fetch11, ...requestConfig } = config;
1245
+ const { client: request = fetch10, ...requestConfig } = config;
1104
1246
  const res = await request({ method: "GET", url: getGetV1WorkoutsEventsUrl().url.toString(), params, ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
1105
1247
  return res.data;
1106
1248
  }
1107
1249
 
1108
1250
  // src/generated/client/api/getV1WorkoutsWorkoutid.ts
1109
- import fetch12 from "@kubb/plugin-client/clients/axios";
1251
+ import fetch11 from "@kubb/plugin-client/clients/axios";
1110
1252
  function getGetV1WorkoutsWorkoutidUrl(workoutId) {
1111
1253
  const res = { method: "GET", url: `/v1/workouts/${workoutId}` };
1112
1254
  return res;
1113
1255
  }
1114
1256
  async function getV1WorkoutsWorkoutid(workoutId, headers, config = {}) {
1115
- const { client: request = fetch12, ...requestConfig } = config;
1257
+ const { client: request = fetch11, ...requestConfig } = config;
1116
1258
  const res = await request({ method: "GET", url: getGetV1WorkoutsWorkoutidUrl(workoutId).url.toString(), ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
1117
1259
  return res.data;
1118
1260
  }
1119
1261
 
1262
+ // src/generated/client/api/postV1ExerciseTemplates.ts
1263
+ import fetch12 from "@kubb/plugin-client/clients/axios";
1264
+ function getPostV1ExerciseTemplatesUrl() {
1265
+ const res = { method: "POST", url: `/v1/exercise_templates` };
1266
+ return res;
1267
+ }
1268
+ async function postV1ExerciseTemplates(headers, data, config = {}) {
1269
+ const { client: request = fetch12, ...requestConfig } = config;
1270
+ const requestData = data;
1271
+ const res = await request({ method: "POST", url: getPostV1ExerciseTemplatesUrl().url.toString(), data: requestData, ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
1272
+ return res.data;
1273
+ }
1274
+
1120
1275
  // src/generated/client/api/postV1RoutineFolders.ts
1121
1276
  import fetch13 from "@kubb/plugin-client/clients/axios";
1122
1277
  function getPostV1RoutineFoldersUrl() {
@@ -1143,53 +1298,40 @@ async function postV1Routines(headers, data, config = {}) {
1143
1298
  return res.data;
1144
1299
  }
1145
1300
 
1146
- // src/generated/client/api/postV1WebhookSubscription.ts
1147
- import fetch15 from "@kubb/plugin-client/clients/axios";
1148
- function getPostV1WebhookSubscriptionUrl() {
1149
- const res = { method: "POST", url: `/v1/webhook-subscription` };
1150
- return res;
1151
- }
1152
- async function postV1WebhookSubscription(headers, data, config = {}) {
1153
- const { client: request = fetch15, ...requestConfig } = config;
1154
- const requestData = data;
1155
- const res = await request({ method: "POST", url: getPostV1WebhookSubscriptionUrl().url.toString(), data: requestData, ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
1156
- return res.data;
1157
- }
1158
-
1159
1301
  // src/generated/client/api/postV1Workouts.ts
1160
- import fetch16 from "@kubb/plugin-client/clients/axios";
1302
+ import fetch15 from "@kubb/plugin-client/clients/axios";
1161
1303
  function getPostV1WorkoutsUrl() {
1162
1304
  const res = { method: "POST", url: `/v1/workouts` };
1163
1305
  return res;
1164
1306
  }
1165
1307
  async function postV1Workouts(headers, data, config = {}) {
1166
- const { client: request = fetch16, ...requestConfig } = config;
1308
+ const { client: request = fetch15, ...requestConfig } = config;
1167
1309
  const requestData = data;
1168
1310
  const res = await request({ method: "POST", url: getPostV1WorkoutsUrl().url.toString(), data: requestData, ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
1169
1311
  return res.data;
1170
1312
  }
1171
1313
 
1172
1314
  // src/generated/client/api/putV1RoutinesRoutineid.ts
1173
- import fetch17 from "@kubb/plugin-client/clients/axios";
1315
+ import fetch16 from "@kubb/plugin-client/clients/axios";
1174
1316
  function getPutV1RoutinesRoutineidUrl(routineId) {
1175
1317
  const res = { method: "PUT", url: `/v1/routines/${routineId}` };
1176
1318
  return res;
1177
1319
  }
1178
1320
  async function putV1RoutinesRoutineid(routineId, headers, data, config = {}) {
1179
- const { client: request = fetch17, ...requestConfig } = config;
1321
+ const { client: request = fetch16, ...requestConfig } = config;
1180
1322
  const requestData = data;
1181
1323
  const res = await request({ method: "PUT", url: getPutV1RoutinesRoutineidUrl(routineId).url.toString(), data: requestData, ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
1182
1324
  return res.data;
1183
1325
  }
1184
1326
 
1185
1327
  // src/generated/client/api/putV1WorkoutsWorkoutid.ts
1186
- import fetch18 from "@kubb/plugin-client/clients/axios";
1328
+ import fetch17 from "@kubb/plugin-client/clients/axios";
1187
1329
  function getPutV1WorkoutsWorkoutidUrl(workoutId) {
1188
1330
  const res = { method: "PUT", url: `/v1/workouts/${workoutId}` };
1189
1331
  return res;
1190
1332
  }
1191
1333
  async function putV1WorkoutsWorkoutid(workoutId, headers, data, config = {}) {
1192
- const { client: request = fetch18, ...requestConfig } = config;
1334
+ const { client: request = fetch17, ...requestConfig } = config;
1193
1335
  const requestData = data;
1194
1336
  const res = await request({ method: "PUT", url: getPutV1WorkoutsWorkoutidUrl(workoutId).url.toString(), data: requestData, ...requestConfig, headers: { ...headers, ...requestConfig.headers } });
1195
1337
  return res.data;
@@ -1229,6 +1371,13 @@ function createClient(apiKey, baseUrl = "https://api.hevyapp.com") {
1229
1371
  getExerciseTemplate: (templateId) => getV1ExerciseTemplatesExercisetemplateid(templateId, headers, {
1230
1372
  client
1231
1373
  }),
1374
+ getExerciseHistory: (exerciseTemplateId, params) => getV1ExerciseHistoryExercisetemplateid(
1375
+ exerciseTemplateId,
1376
+ headers,
1377
+ params,
1378
+ { client }
1379
+ ),
1380
+ createExerciseTemplate: (data) => postV1ExerciseTemplates(headers, data, { client }),
1232
1381
  // Routine Folders
1233
1382
  getRoutineFolders: (params) => getV1RoutineFolders(headers, params, { client }),
1234
1383
  createRoutineFolder: (data) => postV1RoutineFolders(headers, data, { client }),
@@ -1236,9 +1385,9 @@ function createClient(apiKey, baseUrl = "https://api.hevyapp.com") {
1236
1385
  client
1237
1386
  }),
1238
1387
  // Webhooks
1239
- getWebhookSubscription: () => getV1WebhookSubscription(headers, { client }),
1240
- createWebhookSubscription: (data) => postV1WebhookSubscription(headers, data, { client }),
1241
- deleteWebhookSubscription: () => deleteV1WebhookSubscription(headers, { client })
1388
+ getWebhookSubscription: () => (void 0)(headers, { client }),
1389
+ createWebhookSubscription: (data) => (void 0)(headers, data, { client }),
1390
+ deleteWebhookSubscription: () => (void 0)(headers, { client })
1242
1391
  };
1243
1392
  }
1244
1393