hevy-mcp 4.1.1 → 4.1.3
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/cli.mjs +2 -2
- package/dist/index.d.mts +1 -1
- package/dist/index.mjs +2 -2
- package/dist/{src-BPbLELQf.mjs → src-CBiQ6f-q.mjs} +53 -51
- package/package.json +14 -13
- package/server.json +2 -2
package/dist/cli.mjs
CHANGED
|
@@ -4,12 +4,12 @@
|
|
|
4
4
|
(function() {
|
|
5
5
|
try {
|
|
6
6
|
var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {};
|
|
7
|
-
e.SENTRY_RELEASE = { id: "hevy-mcp@4.1.
|
|
7
|
+
e.SENTRY_RELEASE = { id: "hevy-mcp@4.1.3" };
|
|
8
8
|
var n = new e.Error().stack;
|
|
9
9
|
n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "625c4c9c-e20d-40b3-96b1-4e799ef130f3", e._sentryDebugIdIdentifier = "sentry-dbid-625c4c9c-e20d-40b3-96b1-4e799ef130f3");
|
|
10
10
|
} catch (e) {}
|
|
11
11
|
})();
|
|
12
|
-
import { a as createSafeErrorDiagnostic, i as MissingHevyApiKeyError, n as runServer, o as flushTelemetry } from "./src-
|
|
12
|
+
import { a as createSafeErrorDiagnostic, i as MissingHevyApiKeyError, n as runServer, o as flushTelemetry } from "./src-CBiQ6f-q.mjs";
|
|
13
13
|
//#region src/cli.ts
|
|
14
14
|
runServer().catch(async (error) => {
|
|
15
15
|
if (error instanceof MissingHevyApiKeyError) console.error(error.message);
|
package/dist/index.d.mts
CHANGED
|
@@ -5,7 +5,7 @@ type NodeTransport = "stdio" | "http";
|
|
|
5
5
|
//#region src/index.d.ts
|
|
6
6
|
declare function createNodeMcpServer({ apiKey }: {
|
|
7
7
|
apiKey: string;
|
|
8
|
-
}, transport?: NodeTransport): Promise<import("@modelcontextprotocol/
|
|
8
|
+
}, transport?: NodeTransport): Promise<import("@modelcontextprotocol/server").McpServer>;
|
|
9
9
|
declare function runStdioServer(): Promise<void>;
|
|
10
10
|
declare function runServer(): Promise<void>;
|
|
11
11
|
//#endregion
|
package/dist/index.mjs
CHANGED
|
@@ -4,10 +4,10 @@
|
|
|
4
4
|
(function() {
|
|
5
5
|
try {
|
|
6
6
|
var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {};
|
|
7
|
-
e.SENTRY_RELEASE = { id: "hevy-mcp@4.1.
|
|
7
|
+
e.SENTRY_RELEASE = { id: "hevy-mcp@4.1.3" };
|
|
8
8
|
var n = new e.Error().stack;
|
|
9
9
|
n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "e9496b31-626b-4ad1-9416-47ba4ffd2995", e._sentryDebugIdIdentifier = "sentry-dbid-e9496b31-626b-4ad1-9416-47ba4ffd2995");
|
|
10
10
|
} catch (e) {}
|
|
11
11
|
})();
|
|
12
|
-
import { n as runServer, r as runStdioServer, t as createNodeMcpServer } from "./src-
|
|
12
|
+
import { n as runServer, r as runStdioServer, t as createNodeMcpServer } from "./src-CBiQ6f-q.mjs";
|
|
13
13
|
export { createNodeMcpServer, runServer, runStdioServer };
|
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
(function() {
|
|
5
5
|
try {
|
|
6
6
|
var e = "undefined" != typeof window ? window : "undefined" != typeof global ? global : "undefined" != typeof globalThis ? globalThis : "undefined" != typeof self ? self : {};
|
|
7
|
-
e.SENTRY_RELEASE = { id: "hevy-mcp@4.1.
|
|
7
|
+
e.SENTRY_RELEASE = { id: "hevy-mcp@4.1.3" };
|
|
8
8
|
var n = new e.Error().stack;
|
|
9
|
-
n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "
|
|
9
|
+
n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "112c763b-1652-4fb5-8237-94b6a8ef1122", e._sentryDebugIdIdentifier = "sentry-dbid-112c763b-1652-4fb5-8237-94b6a8ef1122");
|
|
10
10
|
} catch (e) {}
|
|
11
11
|
})();
|
|
12
12
|
import { createHmac, randomUUID, timingSafeEqual } from "node:crypto";
|
|
@@ -19,15 +19,14 @@ import { resourceFromAttributes } from "@opentelemetry/resources";
|
|
|
19
19
|
import { BatchSpanProcessor } from "@opentelemetry/sdk-trace-base";
|
|
20
20
|
import { NodeTracerProvider } from "@opentelemetry/sdk-trace-node";
|
|
21
21
|
import { MeterProvider, PeriodicExportingMetricReader } from "@opentelemetry/sdk-metrics";
|
|
22
|
-
import { StdioServerTransport } from "@modelcontextprotocol/
|
|
22
|
+
import { StdioServerTransport } from "@modelcontextprotocol/server/stdio";
|
|
23
23
|
import { z } from "zod";
|
|
24
|
-
import { McpServer } from "@modelcontextprotocol/
|
|
24
|
+
import { McpServer, deserializeMessage } from "@modelcontextprotocol/server";
|
|
25
25
|
import { z as z$1 } from "zod/v4";
|
|
26
26
|
import { isIP } from "node:net";
|
|
27
27
|
import { createServer } from "node:http";
|
|
28
|
-
import {
|
|
28
|
+
import { NodeStreamableHTTPServerTransport } from "@modelcontextprotocol/node";
|
|
29
29
|
import { AsyncLocalStorage } from "node:async_hooks";
|
|
30
|
-
import { deserializeMessage } from "@modelcontextprotocol/sdk/shared/stdio.js";
|
|
31
30
|
import { mkdir, readFile, rename, unlink, writeFile } from "node:fs/promises";
|
|
32
31
|
import { homedir } from "node:os";
|
|
33
32
|
import { dirname, join } from "node:path";
|
|
@@ -81,11 +80,11 @@ function sanitizeSentryMcpSpan(span) {
|
|
|
81
80
|
* OTel Collector → Honeycomb: performance traces, metrics
|
|
82
81
|
*/
|
|
83
82
|
const name$1 = "hevy-mcp";
|
|
84
|
-
const version$1 = "4.1.
|
|
83
|
+
const version$1 = "4.1.3";
|
|
85
84
|
const telemetryEnabled = process.env.HEVY_MCP_TELEMETRY !== "0";
|
|
86
85
|
const collectorToken = "NH9vOela-HYreQxAbJa68cjEmORoEKM57EvneUDVcOo";
|
|
87
86
|
const COLLECTOR_ENDPOINT = "https://otel.chrisdoc.dev/v1";
|
|
88
|
-
const sentryRelease = process.env.SENTRY_RELEASE ?? `hevy-mcp@4.1.
|
|
87
|
+
const sentryRelease = process.env.SENTRY_RELEASE ?? `hevy-mcp@4.1.3`;
|
|
89
88
|
const resource = resourceFromAttributes({
|
|
90
89
|
"service.name": name$1,
|
|
91
90
|
"service.version": version$1
|
|
@@ -220,10 +219,15 @@ function coerceNullishNumberInput(value) {
|
|
|
220
219
|
}
|
|
221
220
|
const zNullableInt = z.preprocess(coerceNullishNumberInput, z.number().int().nullable().optional());
|
|
222
221
|
const zNullableNumber = z.preprocess((value) => value === "" ? void 0 : value, z.coerce.number().nullable().optional());
|
|
223
|
-
const
|
|
222
|
+
const repRangeShape = {
|
|
224
223
|
start: zNullableInt,
|
|
225
224
|
end: zNullableInt
|
|
226
|
-
}
|
|
225
|
+
};
|
|
226
|
+
function optionalRepRangeSchema(schema) {
|
|
227
|
+
return z.preprocess((value) => value === null ? void 0 : value, schema);
|
|
228
|
+
}
|
|
229
|
+
const zOptionalRepRange = optionalRepRangeSchema(z.object(repRangeShape).optional());
|
|
230
|
+
optionalRepRangeSchema(z.object(repRangeShape).strict().optional());
|
|
227
231
|
const setTypeEnum = z.enum([
|
|
228
232
|
"warmup",
|
|
229
233
|
"normal",
|
|
@@ -1502,7 +1506,7 @@ function registerWorkoutPrompts(server, observer) {
|
|
|
1502
1506
|
server.registerPrompt("analyze-workout-progress", {
|
|
1503
1507
|
title: "Analyze Workout Progress",
|
|
1504
1508
|
description: "Analyze recent workout and body-measurement trends.",
|
|
1505
|
-
argsSchema: { weeks: z.coerce.number().int().min(1).max(12).default(4).optional().describe("Number of recent weeks to analyze (1-12).") }
|
|
1509
|
+
argsSchema: z.object({ weeks: z.coerce.number().int().min(1).max(12).default(4).optional().describe("Number of recent weeks to analyze (1-12).") })
|
|
1506
1510
|
}, withPromptObservation("analyze-workout-progress", observer, ({ weeks = 4 }) => ({ messages: [{
|
|
1507
1511
|
role: "user",
|
|
1508
1512
|
content: {
|
|
@@ -1519,10 +1523,10 @@ function registerWorkoutPrompts(server, observer) {
|
|
|
1519
1523
|
server.registerPrompt("create-workout-from-routine", {
|
|
1520
1524
|
title: "Create Workout From Routine",
|
|
1521
1525
|
description: "Create a completed workout from an existing routine.",
|
|
1522
|
-
argsSchema: {
|
|
1526
|
+
argsSchema: z.object({
|
|
1523
1527
|
routineId: z.string().min(1).optional().describe("Routine ID to use as a guide."),
|
|
1524
1528
|
startTime: utcSecondTimestamp.optional().describe("Workout start time in UTC as YYYY-MM-DDTHH:mm:ssZ.")
|
|
1525
|
-
}
|
|
1529
|
+
})
|
|
1526
1530
|
}, withPromptObservation("create-workout-from-routine", observer, ({ routineId, startTime }) => ({ messages: [{
|
|
1527
1531
|
role: "user",
|
|
1528
1532
|
content: {
|
|
@@ -2595,7 +2599,7 @@ function registerHevyResources(server, runtime) {
|
|
|
2595
2599
|
//#endregion
|
|
2596
2600
|
//#region ../core/src/server-metadata.ts
|
|
2597
2601
|
const SERVER_NAME = "hevy-mcp";
|
|
2598
|
-
const SERVER_VERSION = "4.1.
|
|
2602
|
+
const SERVER_VERSION = "4.1.3";
|
|
2599
2603
|
const SERVER_INSTRUCTIONS = [
|
|
2600
2604
|
"Hevy MCP connects clients to the authenticated user's Hevy workout-tracking data, including workouts, routines, exercise templates, routine folders, body measurements, and profile information. HEVY_API_KEY must contain a valid Hevy API key for local stdio use.",
|
|
2601
2605
|
"Safety: all get-* and search-* tools are read-only. create-* and update-* tools mutate Hevy data. Creates are additive and non-idempotent, so repeating one can create duplicates. Updates can overwrite existing data. Delete operations are not available.",
|
|
@@ -2655,16 +2659,13 @@ function registerToolDefinition(server, runtime, definition) {
|
|
|
2655
2659
|
kind: definition.kind,
|
|
2656
2660
|
operation: definition.operation
|
|
2657
2661
|
});
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
|
|
2661
|
-
|
|
2662
|
-
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
return;
|
|
2666
|
-
}
|
|
2667
|
-
server.tool(definition.name, definition.description, definition.inputSchema, definition.annotations, callback);
|
|
2662
|
+
const config = {
|
|
2663
|
+
description: definition.description,
|
|
2664
|
+
inputSchema: z.object(definition.inputSchema),
|
|
2665
|
+
annotations: definition.annotations,
|
|
2666
|
+
...definition.kind === "read" ? { outputSchema: z.object(definition.outputSchema) } : {}
|
|
2667
|
+
};
|
|
2668
|
+
server.registerTool(definition.name, config, callback);
|
|
2668
2669
|
}
|
|
2669
2670
|
//#endregion
|
|
2670
2671
|
//#region ../core/src/utils/tool-annotations.ts
|
|
@@ -2740,6 +2741,14 @@ function paginationShape({ defaultPageSize, maxPageSize, integerPage = true }) {
|
|
|
2740
2741
|
};
|
|
2741
2742
|
}
|
|
2742
2743
|
const nonEmptyId = z.string().min(1);
|
|
2744
|
+
const exerciseTemplateInputShape = {
|
|
2745
|
+
title: z.string().min(1),
|
|
2746
|
+
exerciseType: exerciseTypeEnum,
|
|
2747
|
+
equipmentCategory: equipmentCategoryEnum,
|
|
2748
|
+
muscleGroup: muscleGroupEnum,
|
|
2749
|
+
otherMuscles: z.array(muscleGroupEnum).default([])
|
|
2750
|
+
};
|
|
2751
|
+
const routineFolderInputShape = { name: z.string().min(1) };
|
|
2743
2752
|
const CALENDAR_DATE_MESSAGE = "Date must be in YYYY-MM-DD format";
|
|
2744
2753
|
const calendarDate = z.string().regex(/^\d{4}-\d{2}-\d{2}$/, CALENDAR_DATE_MESSAGE).refine((value) => {
|
|
2745
2754
|
const parsed = /* @__PURE__ */ new Date(`${value}T00:00:00.000Z`);
|
|
@@ -2940,6 +2949,18 @@ function buildMeasurementPayload(fields) {
|
|
|
2940
2949
|
}
|
|
2941
2950
|
return payload;
|
|
2942
2951
|
}
|
|
2952
|
+
function buildExerciseTemplateRequest(input) {
|
|
2953
|
+
return { exercise: {
|
|
2954
|
+
title: input.title,
|
|
2955
|
+
exercise_type: input.exerciseType,
|
|
2956
|
+
equipment_category: input.equipmentCategory,
|
|
2957
|
+
muscle_group: input.muscleGroup,
|
|
2958
|
+
other_muscles: input.otherMuscles
|
|
2959
|
+
} };
|
|
2960
|
+
}
|
|
2961
|
+
function buildRoutineFolderRequest(input) {
|
|
2962
|
+
return { routine_folder: { title: input.name } };
|
|
2963
|
+
}
|
|
2943
2964
|
//#endregion
|
|
2944
2965
|
//#region ../core/src/utils/hevy-error-policy.ts
|
|
2945
2966
|
const READ_RESOURCE_ENDPOINTS = /* @__PURE__ */ new Set([
|
|
@@ -3119,7 +3140,7 @@ const getRoutineFoldersSchema = paginationShape({
|
|
|
3119
3140
|
maxPageSize: 10
|
|
3120
3141
|
});
|
|
3121
3142
|
const getRoutineFolderSchema = { folderId: nonEmptyId };
|
|
3122
|
-
const createRoutineFolderSchema =
|
|
3143
|
+
const createRoutineFolderSchema = routineFolderInputShape;
|
|
3123
3144
|
const folderToolDefinitions = [
|
|
3124
3145
|
{
|
|
3125
3146
|
name: "get-routine-folders",
|
|
@@ -3217,8 +3238,7 @@ const folderToolDefinitions = [
|
|
|
3217
3238
|
kind: "write",
|
|
3218
3239
|
responseContract: createRoutineFolderResponse,
|
|
3219
3240
|
execute: async (runtime, args) => {
|
|
3220
|
-
|
|
3221
|
-
return runtime.getClient().createRoutineFolder({ routine_folder: { title: name } });
|
|
3241
|
+
return runtime.getClient().createRoutineFolder(buildRoutineFolderRequest(args));
|
|
3222
3242
|
}
|
|
3223
3243
|
}
|
|
3224
3244
|
];
|
|
@@ -3383,13 +3403,7 @@ const getExerciseHistorySchema = {
|
|
|
3383
3403
|
startDate: z.string().datetime({ offset: true }).describe("ISO 8601 start date for filtering history").optional(),
|
|
3384
3404
|
endDate: z.string().datetime({ offset: true }).describe("ISO 8601 end date for filtering history").optional()
|
|
3385
3405
|
};
|
|
3386
|
-
const createExerciseTemplateSchema =
|
|
3387
|
-
title: z.string().min(1),
|
|
3388
|
-
exerciseType: exerciseTypeEnum,
|
|
3389
|
-
equipmentCategory: equipmentCategoryEnum,
|
|
3390
|
-
muscleGroup: muscleGroupEnum,
|
|
3391
|
-
otherMuscles: z.array(muscleGroupEnum).default([])
|
|
3392
|
-
};
|
|
3406
|
+
const createExerciseTemplateSchema = exerciseTemplateInputShape;
|
|
3393
3407
|
const searchExerciseTemplatesSchema = {
|
|
3394
3408
|
query: z.string().min(1).describe("Case-insensitive substring to match against exercise template titles"),
|
|
3395
3409
|
primaryMuscleGroup: muscleGroupEnum.optional().describe("Optional filter to restrict results to a specific primary muscle group"),
|
|
@@ -3523,14 +3537,7 @@ const templateToolDefinitions = [
|
|
|
3523
3537
|
kind: "write",
|
|
3524
3538
|
responseContract: createExerciseTemplateResponse,
|
|
3525
3539
|
execute: async (runtime, args) => {
|
|
3526
|
-
|
|
3527
|
-
return await runtime.getClient().createExerciseTemplate({ exercise: {
|
|
3528
|
-
title,
|
|
3529
|
-
exercise_type: exerciseType,
|
|
3530
|
-
equipment_category: equipmentCategory,
|
|
3531
|
-
muscle_group: muscleGroup,
|
|
3532
|
-
other_muscles: otherMuscles
|
|
3533
|
-
} });
|
|
3540
|
+
return runtime.getClient().createExerciseTemplate(buildExerciseTemplateRequest(args));
|
|
3534
3541
|
}
|
|
3535
3542
|
},
|
|
3536
3543
|
{
|
|
@@ -4388,18 +4395,13 @@ function createCountingServer(server) {
|
|
|
4388
4395
|
let count = 0;
|
|
4389
4396
|
return {
|
|
4390
4397
|
server: new Proxy(server, { get(target, property, receiver) {
|
|
4391
|
-
if (property === "tool") return (...args) => {
|
|
4392
|
-
const result = target.tool(...args);
|
|
4393
|
-
count += 1;
|
|
4394
|
-
return result;
|
|
4395
|
-
};
|
|
4396
4398
|
if (property === "registerTool") {
|
|
4397
|
-
const registerTool = (
|
|
4398
|
-
|
|
4399
|
+
const registerTool = target.registerTool.bind(target);
|
|
4400
|
+
return (...args) => {
|
|
4401
|
+
const result = Reflect.apply(registerTool, target, args);
|
|
4399
4402
|
count += 1;
|
|
4400
4403
|
return result;
|
|
4401
4404
|
};
|
|
4402
|
-
return registerTool;
|
|
4403
4405
|
}
|
|
4404
4406
|
return Reflect.get(target, property, receiver);
|
|
4405
4407
|
} }),
|
|
@@ -4801,7 +4803,7 @@ async function startStreamableHttpServer(options, apiKey, createMcpServer) {
|
|
|
4801
4803
|
let session;
|
|
4802
4804
|
let mcpServer;
|
|
4803
4805
|
let connected = false;
|
|
4804
|
-
const transport = new
|
|
4806
|
+
const transport = new NodeStreamableHTTPServerTransport({
|
|
4805
4807
|
sessionIdGenerator: randomUUID,
|
|
4806
4808
|
onsessioninitialized: (id) => {
|
|
4807
4809
|
if (session) sessions.set(id, session);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "hevy-mcp",
|
|
3
|
-
"version": "4.1.
|
|
3
|
+
"version": "4.1.3",
|
|
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": {
|
|
@@ -34,25 +34,26 @@
|
|
|
34
34
|
"build:standalone": "cross-env HEVY_MCP_BUILD_MODE=standalone tsdown -c tsdown.config.ts"
|
|
35
35
|
},
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@modelcontextprotocol/
|
|
38
|
-
"@
|
|
39
|
-
"@opentelemetry/
|
|
40
|
-
"@opentelemetry/exporter-
|
|
41
|
-
"@opentelemetry/
|
|
42
|
-
"@opentelemetry/
|
|
43
|
-
"@opentelemetry/sdk-
|
|
44
|
-
"@opentelemetry/sdk-trace-
|
|
45
|
-
"@
|
|
46
|
-
"@sentry/
|
|
37
|
+
"@modelcontextprotocol/node": "^2.0.0",
|
|
38
|
+
"@modelcontextprotocol/server": "^2.0.0",
|
|
39
|
+
"@opentelemetry/api": "^1.9.1",
|
|
40
|
+
"@opentelemetry/exporter-metrics-otlp-http": "^0.221.0",
|
|
41
|
+
"@opentelemetry/exporter-trace-otlp-http": "^0.221.0",
|
|
42
|
+
"@opentelemetry/resources": "^2.10.0",
|
|
43
|
+
"@opentelemetry/sdk-metrics": "^2.10.0",
|
|
44
|
+
"@opentelemetry/sdk-trace-base": "^2.10.0",
|
|
45
|
+
"@opentelemetry/sdk-trace-node": "^2.10.0",
|
|
46
|
+
"@sentry/node": "^10.68.0",
|
|
47
|
+
"@sentry/opentelemetry": "^10.68.0",
|
|
47
48
|
"semver": "^7.8.5",
|
|
48
49
|
"zod": "^4.4.3"
|
|
49
50
|
},
|
|
50
51
|
"devDependencies": {
|
|
51
52
|
"@hevy-mcp/core": "*",
|
|
52
53
|
"@hevy-mcp/hevy-client": "*",
|
|
53
|
-
"@types/node": "^26.
|
|
54
|
+
"@types/node": "^26.1.1",
|
|
54
55
|
"cross-env": "^10.1.0",
|
|
55
|
-
"tsdown": "^0.22.
|
|
56
|
+
"tsdown": "^0.22.14",
|
|
56
57
|
"typescript": "^7.0.2"
|
|
57
58
|
},
|
|
58
59
|
"engines": {
|
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": "4.1.
|
|
10
|
+
"version": "4.1.3",
|
|
11
11
|
"packages": [
|
|
12
12
|
{
|
|
13
13
|
"registryType": "npm",
|
|
14
14
|
"identifier": "hevy-mcp",
|
|
15
|
-
"version": "4.1.
|
|
15
|
+
"version": "4.1.3",
|
|
16
16
|
"transport": {
|
|
17
17
|
"type": "stdio"
|
|
18
18
|
},
|