@trainheroic-unofficial/athlete-mcp 3.1.0 → 3.2.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.
Files changed (2) hide show
  1. package/dist/server.mjs +53 -2
  2. package/package.json +3 -3
package/dist/server.mjs CHANGED
@@ -287,6 +287,23 @@ const programWorkoutResponseSchema = z.looseObject({
287
287
  sets: z.record(z.string(), z.unknown()).optional()
288
288
  });
289
289
  z.looseObject({ programWorkouts: z.array(programWorkoutResponseSchema).optional() });
290
+ z.looseObject({
291
+ id: intLike,
292
+ title: z.string(),
293
+ programId: intLike,
294
+ group_program: intLike,
295
+ type: intLike,
296
+ program: z.looseObject({
297
+ id: intLike,
298
+ program_type: intLike
299
+ }).optional()
300
+ });
301
+ z.object({
302
+ pub_enabled: z.union([z.number(), z.boolean()]).optional(),
303
+ pub_days: z.unknown().optional(),
304
+ pub_time: z.unknown().optional(),
305
+ pub_timezone: z.string().optional()
306
+ }).refine((v) => v.pub_enabled !== void 0 || v.pub_days !== void 0 || v.pub_time !== void 0 || v.pub_timezone !== void 0, { message: "Provide at least one pub_* field" });
290
307
  //#endregion
291
308
  //#region ../dto/src/workout.ts
292
309
  /** A single exercise prescription inside a block. */
@@ -339,6 +356,10 @@ z.object({
339
356
  blocks: z.array(blockSpecSchema),
340
357
  instruction: z.string().optional()
341
358
  });
359
+ z.object({
360
+ title: z.string().min(1),
361
+ instruction: z.string().optional()
362
+ });
342
363
  //#endregion
343
364
  //#region ../core/src/context.ts
344
365
  /** A tool argument that accepts a numeric id as a number or a string of digits. */
@@ -699,7 +720,7 @@ var TrainHeroicClient = class {
699
720
  session = await this.#ensureSession();
700
721
  res = await this.#send(method, url, session, options.body);
701
722
  }
702
- if (!res.ok) notifyHttpError(this.#onHttpError, method, url, res.status);
723
+ if (!res.ok && !options.expectedStatuses?.includes(res.status)) notifyHttpError(this.#onHttpError, method, url, res.status);
703
724
  const text = await res.text();
704
725
  let data = text;
705
726
  if (text.length > 0) try {
@@ -849,6 +870,15 @@ function fetchWorkingMaxes(client) {
849
870
  function fetchExerciseHistoryList(client) {
850
871
  return getArray(client, "/v5/users/exercises/history", "athlete exercise history list");
851
872
  }
873
+ function fetchRecentExercises(client) {
874
+ return getArray(client, "/v5/users/exercises/recent", "athlete recent exercises");
875
+ }
876
+ function fetchAthleteCircuits(client, kind = "recent") {
877
+ return getArray(client, `/v5/users/circuits/${kind}`, `athlete ${kind} circuits`);
878
+ }
879
+ function fetchAthleteProgrammingPrograms(client) {
880
+ return getArray(client, "/1.0/athlete/programming/programs", "athlete programming programs");
881
+ }
852
882
  /** Free-text search over the athlete's logged exercises (FTS replacement via rankSearch). */
853
883
  async function searchExerciseHistory(client, query, limit = 20) {
854
884
  return rankSearch(await fetchExerciseHistoryList(client), query, limit);
@@ -2114,6 +2144,26 @@ function registerSwapTool(server, ctx) {
2114
2144
  }));
2115
2145
  }));
2116
2146
  }
2147
+ function registerCatalogReads(server, ctx) {
2148
+ server.registerTool("athlete_circuits", {
2149
+ title: "Circuit history",
2150
+ description: "Named circuit history for the logged-in athlete (GET /v5/users/circuits/{recent|history}). kind defaults to recent. Empty when the athlete has no saved circuits. Distinct from circuit *blocks* in workout_build (type 1).",
2151
+ inputSchema: { kind: z.enum(["recent", "history"]).optional() },
2152
+ annotations: READ
2153
+ }, ({ kind }) => attempt(async () => jsonResult(await fetchAthleteCircuits(ctx.client, kind ?? "recent"))));
2154
+ server.registerTool("athlete_programming_programs", {
2155
+ title: "Subscribed programs",
2156
+ description: "Programs the athlete is subscribed to (GET /1.0/athlete/programming/programs). Not the coach list_programs surface. Empty when the athlete has no subscriptions.",
2157
+ inputSchema: {},
2158
+ annotations: READ
2159
+ }, () => attempt(async () => jsonResult(await fetchAthleteProgrammingPrograms(ctx.client))));
2160
+ server.registerTool("athlete_recent_exercises", {
2161
+ title: "Recent exercises",
2162
+ description: "Recently used exercises (GET /v5/users/exercises/recent). Distinct from athlete_exercises (full logged catalog) and athlete_exercise_history (one lift).",
2163
+ inputSchema: {},
2164
+ annotations: READ
2165
+ }, () => attempt(async () => jsonResult(await fetchRecentExercises(ctx.client))));
2166
+ }
2117
2167
  /**
2118
2168
  * Live tools over the logged-in user's own training (history, scheduled/completed workouts,
2119
2169
  * PRs, working maxes), plus a gated set-logging write. The athlete user id is
@@ -2136,6 +2186,7 @@ function registerAthleteTrainingTools(server, ctx) {
2136
2186
  };
2137
2187
  registerProfileTools(server, ctx, whoami, userId);
2138
2188
  registerExerciseTools(server, ctx, userId);
2189
+ registerCatalogReads(server, ctx);
2139
2190
  registerLogTargetsTool(server, ctx);
2140
2191
  registerSessionTools(server, ctx);
2141
2192
  registerLogTool(server, ctx);
@@ -2143,7 +2194,7 @@ function registerAthleteTrainingTools(server, ctx) {
2143
2194
  }
2144
2195
  //#endregion
2145
2196
  //#region package.json
2146
- var version = "3.1.0";
2197
+ var version = "3.2.0";
2147
2198
  //#endregion
2148
2199
  //#region src/server.ts
2149
2200
  function main() {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@trainheroic-unofficial/athlete-mcp",
3
- "version": "3.1.0",
3
+ "version": "3.2.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -21,8 +21,8 @@
21
21
  "dependencies": {
22
22
  "@modelcontextprotocol/server": "2.0.0",
23
23
  "zod": "^4.4.3",
24
- "@trainheroic-unofficial/core": "3.1.0",
25
- "@trainheroic-unofficial/js": "3.1.0"
24
+ "@trainheroic-unofficial/core": "3.2.0",
25
+ "@trainheroic-unofficial/js": "3.2.0"
26
26
  },
27
27
  "devDependencies": {
28
28
  "@types/node": "^26.2.0",