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-
|
|
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(
|
|
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
|
-
|
|
5308
|
-
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
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) =>
|
|
5315
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
|
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.
|
|
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-
|
|
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-
|
|
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-
|
|
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-
|
|
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] = "
|
|
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-
|
|
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.
|
|
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-
|
|
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.
|
|
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.
|
|
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.
|
|
10
|
+
"version": "6.1.13",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "hevy-mcp",
|
|
15
|
-
"version": "6.1.
|
|
15
|
+
"version": "6.1.13",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
},
|