hevy-mcp 6.1.12 → 6.1.13

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/CHANGELOG.md CHANGED
@@ -1,5 +1,11 @@
1
1
  # hevy-mcp
2
2
 
3
+ ## 6.1.13
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1162](https://github.com/chrisdoc/hevy-mcp/pull/1162) [`01a1a5e`](https://github.com/chrisdoc/hevy-mcp/commit/01a1a5e9d253dc4c0192929248a8dd92162dd176) Thanks [@chrisdoc](https://github.com/chrisdoc)! - Accept legacy flat camelCase create-routine calls from connected clients while advertising the canonical nested schema. Present identity-less routine creation responses as confirmed acknowledgements without an empty routine, and advise discovery before retrying.
8
+
3
9
  ## 6.1.12
4
10
 
5
11
  ### Patch Changes
package/dist/cli.mjs CHANGED
@@ -8,7 +8,7 @@
8
8
  n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "d637b259-c547-4286-9669-7b858825b504", e._sentryDebugIdIdentifier = "sentry-dbid-d637b259-c547-4286-9669-7b858825b504");
9
9
  } catch (e) {}
10
10
  })();
11
- import { i as handleFatalStartupError, r as getSafeStartupMessage, t as runServer } from "./runtime-CigeFRdX.mjs";
11
+ import { i as handleFatalStartupError, r as getSafeStartupMessage, t as runServer } from "./runtime-DZnkDB92.mjs";
12
12
  //#region src/cli.ts
