update-routine
Modify workout routines by updating titles, notes, and exercise details. Use this tool to edit and apply changes to existing routines while maintaining folder assignments. Returns the updated routine.
Instructions
Update an existing workout routine by ID. You can modify the title, notes, and exercise data. Returns the updated routine with all changes applied. Note that you cannot change the folder assignment through this method.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| exercises | Yes | ||
| notes | No | ||
| routineId | Yes | ||
| title | Yes |
Implementation Reference
- src/tools/routines.ts:234-278 (handler)Handler function for 'update-routine' tool. Validates hevyClient availability, destructures input args using UpdateRoutineParams type, maps the exercises and sets to the API request format (PutRoutinesRequestExercise and PutRoutinesRequestSet), calls hevyClient.updateRoutine(routineId, payload), handles no-data case, formats the routine with formatRoutine, and returns a pretty JSON response.withErrorHandling(async (args) => { if (!hevyClient) { throw new Error( "API client not initialized. Please provide HEVY_API_KEY.", ); } const { routineId, title, notes, exercises } = args as UpdateRoutineParams; const data = await hevyClient.updateRoutine(routineId, { routine: { title, notes: notes ?? null, exercises: exercises.map( (exercise): PutRoutinesRequestExercise => ({ exercise_template_id: exercise.exerciseTemplateId, superset_id: exercise.supersetId ?? null, rest_seconds: exercise.restSeconds ?? null, notes: exercise.notes ?? null, sets: exercise.sets.map( (set): PutRoutinesRequestSet => ({ type: set.type as PutRoutinesRequestSetTypeEnumKey, weight_kg: set.weightKg ?? null, reps: set.reps ?? null, distance_meters: set.distanceMeters ?? null, duration_seconds: set.durationSeconds ?? null, custom_metric: set.customMetric ?? null, }), ), }), ), }, }); if (!data) { return createEmptyResponse( `Failed to update routine with ID ${routineId}`, ); } const routine = formatRoutine(data); return createJsonResponse(routine, { pretty: true, indent: 2, }); }, "update-routine"),
- src/tools/routines.ts:209-233 (schema)Zod schema defining the input parameters for the 'update-routine' tool: required routineId and title (strings), optional notes (string), and exercises array. Each exercise has exerciseTemplateId (string), optional supersetId, restSeconds, notes, and sets array. Each set has type (enum: warmup/normal/failure/dropset, default normal), and optional weightKg, reps, distanceMeters, durationSeconds, customMetric.{ routineId: z.string().min(1), title: z.string().min(1), notes: z.string().optional(), exercises: z.array( z.object({ exerciseTemplateId: z.string().min(1), supersetId: z.coerce.number().nullable().optional(), restSeconds: z.coerce.number().int().min(0).optional(), notes: z.string().optional(), sets: z.array( z.object({ type: z .enum(["warmup", "normal", "failure", "dropset"]) .default("normal"), weightKg: z.coerce.number().optional(), reps: z.coerce.number().int().optional(), distanceMeters: z.coerce.number().int().optional(), durationSeconds: z.coerce.number().int().optional(), customMetric: z.coerce.number().optional(), }), ), }), ), },
- src/tools/routines.ts:206-279 (registration)Registration of the 'update-routine' MCP tool using server.tool(). Includes the tool name, description (update existing routine by ID, modify title/notes/exercises), input schema, and error-handling wrapped handler function.server.tool( "update-routine", "Update an existing routine by ID. You can modify the title, notes, and exercise configurations. Returns the updated routine with all changes applied.", { routineId: z.string().min(1), title: z.string().min(1), notes: z.string().optional(), exercises: z.array( z.object({ exerciseTemplateId: z.string().min(1), supersetId: z.coerce.number().nullable().optional(), restSeconds: z.coerce.number().int().min(0).optional(), notes: z.string().optional(), sets: z.array( z.object({ type: z .enum(["warmup", "normal", "failure", "dropset"]) .default("normal"), weightKg: z.coerce.number().optional(), reps: z.coerce.number().int().optional(), distanceMeters: z.coerce.number().int().optional(), durationSeconds: z.coerce.number().int().optional(), customMetric: z.coerce.number().optional(), }), ), }), ), }, withErrorHandling(async (args) => { if (!hevyClient) { throw new Error( "API client not initialized. Please provide HEVY_API_KEY.", ); } const { routineId, title, notes, exercises } = args as UpdateRoutineParams; const data = await hevyClient.updateRoutine(routineId, { routine: { title, notes: notes ?? null, exercises: exercises.map( (exercise): PutRoutinesRequestExercise => ({ exercise_template_id: exercise.exerciseTemplateId, superset_id: exercise.supersetId ?? null, rest_seconds: exercise.restSeconds ?? null, notes: exercise.notes ?? null, sets: exercise.sets.map( (set): PutRoutinesRequestSet => ({ type: set.type as PutRoutinesRequestSetTypeEnumKey, weight_kg: set.weightKg ?? null, reps: set.reps ?? null, distance_meters: set.distanceMeters ?? null, duration_seconds: set.durationSeconds ?? null, custom_metric: set.customMetric ?? null, }), ), }), ), }, }); if (!data) { return createEmptyResponse( `Failed to update routine with ID ${routineId}`, ); } const routine = formatRoutine(data); return createJsonResponse(routine, { pretty: true, indent: 2, }); }, "update-routine"), );
- src/tools/routines.ts:46-64 (schema)TypeScript type definition UpdateRoutineParams mirroring the tool input schema, used for type assertion in the handler: routineId, title, optional notes, exercises array with structure matching the Zod schema.type UpdateRoutineParams = { routineId: string; title: string; notes?: string; exercises: Array<{ exerciseTemplateId: string; supersetId?: number | null; restSeconds?: number; notes?: string; sets: Array<{ type: "warmup" | "normal" | "failure" | "dropset"; weightKg?: number; reps?: number; distanceMeters?: number; durationSeconds?: number; customMetric?: number; }>; }>; };