@trainheroic-unofficial/athlete-mcp 0.4.0 → 0.4.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/server.mjs +75 -0
- package/package.json +3 -3
package/dist/server.mjs
CHANGED
|
@@ -848,6 +848,45 @@ async function logAthleteSet(client, args) {
|
|
|
848
848
|
exercisesLogged
|
|
849
849
|
};
|
|
850
850
|
}
|
|
851
|
+
/**
|
|
852
|
+
* POST /v5/programWorkouts/personal — create a personal workout session for a given date.
|
|
853
|
+
* Returns the key ids: workoutId (needed for addExercisesToWorkout), programWorkoutId,
|
|
854
|
+
* savedWorkoutId, and groupId.
|
|
855
|
+
*/
|
|
856
|
+
async function createPersonalWorkout(client, date) {
|
|
857
|
+
const res = await client.request("POST", "/v5/programWorkouts/personal", { body: { date } });
|
|
858
|
+
if (!res.ok) throw new Error(`Create personal workout failed (HTTP ${res.status}).`);
|
|
859
|
+
if (!isRecord(res.data)) throw new Error("Unexpected response from /v5/programWorkouts/personal.");
|
|
860
|
+
const pw = isRecord(res.data.programWorkout) ? res.data.programWorkout : null;
|
|
861
|
+
const sw = isRecord(res.data.savedWorkout) ? res.data.savedWorkout : null;
|
|
862
|
+
if (!pw || !sw) throw new Error("Missing programWorkout or savedWorkout in response.");
|
|
863
|
+
const programWorkoutId = coerceInt(pw.id);
|
|
864
|
+
const workoutId = coerceInt(pw.workoutId);
|
|
865
|
+
const savedWorkoutId = coerceInt(sw.id);
|
|
866
|
+
const groupId = coerceInt(sw.group_id);
|
|
867
|
+
if (!programWorkoutId || !workoutId || !savedWorkoutId || !groupId) throw new Error("Could not parse required ids from personal workout response.");
|
|
868
|
+
return {
|
|
869
|
+
programWorkoutId,
|
|
870
|
+
workoutId,
|
|
871
|
+
savedWorkoutId,
|
|
872
|
+
groupId,
|
|
873
|
+
date: typeof pw.date === "string" ? pw.date : date
|
|
874
|
+
};
|
|
875
|
+
}
|
|
876
|
+
/**
|
|
877
|
+
* PUT /v5/personalCalendar/workouts/{workoutId}/addExercises — add exercises to a personal
|
|
878
|
+
* workout. Returns saved workout set objects: each top-level `id` is a savedWorkoutSetId
|
|
879
|
+
* and `savedWorkoutSetExercises[].id` is a savedWorkoutSetExerciseId, both needed by
|
|
880
|
+
* logAthleteSet.
|
|
881
|
+
*/
|
|
882
|
+
async function addExercisesToWorkout(client, workoutId, exercises) {
|
|
883
|
+
const res = await client.request("PUT", `/v5/personalCalendar/workouts/${workoutId}/addExercises`, { body: {
|
|
884
|
+
exercises,
|
|
885
|
+
circuits: []
|
|
886
|
+
} });
|
|
887
|
+
if (!res.ok) throw new Error(`Add exercises to workout failed (HTTP ${res.status}).`);
|
|
888
|
+
return res.data;
|
|
889
|
+
}
|
|
851
890
|
/** Flatten `/v5/exercises/{id}/history` into PRs + a session time-series. */
|
|
852
891
|
function presentExerciseHistory(detail) {
|
|
853
892
|
return {
|
|
@@ -980,6 +1019,41 @@ function registerExerciseTools(server, ctx, userId) {
|
|
|
980
1019
|
annotations: READ
|
|
981
1020
|
}, ({ exerciseId, date }) => attempt(async () => jsonResult(await fetchExerciseStats(ctx.client, toId(exerciseId), await userId(), date))));
|
|
982
1021
|
}
|
|
1022
|
+
/** Create a personal workout session and add exercises to it. */
|
|
1023
|
+
function registerSessionTools(server, ctx) {
|
|
1024
|
+
server.registerTool("athlete_session_create", {
|
|
1025
|
+
title: "Create personal workout session",
|
|
1026
|
+
description: "Create a new personal workout session for a given YYYY-MM-DD date on the athlete's personal calendar. Returns programWorkoutId, workoutId (pass to athlete_session_add_exercises), savedWorkoutId, groupId, and date.",
|
|
1027
|
+
inputSchema: { date: dateString },
|
|
1028
|
+
annotations: {
|
|
1029
|
+
readOnlyHint: false,
|
|
1030
|
+
destructiveHint: false,
|
|
1031
|
+
openWorldHint: true
|
|
1032
|
+
}
|
|
1033
|
+
}, ({ date }) => attempt(async () => jsonResult(await createPersonalWorkout(ctx.client, date))));
|
|
1034
|
+
server.registerTool("athlete_session_add_exercises", {
|
|
1035
|
+
title: "Add exercises to a personal workout session",
|
|
1036
|
+
description: "Add one or more exercises to a personal workout session. Get workoutId from athlete_session_create. Each item needs an exerciseId (from athlete_exercises) and a 1-based order. Returns saved workout set objects: each top-level id is a savedWorkoutSetId and savedWorkoutSetExercises[].id is a savedWorkoutSetExerciseId — both needed for athlete_log_set.",
|
|
1037
|
+
inputSchema: {
|
|
1038
|
+
workoutId: idParam,
|
|
1039
|
+
exercises: z.array(z.object({
|
|
1040
|
+
exerciseId: idParam,
|
|
1041
|
+
order: z.number().int().positive()
|
|
1042
|
+
})).min(1)
|
|
1043
|
+
},
|
|
1044
|
+
annotations: {
|
|
1045
|
+
readOnlyHint: false,
|
|
1046
|
+
destructiveHint: false,
|
|
1047
|
+
openWorldHint: true
|
|
1048
|
+
}
|
|
1049
|
+
}, ({ workoutId, exercises }) => attempt(async () => {
|
|
1050
|
+
const mapped = exercises.map((e) => ({
|
|
1051
|
+
exerciseId: toId(e.exerciseId),
|
|
1052
|
+
order: e.order
|
|
1053
|
+
}));
|
|
1054
|
+
return jsonResult(await addExercisesToWorkout(ctx.client, toId(workoutId), mapped), { hint: "Each top-level id is a savedWorkoutSetId; savedWorkoutSetExercises[].id is the savedWorkoutSetExerciseId for athlete_log_set." });
|
|
1055
|
+
}));
|
|
1056
|
+
}
|
|
983
1057
|
/** The gated set-logging write. */
|
|
984
1058
|
function registerLogTool(server, ctx) {
|
|
985
1059
|
server.registerTool("athlete_log_set", {
|
|
@@ -1030,6 +1104,7 @@ function registerAthleteTrainingTools(server, ctx) {
|
|
|
1030
1104
|
};
|
|
1031
1105
|
registerProfileTools(server, ctx, whoami, userId);
|
|
1032
1106
|
registerExerciseTools(server, ctx, userId);
|
|
1107
|
+
registerSessionTools(server, ctx);
|
|
1033
1108
|
registerLogTool(server, ctx);
|
|
1034
1109
|
}
|
|
1035
1110
|
//#endregion
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@trainheroic-unofficial/athlete-mcp",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -21,8 +21,8 @@
|
|
|
21
21
|
"dependencies": {
|
|
22
22
|
"@modelcontextprotocol/sdk": "^1.29.0",
|
|
23
23
|
"zod": "^4.4.3",
|
|
24
|
-
"@trainheroic-unofficial/
|
|
25
|
-
"@trainheroic-unofficial/
|
|
24
|
+
"@trainheroic-unofficial/js": "0.4.1",
|
|
25
|
+
"@trainheroic-unofficial/core": "0.4.1"
|
|
26
26
|
},
|
|
27
27
|
"devDependencies": {
|
|
28
28
|
"@types/node": "^26.0.0",
|