13
13
  runServer().catch(async (error) => {
14
14
  await handleFatalStartupError(error);
@@ -68,14 +68,14 @@ function convertSchema(schema, io) {
68
68
  * array. The MCP wire envelope does not need a repeated `$schema` marker, and
69
69
  * structured output is validated by the original Zod schema before sending.
70
70
  */
71
- function compactJsonSchema(schema) {
71
+ function compactJsonSchema(schema, advertisedSchema = schema) {
72
72
  let inputSchema;
73
73
  let outputSchema;
74
74
  Object.defineProperty(schema["~standard"], "jsonSchema", {
75
75
  configurable: true,
76
76
  value: {
77
77
  input: () => {
78
- inputSchema ??= convertSchema(schema, "input");
78
+ inputSchema ??= convertSchema(advertisedSchema, "input");
79
79
  return inputSchema;
80
80
  },
81
81
  output: () => {
@@ -5303,16 +5303,24 @@ const updateWorkoutResponse = defineJsonResponseContract((data) => data.workout
5303
5303
  const repRangeDisplayWarningText = "Note: Hevy's public API stores rep ranges (rep_range), but the Hevy apps may not display them because they rely on an internal-only exercise field (input_modifier). See https://github.com/chrisdoc/hevy-mcp/issues/261 for details/workarounds.";
5304
5304
  const createRoutineResponse = defineStructuredResponseContract({
5305
5305
  outputSchema: createRoutineOutputSchema,
5306
- normalize: (data) => ({
5307
- created: true,
5308
- commit_state: "confirmed",
5309
- routine: data.routine ? projectRoutine(data.routine) : null,
5310
- routine_id: data.routine?.id ?? null,
5311
- uses_rep_ranges: data.usesRepRanges
5312
- }),
5306
+ normalize: (data) => {
5307
+ const projected = data.routine ? projectRoutine(data.routine) : null;
5308
+ const routine = projected?.id ? projected : null;
5309
+ return {
5310
+ created: true,
5311
+ commit_state: "confirmed",
5312
+ routine,
5313
+ routine_id: routine?.id ?? null,
5314
+ uses_rep_ranges: data.usesRepRanges
5315
+ };
5316
+ },
5313
5317
  legacyJson: (output) => output,
5314
- additionalText: (_data, output) => output.uses_rep_ranges ? [repRangeDisplayWarningText] : [],
5315
- telemetry: (data) => routineResultTelemetry(data.routine)
5318
+ additionalText: (_data, output) => {
5319
+ const messages = output.uses_rep_ranges ? [repRangeDisplayWarningText] : [];
5320
+ if (output.routine_id === null) messages.push("Hevy confirmed routine creation but did not return an ID. Search routines before retrying to avoid duplicates.");
5321
+ return messages;
5322
+ },
5323
+ telemetry: (data) => routineResultTelemetry(data.routine?.id ? data.routine : null)
5316
5324
  });
5317
5325
  const updateRoutineResponse = defineJsonResponseContract((data) => data.routine ? {
5318
5326
  json: projectRoutine(data.routine),
@@ -5346,9 +5354,10 @@ const registeredToolConfigCache = /* @__PURE__ */ new WeakMap();
5346
5354
  function getRegisteredToolConfig(definition) {
5347
5355
  const cached = registeredToolConfigCache.get(definition);
5348
5356
  if (cached) return cached;
5357
+ const advertisedInputSchema = z.strictObject(definition.inputSchema);
5349
5358
  const config = {
5350
5359
  description: definition.description,
5351
- inputSchema: compactJsonSchema(z.strictObject(definition.inputSchema)),
5360
+ inputSchema: compactJsonSchema(definition.inputParser ?? advertisedInputSchema, advertisedInputSchema),
5352
5361
  annotations: definition.annotations
5353
5362
  };
5354
5363
  if (definition.outputSchema) config.outputSchema = compactJsonSchema(z.object(definition.outputSchema));
@@ -5379,7 +5388,8 @@ function registerToolDefinition(server, runtime, definition) {
5379
5388
  server.registerTool(definition.name, config, (args, context) => {
5380
5389
  let parsed;
5381
5390
  try {
5382
- parsed = z.strictObject(definition.inputSchema).parse(args ?? {});
5391
+ const normalized = definition.inputParser ? definition.inputParser.parse(args ?? {}) : args ?? {};
5392
+ parsed = z.strictObject(definition.inputSchema).parse(normalized);
5383
5393
  } catch (error) {
5384
5394
  const path = error instanceof z.ZodError ? error.issues[0]?.path?.map((segment) => String(segment)).join(".") || "arguments" : "arguments";
5385
5395
  if (context) return invalidInputHandler({ path }, {
@@ -5641,7 +5651,57 @@ const routinePayloadFields = {
5641
5651
  exercises: routineExercisesSchema
5642
5652
  };
5643
5653
  const routinePayloadSchema = z.strictObject(routinePayloadFields);
5644
- const createRoutineInputFields = z.strictObject({ routine: routinePayloadSchema }).shape;
5654
+ const createRoutineInputSchema = z.strictObject({ routine: routinePayloadSchema });
5655
+ const createRoutineInputFields = createRoutineInputSchema.shape;
5656
+ const legacyRoutineSetSchema = z.strictObject({
5657
+ type: setTypeEnum.optional(),
5658
+ weight: zNullableNumber,
5659
+ weightKg: zNullableNumber,
5660
+ reps: zNullableInt.optional(),
5661
+ distance: zNullableInt,
5662
+ distanceMeters: zNullableInt,
5663
+ duration: zNullableInt,
5664
+ durationSeconds: zNullableInt,
5665
+ repRange: zStrictOptionalRepRange,
5666
+ customMetric: zNullableNumber
5667
+ });
5668
+ const legacyCreateRoutineInputSchema = z.strictObject({
5669
+ title: z.string().min(1),
5670
+ folderId: z.coerce.number().nullable().optional(),
5671
+ notes: z.string().optional(),
5672
+ exercises: z.array(z.strictObject({
5673
+ exerciseTemplateId: nonEmptyId,
5674
+ supersetId: z.coerce.number().nullable().optional(),
5675
+ restSeconds: z.coerce.number().int().min(0).optional(),
5676
+ notes: z.string().optional(),
5677
+ sets: z.array(legacyRoutineSetSchema).min(1)
5678
+ })).min(1)
5679
+ });
5680
+ const createRoutineInputParser = z.preprocess((input) => {
5681
+ const legacy = legacyCreateRoutineInputSchema.safeParse(input);
5682
+ if (!legacy.success) return input;
5683
+ const { title, folderId, notes, exercises } = legacy.data;
5684
+ return { routine: {
5685
+ title,
5686
+ folder_id: folderId,
5687
+ notes,
5688
+ exercises: exercises.map((exercise) => ({
5689
+ exercise_template_id: exercise.exerciseTemplateId,
5690
+ superset_id: exercise.supersetId,
5691
+ rest_seconds: exercise.restSeconds,
5692
+ notes: exercise.notes,
5693
+ sets: exercise.sets.map((set) => ({
5694
+ type: set.type ?? "normal",
5695
+ weight_kg: set.weightKg ?? set.weight ?? void 0,
5696
+ reps: set.reps,
5697
+ distance_meters: set.distanceMeters ?? set.distance ?? void 0,
5698
+ duration_seconds: set.durationSeconds ?? set.duration ?? void 0,
5699
+ rep_range: set.repRange,
5700
+ custom_metric: set.customMetric ?? void 0
5701
+ }))
5702
+ }))
5703
+ } };
5704
+ }, createRoutineInputSchema);
5645
5705
  const routineUpdatePayloadFields = {
5646
5706
  title: z.string().min(1),
5647
5707
  notes: z.string().optional(),
@@ -5870,6 +5930,7 @@ const routineToolDefinitions = [
5870
5930
  operation: "create",
5871
5931
  description: "Writes a reusable routine; use create-workout for completed sessions. Retries can create duplicates.",
5872
5932
  inputSchema: createRoutineInputFields,
5933
+ inputParser: createRoutineInputParser,
5873
5934
  kind: "write",
5874
5935
  outputSchema: createRoutineOutputSchema,
5875
5936
  annotations: createAnnotations("Create Routine"),
@@ -6624,7 +6685,7 @@ function readBuildGlobal(value) {
6624
6685
  }
6625
6686
  }
6626
6687
  const buildName = readBuildGlobal(() => "hevy-mcp");
6627
- const buildVersion = readBuildGlobal(() => "6.1.12");
6688
+ const buildVersion = readBuildGlobal(() => "6.1.13");
6628
6689
  const SERVER_NAME = readBuildString(buildName, "hevy-mcp");
6629
6690
  const SERVER_VERSION = readBuildString(buildVersion, "dev");
6630
6691
  const SERVER_INSTRUCTIONS = [
@@ -7192,4 +7253,4 @@ function assertApiKey(apiKey) {
7192
7253
  //#endregion
7193
7254
  export { SAFE_USER_HASH_PATTERN as a, mergeAbortSignals as c, createHevyClient as d, SAFE_OBSERVATION_CODES as f, isHevyHttpError as h, createHevyMcpServer as i, createSafeErrorDiagnostic as l, metricEndpointIdentity as m, assertApiKey as n, USER_HASH_CONTEXT as o, diagnosticEndpointIdentity as p, parseConfig as r, createExecutionProjection as s, MissingHevyApiKeyError as t, bucketCount as u };
7194
7255
 
7195
- //# sourceMappingURL=config-C53fgLWf.mjs.map
7256
+ //# sourceMappingURL=config-0fixupML.mjs.map
package/dist/index.mjs CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  // Generated with tsdown
3
3
  // https://tsdown.dev
4
- import { d as createHevyClient, i as createHevyMcpServer, n as assertApiKey } from "./config-C53fgLWf.mjs";
4
+ import { d as createHevyClient, i as createHevyMcpServer, n as assertApiKey } from "./config-0fixupML.mjs";
5
5
  //#region src/index.ts
6
6
  /**
7
7
  * Create an unconnected MCP server for embedding in a Node application.
@@ -26,7 +26,7 @@ async function createNodeMcpServer({ apiKey }, _transport = "stdio", lifecycleSi
26
26
  * does not evaluate the runtime bootstrap; it is loaded only when invoked.
27
27
  */
28
28
  async function runStdioServer() {
29
- const { runStdioServer: run } = await import("./runtime-CigeFRdX.mjs").then((n) => n.n);
29
+ const { runStdioServer: run } = await import("./runtime-DZnkDB92.mjs").then((n) => n.n);
30
30
  return run();
31
31
  }
32
32
  /**
@@ -34,7 +34,7 @@ async function runStdioServer() {
34
34
  * does not evaluate the runtime bootstrap; it is loaded only when invoked.
35
35
  */
36
36
  async function runServer() {
37
- const { runServer: run } = await import("./runtime-CigeFRdX.mjs").then((n) => n.n);
37
+ const { runServer: run } = await import("./runtime-DZnkDB92.mjs").then((n) => n.n);
38
38
  return run();
39
39
  }
40
40
  //#endregion
@@ -5,10 +5,10 @@
5
5
  try {
6
6
  var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {};
7
7
  var n = new e.Error().stack;
8
- n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "53720420-351c-4adc-9558-c7e27da54159", e._sentryDebugIdIdentifier = "sentry-dbid-53720420-351c-4adc-9558-c7e27da54159");
8
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "590b105c-b553-42c4-93bf-694cbacbccb1", e._sentryDebugIdIdentifier = "sentry-dbid-590b105c-b553-42c4-93bf-694cbacbccb1");
9
9
  } catch (e) {}
10
10
  })();
11
- import { a as SAFE_USER_HASH_PATTERN, c as mergeAbortSignals, d as createHevyClient, f as SAFE_OBSERVATION_CODES, h as isHevyHttpError, i as createHevyMcpServer, l as createSafeErrorDiagnostic, m as metricEndpointIdentity, n as assertApiKey, o as USER_HASH_CONTEXT, p as diagnosticEndpointIdentity, r as parseConfig, s as createExecutionProjection, t as MissingHevyApiKeyError, u as bucketCount } from "./config-C53fgLWf.mjs";
11
+ import { a as SAFE_USER_HASH_PATTERN, c as mergeAbortSignals, d as createHevyClient, f as SAFE_OBSERVATION_CODES, h as isHevyHttpError, i as createHevyMcpServer, l as createSafeErrorDiagnostic, m as metricEndpointIdentity, n as assertApiKey, o as USER_HASH_CONTEXT, p as diagnosticEndpointIdentity, r as parseConfig, s as createExecutionProjection, t as MissingHevyApiKeyError, u as bucketCount } from "./config-0fixupML.mjs";
12
12
  import { ZodError, z } from "zod";
13
13
  import { Data, Duration, Effect, Exit, Fiber, Layer, Scope, Semaphore } from "effect";
14
14
  import { deserializeMessage } from "@modelcontextprotocol/server";
@@ -410,7 +410,7 @@ function parseBuildString(value, fallback) {
410
410
  return z.string().parse(value ?? fallback);
411
411
  }
412
412
  const name$1 = parseBuildString(readBuildGlobal(() => "hevy-mcp"), "hevy-mcp");
413
- const version$1 = parseBuildString(readBuildGlobal(() => "6.1.12"), "dev");
413
+ const version$1 = parseBuildString(readBuildGlobal(() => "6.1.13"), "dev");
414
414
  const telemetryEnabled = process.env.HEVY_MCP_TELEMETRY !== "0";
415
415
  const collectorToken = z.string().safeParse(readBuildGlobal(() => "NH9vOela-HYreQxAbJa68cjEmORoEKM57EvneUDVcOo")).data ?? process.env.OTEL_COLLECTOR_TOKEN ?? "";
416
416
  const COLLECTOR_ENDPOINT = "https://otel.chrisdoc.dev/v1";
@@ -2958,4 +2958,4 @@ async function runServer() {
2958
2958
  //#endregion
2959
2959
  export { handleFatalStartupError as i, runtime_exports as n, getSafeStartupMessage as r, runServer as t };
2960
2960
 
2961
- //# sourceMappingURL=runtime-CigeFRdX.mjs.map
2961
+ //# sourceMappingURL=runtime-DZnkDB92.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hevy-mcp",
3
- "version": "6.1.12",
3
+ "version": "6.1.13",
4
4
  "private": false,
5
5
  "description": "A Model Context Protocol (MCP) server implementation that interfaces with the Hevy fitness tracking app and its API.",
6
6
  "repository": {
@@ -43,7 +43,7 @@
43
43
  "zod": "^4.6.5"
44
44
  },
45
45
  "devDependencies": {
46
- "@hevy-mcp/core": "0.2.11",
46
+ "@hevy-mcp/core": "0.2.12",
47
47
  "@hevy-mcp/hevy-client": "0.2.8",
48
48
  "@sentry/core": "^10.74.0",
49
49
  "@types/node": "^26.5.1",
package/server.json CHANGED
@@ -7,12 +7,12 @@
7
7
  "url": "https://github.com/chrisdoc/hevy-mcp",
8
8
  "source": "github"
9
9
  },
10
- "version": "6.1.12",
10
+ "version": "6.1.13",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "identifier": "hevy-mcp",
15
- "version": "6.1.12",
15
+ "version": "6.1.13",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  },