hevy-mcp 6.1.13 → 6.1.14

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,15 @@
1
1
  # hevy-mcp
2
2
 
3
+ ## 6.1.14
4
+
5
+ ### Patch Changes
6
+
7
+ - [#1168](https://github.com/chrisdoc/hevy-mcp/pull/1168) [`6e61a84`](https://github.com/chrisdoc/hevy-mcp/commit/6e61a8439bf21bd74e74ee848c8ae5fdac78a52f) Thanks [@chrisdoc](https://github.com/chrisdoc)! - Expose string enum values for workout set RPE in tool input schemas to support Google Gemini and Vertex AI FunctionDeclaration validation, casting back to numeric values for downstream API calls.
8
+
9
+ - [#1165](https://github.com/chrisdoc/hevy-mcp/pull/1165) [`f35465e`](https://github.com/chrisdoc/hevy-mcp/commit/f35465e55023b9d77af993d674e5e218a3424785) Thanks [@dependabot](https://github.com/apps/dependabot)! - Regenerate the Hevy client with the updated Kubb toolchain.
10
+
11
+ - [#1168](https://github.com/chrisdoc/hevy-mcp/pull/1168) [`6e61a84`](https://github.com/chrisdoc/hevy-mcp/commit/6e61a8439bf21bd74e74ee848c8ae5fdac78a52f) Thanks [@chrisdoc](https://github.com/chrisdoc)! - Expose the client's maxGetRetries option through createNodeMcpServer. Embedders can set it to zero to disable automatic request retries, including PUT retries, and reconcile uncertain writes explicitly. Omitting the option preserves the existing client policy.
12
+
3
13
  ## 6.1.13
4
14
 
5
15
  ### 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-DZnkDB92.mjs";
11
+ import { i as handleFatalStartupError, r as getSafeStartupMessage, t as runServer } from "./runtime-Dkm4I9j5.mjs";
12
12
  //#region src/cli.ts
13
13
  runServer().catch(async (error) => {
14
14
  await handleFatalStartupError(error);
@@ -839,9 +839,19 @@ async function resolveAuth(params) {
839
839
  return;
840
840
  }
841
841
  }
842
- async function runValidator(validator, value) {
842
+ async function runValidator({ validator, value, context, onValidationError }) {
843
843
  if (!validator) return value;
844
- return validateStandardSchema(validator, value);
844
+ try {
845
+ return await validateStandardSchema(validator, value);
846
+ } catch (error) {
847
+ if (!onValidationError || !(error instanceof ParseError)) throw error;
848
+ const handled = await onValidationError(error, {
849
+ ...context,
850
+ value
851
+ });
852
+ if (!handled) throw error;
853
+ return handled.value;
854
+ }
845
855
  }
846
856
  /**
847
857
  * The base media type of a `Content-Type` value, lowercased and stripped of any `; charset=...` parameters.
@@ -904,7 +914,16 @@ async function resolveRequest({ config, requestConfig }) {
904
914
  const cookie = serializeCookies(requestConfig.cookies, requestConfig.styles?.cookie);
905
915
  if (cookie) headers["Cookie"] = [headers["Cookie"], cookie].filter(Boolean).join("; ");
906
916
  }
907
- const validatedBody = await runValidator(requestConfig.validator?.request, requestConfig.body);
917
+ const validatedBody = await runValidator({
918
+ validator: requestConfig.validator?.request,
919
+ value: requestConfig.body,
920
+ context: {
921
+ direction: "request",
922
+ method: requestConfig.method,
923
+ url: requestConfig.url
924
+ },
925
+ onValidationError: requestConfig.onValidationError ?? config.onValidationError
926
+ });
908
927
  const requestContentTypeBase = baseContentType(requestContentType);
909
928
  const contentCodec = requestContentTypeBase ? codecs[requestContentTypeBase] : void 0;
910
929
  const usesDefaultBodySerializer = !contentCodec?.serialize && bodySerializer === defaultBodySerializer;
@@ -947,7 +966,7 @@ async function resolveRequest({ config, requestConfig }) {
947
966
  * validates it, and throws a `ResponseError` (after running the error interceptors) for a non-2xx
948
967
  * response under `throwOnError`.
949
968
  */
950
- async function settleResult({ result, codecs, throwOnError, validator, errorInterceptors }) {
969
+ async function settleResult({ result, request, codecs, throwOnError, validator, onValidationError, errorInterceptors }) {
951
970
  const isSuccess = result.status >= 200 && result.status < 300;
952
971
  const contentType = result.contentType ?? getResponseContentType(result.headers);
953
972
  let decoded = result.data;
@@ -955,8 +974,21 @@ async function settleResult({ result, codecs, throwOnError, validator, errorInte
955
974
  const codec = codecs[contentType];
956
975
  if (codec?.deserialize) decoded = await codec.deserialize(result.data, contentType);
957
976
  }
977
+ const validationContext = {
978
+ method: request.method,
979
+ url: request.url,
980
+ status: result.status
981
+ };
958
982
  if (isSuccess) {
959
- const data = await runValidator(validator?.response, decoded);
983
+ const data = await runValidator({
984
+ validator: validator?.response,
985
+ value: decoded,
986
+ context: {
987
+ direction: "response",
988
+ ...validationContext
989
+ },
990
+ onValidationError
991
+ });
960
992
  return {
961
993
  status: result.status,
962
994
  data,
@@ -966,7 +998,15 @@ async function settleResult({ result, codecs, throwOnError, validator, errorInte
966
998
  response: result.response
967
999
  };
968
1000
  }
969
- const error = await runValidator(validator?.error, decoded);
1001
+ const error = await runValidator({
1002
+ validator: validator?.error,
1003
+ value: decoded,
1004
+ context: {
1005
+ direction: "error",
1006
+ ...validationContext
1007
+ },
1008
+ onValidationError
1009
+ });
970
1010
  if (throwOnError) {
971
1011
  const responseError = new ResponseError({
972
1012
  data: error,
@@ -1008,9 +1048,11 @@ function createClientCore(options) {
1008
1048
  const resolvedRequest = await interceptors.request.run(request);
1009
1049
  return settleResult({
1010
1050
  result: await interceptors.response.run(await transport(resolvedRequest)),
1051
+ request: resolvedRequest,
1011
1052
  codecs,
1012
1053
  throwOnError: requestConfig.throwOnError ?? config.throwOnError ?? true,
1013
1054
  validator: requestConfig.validator,
1055
+ onValidationError: requestConfig.onValidationError ?? config.onValidationError,
1014
1056
  errorInterceptors: interceptors.error
1015
1057
  });
1016
1058
  });
@@ -5562,16 +5604,16 @@ const calendarDate = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, CALENDAR_DATE_MESSA
5562
5604
  const parsed = /* @__PURE__ */ new Date(`${value}T00:00:00.000Z`);
5563
5605
  return !Number.isNaN(parsed.getTime()) && parsed.toISOString().startsWith(value);
5564
5606
  }, CALENDAR_DATE_MESSAGE);
5565
- const rpeEnum = z.union([
5566
- z.literal(6),
5567
- z.literal(7),
5568
- z.literal(7.5),
5569
- z.literal(8),
5570
- z.literal(8.5),
5571
- z.literal(9),
5572
- z.literal(9.5),
5573
- z.literal(10)
5574
- ]);
5607
+ const rpeEnum = z.preprocess((val) => isFiniteNumber$1(val) ? String(val) : val, z.enum([
5608
+ "6",
5609
+ "7",
5610
+ "7.5",
5611
+ "8",
5612
+ "8.5",
5613
+ "9",
5614
+ "9.5",
5615
+ "10"
5616
+ ])).transform((val) => Number(val));
5575
5617
  const workoutSetFields = {
5576
5618
  type: setTypeEnum,
5577
5619
  weight_kg: z.coerce.number().optional().nullable(),
@@ -6685,7 +6727,7 @@ function readBuildGlobal(value) {
6685
6727
  }
6686
6728
  }
6687
6729
  const buildName = readBuildGlobal(() => "hevy-mcp");
6688
- const buildVersion = readBuildGlobal(() => "6.1.13");
6730
+ const buildVersion = readBuildGlobal(() => "6.1.14");
6689
6731
  const SERVER_NAME = readBuildString(buildName, "hevy-mcp");
6690
6732
  const SERVER_VERSION = readBuildString(buildVersion, "dev");
6691
6733
  const SERVER_INSTRUCTIONS = [
@@ -7253,4 +7295,4 @@ function assertApiKey(apiKey) {
7253
7295
  //#endregion
7254
7296
  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 };
7255
7297
 
7256
- //# sourceMappingURL=config-0fixupML.mjs.map
7298
+ //# sourceMappingURL=config-C3y5yJ8b.mjs.map
package/dist/index.d.mts CHANGED
@@ -17,8 +17,14 @@ interface NodeLifecycleHandle {
17
17
  * telemetry, or connect a transport. The embedding application owns those
18
18
  * concerns and the transport lifecycle.
19
19
  */
20
- export declare function createNodeMcpServer({ apiKey }: {
20
+ export declare function createNodeMcpServer({ apiKey, maxGetRetries }: {
21
21
  apiKey: string;
22
+ /**
23
+ * Client retry budget (also applies to PUT). Set to 0 to disable all
24
+ * automatic request retries; reconcile uncertain writes before retrying.
25
+ * Omit to retain the client's existing retry policy.
26
+ */
27
+ maxGetRetries?: number;
22
28
  }, _transport?: NodeTransport, lifecycleSignal?: AbortSignal): Promise<import("@modelcontextprotocol/server").McpServer>;
23
29
  /**
24
30
  * Compatibility wrapper for the executable runtime. Importing this module
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-0fixupML.mjs";
4
+ import { d as createHevyClient, i as createHevyMcpServer, n as assertApiKey } from "./config-C3y5yJ8b.mjs";
5
5
  //#region src/index.ts
6
6
  /**
7
7
  * Create an unconnected MCP server for embedding in a Node application.
@@ -11,12 +11,13 @@ import { d as createHevyClient, i as createHevyMcpServer, n as assertApiKey } fr
11
11
  * telemetry, or connect a transport. The embedding application owns those
12
12
  * concerns and the transport lifecycle.
13
13
  */
14
- async function createNodeMcpServer({ apiKey }, _transport = "stdio", lifecycleSignal) {
14
+ async function createNodeMcpServer({ apiKey, maxGetRetries }, _transport = "stdio", lifecycleSignal) {
15
15
  assertApiKey(apiKey);
16
16
  return await createHevyMcpServer({
17
17
  createClient: ({ onLog }) => createHevyClient({
18
18
  apiKey,
19
- onLog
19
+ onLog,
20
+ ...maxGetRetries === void 0 ? {} : { maxGetRetries }
20
21
  }),
21
22
  lifecycleSignal
22
23
  });
@@ -26,7 +27,7 @@ async function createNodeMcpServer({ apiKey }, _transport = "stdio", lifecycleSi
26
27
  * does not evaluate the runtime bootstrap; it is loaded only when invoked.
27
28
  */
28
29
  async function runStdioServer() {
29
- const { runStdioServer: run } = await import("./runtime-DZnkDB92.mjs").then((n) => n.n);
30
+ const { runStdioServer: run } = await import("./runtime-Dkm4I9j5.mjs").then((n) => n.n);
30
31
  return run();
31
32
  }
32
33
  /**
@@ -34,7 +35,7 @@ async function runStdioServer() {
34
35
  * does not evaluate the runtime bootstrap; it is loaded only when invoked.
35
36
  */
36
37
  async function runServer() {
37
- const { runServer: run } = await import("./runtime-DZnkDB92.mjs").then((n) => n.n);
38
+ const { runServer: run } = await import("./runtime-Dkm4I9j5.mjs").then((n) => n.n);
38
39
  return run();
39
40
  }
40
41
  //#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] = "590b105c-b553-42c4-93bf-694cbacbccb1", e._sentryDebugIdIdentifier = "sentry-dbid-590b105c-b553-42c4-93bf-694cbacbccb1");
8
+ n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "cd83062e-356a-42d7-888c-2b912349753c", e._sentryDebugIdIdentifier = "sentry-dbid-cd83062e-356a-42d7-888c-2b912349753c");
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-0fixupML.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-C3y5yJ8b.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.13"), "dev");
413
+ const version$1 = parseBuildString(readBuildGlobal(() => "6.1.14"), "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-DZnkDB92.mjs.map
2961
+ //# sourceMappingURL=runtime-Dkm4I9j5.mjs.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hevy-mcp",
3
- "version": "6.1.13",
3
+ "version": "6.1.14",
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,8 +43,8 @@
43
43
  "zod": "^4.6.5"
44
44
  },
45
45
  "devDependencies": {
46
- "@hevy-mcp/core": "0.2.12",
47
- "@hevy-mcp/hevy-client": "0.2.8",
46
+ "@hevy-mcp/core": "0.2.13",
47
+ "@hevy-mcp/hevy-client": "0.2.9",
48
48
  "@sentry/core": "^10.74.0",
49
49
  "@types/node": "^26.5.1",
50
50
  "cross-env": "^10.1.0",
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.13",
10
+ "version": "6.1.14",
11
11
  "packages": [
12
12
  {
13
13
  "registryType": "npm",
14
14
  "identifier": "hevy-mcp",
15
- "version": "6.1.13",
15
+ "version": "6.1.14",
16
16
  "transport": {
17
17
  "type": "stdio"
18
18
  },