hevy-mcp 1.13.0 → 1.13.2
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/README.md +24 -1
- package/dist/cli.js +35 -23
- package/dist/cli.js.map +1 -1
- package/dist/index.js +35 -23
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -15,11 +15,22 @@ A Model Context Protocol (MCP) server implementation that interfaces with the [H
|
|
|
15
15
|
|
|
16
16
|
> **Note:** HTTP transport and Docker images remain deprecated. Smithery deployment now uses the official TypeScript runtime flow (no Docker required), or you can run the server locally via stdio (e.g., `npx hevy-mcp`). Existing GHCR images remain available but are no longer updated.
|
|
17
17
|
|
|
18
|
+
## Quick start
|
|
19
|
+
|
|
20
|
+
Pick the workflow that fits your setup:
|
|
21
|
+
|
|
22
|
+
| Scenario | Command | Requirements |
|
|
23
|
+
| --- | --- | --- |
|
|
24
|
+
| One-off stdio run | `HEVY_API_KEY=sk_live... npx -y hevy-mcp` | Node.js ≥ 20, Hevy API key |
|
|
25
|
+
| Local development | `pnpm install && pnpm run dev` | `.env` with `HEVY_API_KEY`, pnpm via Corepack |
|
|
26
|
+
| Smithery playground / deploy | `pnpm run smithery:dev` / `pnpm run smithery:build` | `HEVY_API_KEY`, `SMITHERY_API_KEY` (or `pnpm dlx @smithery/cli login`) |
|
|
27
|
+
|
|
18
28
|
## Prerequisites
|
|
19
29
|
|
|
20
30
|
- Node.js (v20 or higher)
|
|
21
31
|
- pnpm (via Corepack)
|
|
22
32
|
- A Hevy API key
|
|
33
|
+
- Optional: A Smithery account + API key/login if you plan to deploy via Smithery
|
|
23
34
|
|
|
24
35
|
## Installation
|
|
25
36
|
|
|
@@ -39,8 +50,11 @@ cd hevy-mcp
|
|
|
39
50
|
|
|
40
51
|
# Install dependencies
|
|
41
52
|
corepack use pnpm@10.22.0
|
|
53
|
+
pnpm install
|
|
54
|
+
|
|
55
|
+
# Create .env and add your keys (never commit real keys)
|
|
42
56
|
cp .env.sample .env
|
|
43
|
-
# Edit .env and add
|
|
57
|
+
# Edit .env and add at least HEVY_API_KEY. Add SMITHERY_API_KEY if you use Smithery CLI.
|
|
44
58
|
```
|
|
45
59
|
|
|
46
60
|
### Integration with Cursor
|
|
@@ -104,6 +118,8 @@ Smithery can bundle and host `hevy-mcp` without Docker by importing the exported
|
|
|
104
118
|
|
|
105
119
|
4. Connect the repository to Smithery and trigger a deployment from their dashboard. Configuration is handled entirely through the exported Zod schema, so no additional `smithery.yaml` env mapping is required.
|
|
106
120
|
|
|
121
|
+
> **Why are `chalk`, `cors`, and `@smithery/sdk` dependencies?** Smithery’s TypeScript runtime injects its own Express bootstrap that imports these packages. Declaring them in `package.json` ensures the Smithery CLI can bundle your server successfully.
|
|
122
|
+
|
|
107
123
|
hevy-mcp now runs exclusively over stdio, which works seamlessly with MCP-aware clients like Claude Desktop and Cursor. HTTP transport has been removed to simplify deployment.
|
|
108
124
|
|
|
109
125
|
## Usage
|
|
@@ -265,6 +281,13 @@ Kubb generates TypeScript types, API clients, Zod schemas, and mock data from th
|
|
|
265
281
|
|
|
266
282
|
- **Rollup optional dependency missing**: If you see an error similar to `Cannot find module @rollup/rollup-linux-x64-gnu`, set the environment variable `ROLLUP_SKIP_NODEJS_NATIVE_BUILD=true` before running `pnpm run build`. This forces Rollup to use the pure JavaScript fallback and avoids the npm optional dependency bug on some Linux runners.
|
|
267
283
|
|
|
284
|
+
### Troubleshooting Smithery deployments
|
|
285
|
+
|
|
286
|
+
- **`smithery.yaml` validation failed (unexpected fields)**: Only `runtime`, `target`, and `env` are allowed for the TypeScript runtime. Remove `entry`, `name`, or other fields.
|
|
287
|
+
- **`Could not resolve "chalk"/"cors"`**: Run `pnpm install` so the runtime dependencies listed in `package.json` are present before invoking Smithery.
|
|
288
|
+
- **`Failed to connect to Smithery API: Unauthorized`**: Log in via `pnpm dlx @smithery/cli login` or set `SMITHERY_API_KEY` in `.env`.
|
|
289
|
+
- **Tunnel crashes with `RangeError: Invalid count value`**: This is a known issue in certain `@smithery/cli` builds. Upgrade/downgrade the CLI (e.g., `pnpm add -D @smithery/cli@latest`) or contact Smithery support.
|
|
290
|
+
|
|
268
291
|
## License
|
|
269
292
|
|
|
270
293
|
This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.
|
package/dist/cli.js
CHANGED
|
@@ -10,7 +10,7 @@ import { z as z6 } from "zod";
|
|
|
10
10
|
|
|
11
11
|
// package.json
|
|
12
12
|
var name = "hevy-mcp";
|
|
13
|
-
var version = "1.
|
|
13
|
+
var version = "1.13.1";
|
|
14
14
|
|
|
15
15
|
// src/tools/folders.ts
|
|
16
16
|
import { z } from "zod";
|
|
@@ -343,9 +343,12 @@ function registerRoutineTools(server, hevyClient) {
|
|
|
343
343
|
sets: z2.array(
|
|
344
344
|
z2.object({
|
|
345
345
|
type: z2.enum(["warmup", "normal", "failure", "dropset"]).default("normal"),
|
|
346
|
+
weight: z2.coerce.number().optional(),
|
|
346
347
|
weightKg: z2.coerce.number().optional(),
|
|
347
348
|
reps: z2.coerce.number().int().optional(),
|
|
349
|
+
distance: z2.coerce.number().int().optional(),
|
|
348
350
|
distanceMeters: z2.coerce.number().int().optional(),
|
|
351
|
+
duration: z2.coerce.number().int().optional(),
|
|
349
352
|
durationSeconds: z2.coerce.number().int().optional(),
|
|
350
353
|
customMetric: z2.coerce.number().optional()
|
|
351
354
|
})
|
|
@@ -378,10 +381,10 @@ function registerRoutineTools(server, hevyClient) {
|
|
|
378
381
|
sets: exercise.sets.map(
|
|
379
382
|
(set) => ({
|
|
380
383
|
type: set.type,
|
|
381
|
-
weight_kg: set.weightKg ?? null,
|
|
384
|
+
weight_kg: set.weight ?? set.weightKg ?? null,
|
|
382
385
|
reps: set.reps ?? null,
|
|
383
|
-
distance_meters: set.distanceMeters ?? null,
|
|
384
|
-
duration_seconds: set.durationSeconds ?? null,
|
|
386
|
+
distance_meters: set.distance ?? set.distanceMeters ?? null,
|
|
387
|
+
duration_seconds: set.duration ?? set.durationSeconds ?? null,
|
|
385
388
|
custom_metric: set.customMetric ?? null
|
|
386
389
|
})
|
|
387
390
|
)
|
|
@@ -414,9 +417,12 @@ function registerRoutineTools(server, hevyClient) {
|
|
|
414
417
|
sets: z2.array(
|
|
415
418
|
z2.object({
|
|
416
419
|
type: z2.enum(["warmup", "normal", "failure", "dropset"]).default("normal"),
|
|
420
|
+
weight: z2.coerce.number().optional(),
|
|
417
421
|
weightKg: z2.coerce.number().optional(),
|
|
418
422
|
reps: z2.coerce.number().int().optional(),
|
|
423
|
+
distance: z2.coerce.number().int().optional(),
|
|
419
424
|
distanceMeters: z2.coerce.number().int().optional(),
|
|
425
|
+
duration: z2.coerce.number().int().optional(),
|
|
420
426
|
durationSeconds: z2.coerce.number().int().optional(),
|
|
421
427
|
customMetric: z2.coerce.number().optional()
|
|
422
428
|
})
|
|
@@ -448,10 +454,10 @@ function registerRoutineTools(server, hevyClient) {
|
|
|
448
454
|
sets: exercise.sets.map(
|
|
449
455
|
(set) => ({
|
|
450
456
|
type: set.type,
|
|
451
|
-
weight_kg: set.weightKg ?? null,
|
|
457
|
+
weight_kg: set.weight ?? set.weightKg ?? null,
|
|
452
458
|
reps: set.reps ?? null,
|
|
453
|
-
distance_meters: set.distanceMeters ?? null,
|
|
454
|
-
duration_seconds: set.durationSeconds ?? null,
|
|
459
|
+
distance_meters: set.distance ?? set.distanceMeters ?? null,
|
|
460
|
+
duration_seconds: set.duration ?? set.durationSeconds ?? null,
|
|
455
461
|
custom_metric: set.customMetric ?? null
|
|
456
462
|
})
|
|
457
463
|
)
|
|
@@ -762,9 +768,12 @@ function registerWorkoutTools(server, hevyClient) {
|
|
|
762
768
|
sets: z5.array(
|
|
763
769
|
z5.object({
|
|
764
770
|
type: z5.enum(["warmup", "normal", "failure", "dropset"]).default("normal"),
|
|
771
|
+
weight: z5.coerce.number().optional().nullable(),
|
|
765
772
|
weightKg: z5.coerce.number().optional().nullable(),
|
|
766
773
|
reps: z5.coerce.number().int().optional().nullable(),
|
|
774
|
+
distance: z5.coerce.number().int().optional().nullable(),
|
|
767
775
|
distanceMeters: z5.coerce.number().int().optional().nullable(),
|
|
776
|
+
duration: z5.coerce.number().int().optional().nullable(),
|
|
768
777
|
durationSeconds: z5.coerce.number().int().optional().nullable(),
|
|
769
778
|
rpe: z5.coerce.number().optional().nullable(),
|
|
770
779
|
customMetric: z5.coerce.number().optional().nullable()
|
|
@@ -794,16 +803,16 @@ function registerWorkoutTools(server, hevyClient) {
|
|
|
794
803
|
exercises: exercises.map(
|
|
795
804
|
(exercise) => ({
|
|
796
805
|
exercise_template_id: exercise.exerciseTemplateId,
|
|
797
|
-
superset_id: exercise.supersetId
|
|
798
|
-
notes: exercise.notes
|
|
806
|
+
superset_id: exercise.supersetId ?? null,
|
|
807
|
+
notes: exercise.notes ?? null,
|
|
799
808
|
sets: exercise.sets.map((set) => ({
|
|
800
809
|
type: set.type,
|
|
801
|
-
weight_kg: set.weightKg
|
|
802
|
-
reps: set.reps
|
|
803
|
-
distance_meters: set.distanceMeters
|
|
804
|
-
duration_seconds: set.durationSeconds
|
|
805
|
-
rpe: set.rpe
|
|
806
|
-
custom_metric: set.customMetric
|
|
810
|
+
weight_kg: set.weight ?? set.weightKg ?? null,
|
|
811
|
+
reps: set.reps ?? null,
|
|
812
|
+
distance_meters: set.distance ?? set.distanceMeters ?? null,
|
|
813
|
+
duration_seconds: set.duration ?? set.durationSeconds ?? null,
|
|
814
|
+
rpe: set.rpe ?? null,
|
|
815
|
+
custom_metric: set.customMetric ?? null
|
|
807
816
|
}))
|
|
808
817
|
})
|
|
809
818
|
)
|
|
@@ -837,9 +846,12 @@ function registerWorkoutTools(server, hevyClient) {
|
|
|
837
846
|
sets: z5.array(
|
|
838
847
|
z5.object({
|
|
839
848
|
type: z5.enum(["warmup", "normal", "failure", "dropset"]).default("normal"),
|
|
849
|
+
weight: z5.coerce.number().optional().nullable(),
|
|
840
850
|
weightKg: z5.coerce.number().optional().nullable(),
|
|
841
851
|
reps: z5.coerce.number().int().optional().nullable(),
|
|
852
|
+
distance: z5.coerce.number().int().optional().nullable(),
|
|
842
853
|
distanceMeters: z5.coerce.number().int().optional().nullable(),
|
|
854
|
+
duration: z5.coerce.number().int().optional().nullable(),
|
|
843
855
|
durationSeconds: z5.coerce.number().int().optional().nullable(),
|
|
844
856
|
rpe: z5.coerce.number().optional().nullable(),
|
|
845
857
|
customMetric: z5.coerce.number().optional().nullable()
|
|
@@ -877,16 +889,16 @@ function registerWorkoutTools(server, hevyClient) {
|
|
|
877
889
|
exercises: exercises.map(
|
|
878
890
|
(exercise) => ({
|
|
879
891
|
exercise_template_id: exercise.exerciseTemplateId,
|
|
880
|
-
superset_id: exercise.supersetId
|
|
881
|
-
notes: exercise.notes
|
|
892
|
+
superset_id: exercise.supersetId ?? null,
|
|
893
|
+
notes: exercise.notes ?? null,
|
|
882
894
|
sets: exercise.sets.map((set) => ({
|
|
883
895
|
type: set.type,
|
|
884
|
-
weight_kg: set.weightKg
|
|
885
|
-
reps: set.reps
|
|
886
|
-
distance_meters: set.distanceMeters
|
|
887
|
-
duration_seconds: set.durationSeconds
|
|
888
|
-
rpe: set.rpe
|
|
889
|
-
custom_metric: set.customMetric
|
|
896
|
+
weight_kg: set.weight ?? set.weightKg ?? null,
|
|
897
|
+
reps: set.reps ?? null,
|
|
898
|
+
distance_meters: set.distance ?? set.distanceMeters ?? null,
|
|
899
|
+
duration_seconds: set.duration ?? set.durationSeconds ?? null,
|
|
900
|
+
rpe: set.rpe ?? null,
|
|
901
|
+
custom_metric: set.customMetric ?? null
|
|
890
902
|
}))
|
|
891
903
|
})
|
|
892
904
|
)
|