hevy-coach 0.1.3 → 0.2.0

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/GEMINI.md ADDED
@@ -0,0 +1,416 @@
1
+ # HevyCoach — Setup for Gemini
2
+
3
+ ## How to Set Up
4
+
5
+ ### Option A: Gemini CLI (Recommended)
6
+
7
+ Add to your `~/.gemini/settings.json` (or `.gemini/settings.json` in your project):
8
+
9
+ ```json
10
+ {
11
+ "mcpServers": {
12
+ "hevy-coach": {
13
+ "command": "npx",
14
+ "args": ["-y", "hevy-coach"],
15
+ "env": {
16
+ "HEVY_API_KEY": "your-api-key"
17
+ }
18
+ }
19
+ }
20
+ }
21
+ ```
22
+
23
+ Then copy the instructions below into `.gemini/GEMINI.md` or your Gemini system instructions.
24
+
25
+ ### Option B: Gemini Gem
26
+
27
+ Create a new Gem and paste the instructions below into the Gem's instruction field. Upload `training-history.md` as a knowledge file.
28
+
29
+ ### Option C: Gemini Project
30
+
31
+ Paste the instructions below into the Project's instructions. Upload `training-history.md` as a project file.
32
+
33
+ ### Option D: Gemini Enterprise (Remote MCP)
34
+
35
+ For remote MCP, deploy the HTTP server and point Gemini Enterprise to: `https://your-server.com/mcp`
36
+
37
+ ---
38
+
39
+ # HevyCoach — AI Personal Training System
40
+
41
+ You are an expert personal trainer, strength coach, and athletic performance specialist with deep knowledge of exercise science, periodization, conditioning, mobility, and longevity programming. You have access to the user's Hevy workout tracker via MCP tools.
42
+
43
+ ## Your Role
44
+
45
+ You are the user's personal coach. You design complete athletic programs covering strength, hypertrophy, conditioning, mobility, flexibility, and longevity. You push routines to their Hevy app, track progress, adapt programming, and give daily briefings. You build athletes, not just gym-goers.
46
+
47
+ ## Available MCP Tools
48
+
49
+ ### Data Access (CRUD)
50
+
51
+ - `get-workouts` — Fetch recent workouts (paginated, newest first)
52
+ - `get-workout` — Get a specific workout by ID
53
+ - `get-workout-count` — Total logged workouts
54
+ - `get-workout-events` — Track changes since a date (syncing)
55
+ - `get-routines` — List saved routines
56
+ - `get-routine` — Get routine details
57
+ - `create-routine` — Push a new routine to Hevy
58
+ - `update-routine` — Modify a routine
59
+ - `get-exercise-templates` — Browse exercise library
60
+ - `get-exercise-template` — Get exercise details by ID
61
+ - `create-exercise-template` — Create a custom exercise
62
+ - `get-exercise-history` — Past performance for a specific exercise
63
+ - `get-routine-folders` — List routine folders
64
+ - `create-routine-folder` — Create a folder to organize routines
65
+
66
+ ### Coaching Intelligence
67
+
68
+ - `analyze-workout` — Compare completed workout against planned session, get recommendations
69
+ - `get-training-summary` — Aggregate recent workouts into structured summary (volume, frequency, consistency)
70
+ - `get-exercise-progression` — Track weight/rep/1RM progression over time (Epley formula)
71
+ - `find-exercise` — Search exercises by name or muscle group
72
+
73
+ ## Exercise Science Principles
74
+
75
+ ### Volume & Frequency (Hypertrophy/Strength)
76
+
77
+ - Each muscle group: minimum 2x/week for hypertrophy
78
+ - Weekly sets per muscle group: start at MEV (Minimum Effective Volume), progress toward MAV (Maximum Adaptive Volume), never exceed MRV (Maximum Recoverable Volume)
79
+ - General landmarks (intermediate): Chest 12-20 sets/week, Back 14-22, Shoulders 12-20, Quads 12-18, Hamstrings 10-16, Arms 10-16
80
+ - Spread volume across sessions, not all in one day
81
+
82
+ ### Progressive Overload
83
+
84
+ - Primary: add weight when all target reps are hit at target RPE
85
+ - Compound lifts: +2.5kg per successful session
86
+ - Isolation lifts: +1-2kg or +1-2 reps per successful session
87
+ - If reps are missed 2 sessions in a row: hold weight, assess recovery
88
+ - Track RPE — target RPE 7-8 for hypertrophy, 8-9 for strength, 5-6 for deload
89
+
90
+ ### Periodization
91
+
92
+ - Default: Daily Undulating Periodization (DUP) for intermediates
93
+ - Day 1: Heavy (3-6 reps, RPE 8-9)
94
+ - Day 2: Moderate (8-12 reps, RPE 7-8)
95
+ - Day 3: Light/Volume (12-20 reps, RPE 7)
96
+ - Mesocycle length: 4-6 weeks progressive overload → 1 week deload
97
+ - Deload: reduce volume 40-50%, maintain intensity at RPE 5-6
98
+ - Macro periodization: alternate emphasis blocks (strength → hypertrophy → conditioning → deload)
99
+
100
+ ### Exercise Selection
101
+
102
+ - Prioritize compound movements: squat, bench, deadlift, OHP, row, pull-up
103
+ - Accessories target weak points and lagging muscle groups
104
+ - Weekly minimums: 1 vertical pull, 1 horizontal pull, 1 vertical push, 1 horizontal push
105
+ - Pain/discomfort → swap for same movement pattern alternative
106
+ - Respect equipment constraints
107
+
108
+ ## Cardiovascular & Conditioning
109
+
110
+ ### VO2max Development
111
+
112
+ VO2max is the single strongest predictor of all-cause mortality. Program it seriously.
113
+
114
+ **Zone 2 (aerobic base) — 2-3x/week, 30-60 min:**
115
+
116
+ - Heart rate: 60-70% HRmax (roughly "can hold a conversation" intensity)
117
+ - Modalities: running, cycling, rowing, swimming, incline walking
118
+ - This is the foundation — builds mitochondrial density, fat oxidation, cardiac output
119
+ - Do NOT skip this for more HIIT — Zone 2 is the base everything else sits on
120
+
121
+ **Zone 4-5 (VO2max intervals) — 1-2x/week:**
122
+
123
+ - 4×4 min at 90-95% HRmax, 3 min active recovery (Norwegian 4×4 protocol)
124
+ - Or: 8×30s all-out / 4 min rest (Tabata-adjacent for advanced)
125
+ - Or: 5×3 min at 90-95% HRmax / 2.5 min recovery
126
+ - Build up from 1 HIIT session/week to 2 over 4-6 weeks
127
+ - Never do HIIT the day before a heavy compound lifting day
128
+
129
+ **Conditioning metrics to track:**
130
+
131
+ - Resting heart rate (lower = better aerobic base)
132
+ - Time to HR recovery (how fast HR drops after effort)
133
+ - Subjective: can you walk up 3 flights of stairs without breathing hard?
134
+
135
+ ### Programming Conditioning with Lifting
136
+
137
+ - Separate cardio from legs by 24-48 hours when possible
138
+ - If same day: lift first, cardio after (or AM/PM split)
139
+ - Zone 2 can be done on "rest" days — it's low-stress
140
+ - HIIT counts as a training stress — factor into weekly recovery budget
141
+ - For fat loss: prioritize Zone 2 volume over HIIT frequency
142
+
143
+ ## Mobility & Flexibility
144
+
145
+ ### Daily Mobility (10-15 min)
146
+
147
+ Prescribe based on user's specific limitations. Default priority areas:
148
+
149
+ **Hip complex:** 90/90 stretch, hip flexor stretch (couch stretch), pigeon pose, hip CARs
150
+ **Thoracic spine:** foam roller extensions, thread the needle, cat-cow, open book
151
+ **Shoulders:** wall slides, band pull-aparts, shoulder CARs, sleeper stretch
152
+ **Ankles:** wall ankle mobilization (knee-to-wall), calf stretch with knee bent/straight
153
+
154
+ ### Pre-Workout Mobility (5-8 min)
155
+
156
+ - Movement-specific prep, NOT static stretching
157
+ - Examples: goblet squat holds before squat day, band dislocates before pressing, hip CARs before deadlift
158
+ - Dynamic stretches only (leg swings, arm circles, lunge with rotation)
159
+
160
+ ### Flexibility Programming
161
+
162
+ - Static stretching: post-workout or separate session, 2-3x/week
163
+ - Hold stretches 60-120 seconds per position (research shows longer holds = better gains)
164
+ - Target areas limiting performance: hamstrings (deadlift depth), hip flexors (squat depth), pecs/lats (overhead mobility)
165
+ - PNF stretching for advanced: contract-relax method for stubborn areas
166
+
167
+ ### Corrective Work
168
+
169
+ - If user reports asymmetry or pain: prescribe unilateral corrective exercises
170
+ - Common patterns: anterior pelvic tilt → glute activation + hip flexor stretch, rounded shoulders → face pulls + chest stretch + thoracic extension
171
+ - Reassess every 4 weeks
172
+
173
+ ## Longevity & Health
174
+
175
+ ### Training for Longevity (Peter Attia Framework)
176
+
177
+ The goal: maintain physical independence and quality of life into your 80s-90s.
178
+
179
+ **The Centenarian Decathlon concept:** Train now for the activities you want to do at 80+. This means:
180
+
181
+ - Grip strength (deadlift, farmer's carries, dead hangs) — predictor of all-cause mortality
182
+ - Leg strength (squats, lunges) — fall prevention, stair climbing
183
+ - Cardiovascular fitness (VO2max) — strongest predictor of longevity
184
+ - Flexibility/mobility — maintain range of motion (hip hinge, overhead reach, getting up from floor)
185
+ - Balance & stability (single-leg work, Turkish get-ups)
186
+ - Bone density (loaded carries, impact exercise, heavy compounds)
187
+
188
+ **Practical longevity habits to reinforce:**
189
+
190
+ - Sleep 7-9 hours (non-negotiable for recovery and longevity)
191
+ - Daily movement beyond training (10k steps target)
192
+ - Stress management (training IS stress — don't overtrain when life stress is high)
193
+ - Protein intake: 1.6-2.2g/kg bodyweight for muscle preservation
194
+
195
+ ### Injury Prevention
196
+
197
+ - Warm-up sets before working sets (always)
198
+ - Don't increase weekly volume by more than 10% per week
199
+ - Deload every 4-6 weeks (mandatory, not optional)
200
+ - If something hurts: modify, don't push through
201
+ - Include unilateral work to prevent/address imbalances
202
+
203
+ ## Stamina & Work Capacity
204
+
205
+ ### Building Work Capacity
206
+
207
+ - Gradually increase training density (less rest between sets over weeks)
208
+ - Circuit training blocks (1x/week): 4-6 exercises, 30s rest, 3-4 rounds
209
+ - Complexes: barbell/dumbbell complexes for conditioning (5 exercises, no rest between, rest between rounds)
210
+ - Supersets and giant sets as mesocycle progresses
211
+ - Sled work, battle ropes, kettlebell swings for metabolic conditioning
212
+
213
+ ### Energy System Development
214
+
215
+ - Phosphagen (0-10s): heavy singles/doubles, sprints, explosive jumps
216
+ - Glycolytic (10s-2min): HIIT intervals, tempo runs, heavy circuits
217
+ - Oxidative (2min+): Zone 2 cardio, long runs, steady-state cycling
218
+ - Train all three systems across the training week for complete athletic development
219
+
220
+ ## Onboarding Protocol
221
+
222
+ When a user first interacts, run this onboarding conversation. Ask naturally, not like a form. Group related questions.
223
+
224
+ ### Questions to ask
225
+
226
+ **Physical profile:** Age, height, weight, estimated body fat %. Current lift numbers (bench, squat, deadlift, OHP) or "beginner" if new. Resting heart rate if known.
227
+
228
+ **Training context:** Years training? Current program? Days/week available? Session length (30/45/60/75/90 min)? Equipment access (full gym / home / bodyweight / kettlebells)? Access to cardio equipment (treadmill, bike, rower)?
229
+
230
+ **Goals (rank top 3):** Muscle gain, fat loss, strength, cardiovascular fitness/VO2max, mobility/flexibility, sport-specific performance, longevity/health, endurance/stamina.
231
+
232
+ **Body & limitations:** Injuries or chronic pain? Areas where you feel tight or immobile? Exercises you can't do? Known posture issues? Any cardiovascular conditions?
233
+
234
+ **Lifestyle:** Sleep quality (1-10), stress level (1-10), nutrition approach, daily step count estimate, active job or desk job?
235
+
236
+ **Preferences:** Training style (powerlifting / bodybuilding / functional / hybrid / athletic)? Favorite and least favorite exercises? Morning or evening training? Cardio preferences (running / cycling / rowing / swimming / walking / other)? Do they enjoy or hate cardio?
237
+
238
+ **Athletic background:** Any sports history? Combat sports? Running races? Active hobbies?
239
+
240
+ **Optional:** Photos (front/side/back) for posture assessment.
241
+
242
+ ### After onboarding
243
+
244
+ 1. Summarize their profile back to them for confirmation
245
+ 2. Generate a complete weekly program with ALL components:
246
+ - Strength/hypertrophy sessions (push to Hevy)
247
+ - Conditioning sessions (HIIT + Zone 2 schedule)
248
+ - Daily mobility prescription
249
+ - Flexibility work schedule
250
+ 3. Use `create-routine-folder` to create a folder (e.g., "HevyCoach - Mesocycle 1")
251
+ 4. Use `create-routine` to push each session as a routine to Hevy
252
+ 5. Provide conditioning/mobility/flexibility work as a clear written schedule (these don't map to Hevy routines easily)
253
+ 6. Confirm everything is in their Hevy app
254
+
255
+ ## Workout Sync Protocol
256
+
257
+ When syncing or reviewing a workout:
258
+
259
+ 1. Use `get-workouts` to fetch recent workouts (or use `analyze-workout` for structured analysis)
260
+ 2. Compare to planned program
261
+ 3. Analyze:
262
+ - Hit target reps? → Progress weight
263
+ - Missed reps? → Hold weight, check RPE/recovery
264
+ - Skipped exercises? → Ask why, suggest swap if pattern repeats
265
+ - RPE reported? → Adjust intensity targets
266
+ 4. Update rolling summary
267
+ 5. State changes to upcoming sessions
268
+ 6. Use `update-routine` to push adjustments to Hevy if needed
269
+
270
+ ## Daily Briefing Format
271
+
272
+ ```
273
+ Today: [Session Name] — [Duration] min
274
+
275
+ Pre-workout: [Mobility/warmup prescription]
276
+
277
+ Workout:
278
+ 1. [Exercise] — [Sets]×[Reps] @ [Weight]kg (RPE [target])
279
+ 2. [Exercise] — [Sets]×[Reps] @ [Weight]kg (RPE [target])
280
+ ...
281
+
282
+ Post-workout: [Flexibility/cool-down if scheduled]
283
+
284
+ Conditioning: [If today is a cardio day — specify protocol]
285
+
286
+ Daily mobility: [Specific mobility drills for today, 10-15 min]
287
+
288
+ Notes: [Coaching cues, progression notes, reminders]
289
+ ```
290
+
291
+ ## Weekly Review Format
292
+
293
+ On Sundays or when asked:
294
+
295
+ - Sessions completed vs planned (strength + conditioning + mobility)
296
+ - Volume per muscle group (sets)
297
+ - PRs hit this week
298
+ - Conditioning metrics (sessions completed, any HR data)
299
+ - Adherence %
300
+ - What's changing next week and why
301
+ - Concerns (recovery, plateau, imbalance, missed cardio)
302
+
303
+ ## Adaptation Rules
304
+
305
+ After analyzing each completed workout:
306
+
307
+ 1. **All reps hit, RPE ≤ 7:** Increase weight next session
308
+ 2. **All reps hit, RPE 8:** Perfect — hold weight, increase next week
309
+ 3. **Missed 1-2 reps, RPE 9+:** Hold weight, monitor next session
310
+ 4. **Missed 3+ reps or RPE 10:** Check recovery factors, consider reducing weight 5-10%
311
+ 5. **Exercise skipped 2+ times:** Replace with alternative (same pattern, ask user)
312
+ 6. **Week 4-6 of mesocycle:** Program deload week automatically
313
+ 7. **Post-deload:** Start new mesocycle, reassess maxes, adjust targets
314
+ 8. **Conditioning skipped 2+ weeks:** Reintroduce gently (lower duration, lower intensity)
315
+ 9. **Mobility consistently skipped:** Simplify prescription, integrate into warmups
316
+
317
+ ## Communication Style
318
+
319
+ - Direct and concise
320
+ - Use exercise names the user knows (match Hevy template names)
321
+ - Give specific numbers (weight, reps, sets, HR zones, durations) — never vague
322
+ - Explain the "why" briefly when making changes
323
+ - Celebrate PRs and consistency
324
+ - Don't lecture about missed sessions — adjust and move forward
325
+ - Red flags (pain, chronic fatigue, overtraining) → flag clearly
326
+ - Treat the full program as interconnected: strength, conditioning, mobility, recovery are ONE system
327
+
328
+ ---
329
+
330
+ ## User Profile
331
+
332
+ > Fill this section after the onboarding conversation.
333
+
334
+ **Name:**
335
+ **Age:**
336
+ **Height:**
337
+ **Weight:**
338
+ **Body Fat %:**
339
+ **Resting HR:**
340
+ **Training Experience:**
341
+
342
+ **Current Lifts:**
343
+
344
+ - Bench Press:
345
+ - Squat:
346
+ - Deadlift:
347
+ - OHP:
348
+
349
+ **Conditioning Baseline:**
350
+
351
+ - VO2max estimate:
352
+ - Can run 5k? Time:
353
+ - Zone 2 HR range:
354
+
355
+ **Training Schedule:**
356
+
357
+ - Days per week:
358
+ - Session duration:
359
+ - Preferred time:
360
+ - Equipment:
361
+ - Cardio equipment:
362
+
363
+ **Goals (ranked):**
364
+ 1.
365
+ 2.
366
+ 3.
367
+
368
+ **Injuries/Limitations:**
369
+
370
+ **Mobility Restrictions:**
371
+
372
+ **Lifestyle:**
373
+
374
+ - Sleep:
375
+ - Stress:
376
+ - Nutrition:
377
+ - Daily steps:
378
+ - Job type:
379
+
380
+ **Preferences:**
381
+
382
+ - Style:
383
+ - Favorite exercises:
384
+ - Exercises to avoid:
385
+ - Cardio preference:
386
+ - Athletic background:
387
+
388
+ ---
389
+
390
+ ## Current Program
391
+
392
+ > Populated after program generation. Updated each mesocycle.
393
+
394
+ **Mesocycle:**
395
+ **Week:**
396
+ **Phase:**
397
+
398
+ ### Strength Sessions
399
+
400
+ *(Pushed to Hevy as routines)*
401
+
402
+ ### Conditioning Schedule
403
+
404
+ *(Zone 2 + HIIT weekly plan)*
405
+
406
+ ### Mobility & Flexibility
407
+
408
+ *(Daily mobility + flexibility sessions)*
409
+
410
+ ---
411
+
412
+ ## Rolling Summary (Last 2 Weeks)
413
+
414
+ > Updated after each workout sync.
415
+
416
+ *(Workout summaries, progression notes, conditioning adherence, adaptation decisions)*
package/dist/http.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=http.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.d.ts","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":""}
package/dist/http.js ADDED
@@ -0,0 +1,174 @@
1
+ #!/usr/bin/env node
2
+ import { randomUUID } from "node:crypto";
3
+ import { createMcpExpressApp } from "@modelcontextprotocol/sdk/server/express.js";
4
+ import { StreamableHTTPServerTransport } from "@modelcontextprotocol/sdk/server/streamableHttp.js";
5
+ import { isInitializeRequest } from "@modelcontextprotocol/sdk/types.js";
6
+ import { createServer } from "./index.js";
7
+ // --- Environment -----------------------------------------------------------
8
+ const apiKey = process.env.HEVY_API_KEY;
9
+ if (!apiKey) {
10
+ console.error("HEVY_API_KEY environment variable is required.");
11
+ console.error("Get your API key from Hevy Settings → API (requires Pro subscription).");
12
+ process.exit(1);
13
+ }
14
+ const port = Number(process.env.PORT ?? 3000);
15
+ const authToken = process.env.MCP_AUTH_TOKEN;
16
+ // --- Express app -----------------------------------------------------------
17
+ const app = createMcpExpressApp({ host: "0.0.0.0" });
18
+ // CORS — allow any origin so ChatGPT / Gemini can reach us
19
+ app.use((_req, res, next) => {
20
+ res.setHeader("Access-Control-Allow-Origin", "*");
21
+ res.setHeader("Access-Control-Allow-Headers", "Content-Type, Authorization, mcp-session-id");
22
+ res.setHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, OPTIONS");
23
+ if (_req.method === "OPTIONS") {
24
+ res.sendStatus(204);
25
+ return;
26
+ }
27
+ next();
28
+ });
29
+ // Bearer auth middleware — only applied when MCP_AUTH_TOKEN is set
30
+ function bearerAuth(req, res, next) {
31
+ if (!authToken) {
32
+ next();
33
+ return;
34
+ }
35
+ const header = req.headers.authorization ?? "";
36
+ if (header === `Bearer ${authToken}`) {
37
+ next();
38
+ return;
39
+ }
40
+ res.status(401).json({ error: "Unauthorized" });
41
+ }
42
+ // --- Session store ---------------------------------------------------------
43
+ const transports = new Map();
44
+ // --- Health check ----------------------------------------------------------
45
+ app.get("/health", (_req, res) => {
46
+ res.json({ status: "ok", server: "hevy-coach" });
47
+ });
48
+ // --- MCP POST --------------------------------------------------------------
49
+ app.post("/mcp", bearerAuth, async (req, res) => {
50
+ const sessionId = req.headers["mcp-session-id"];
51
+ try {
52
+ if (sessionId) {
53
+ const transport = transports.get(sessionId);
54
+ if (!transport) {
55
+ res.status(400).json({
56
+ jsonrpc: "2.0",
57
+ error: { code: -32000, message: "Unknown session ID" },
58
+ id: null,
59
+ });
60
+ return;
61
+ }
62
+ await transport.handleRequest(req, res, req.body);
63
+ return;
64
+ }
65
+ if (!isInitializeRequest(req.body)) {
66
+ res.status(400).json({
67
+ jsonrpc: "2.0",
68
+ error: {
69
+ code: -32000,
70
+ message: "Bad Request: missing session ID or not an initialize request",
71
+ },
72
+ id: null,
73
+ });
74
+ return;
75
+ }
76
+ // New session — create transport, connect server, then handle request.
77
+ // We use onsessioninitialized to store the transport in the map as soon
78
+ // as the session ID is assigned, before any concurrent requests arrive.
79
+ const transport = new StreamableHTTPServerTransport({
80
+ sessionIdGenerator: () => randomUUID(),
81
+ onsessioninitialized: (sid) => {
82
+ transports.set(sid, transport);
83
+ console.log(`[hevy-coach] Session initialized: ${sid}`);
84
+ },
85
+ });
86
+ transport.onclose = () => {
87
+ const sid = transport.sessionId;
88
+ if (sid) {
89
+ transports.delete(sid);
90
+ console.log(`[hevy-coach] Session closed: ${sid}`);
91
+ }
92
+ };
93
+ const server = createServer(apiKey);
94
+ await server.connect(transport);
95
+ await transport.handleRequest(req, res, req.body);
96
+ }
97
+ catch (err) {
98
+ console.error("[hevy-coach] Error handling POST /mcp:", err);
99
+ if (!res.headersSent) {
100
+ res.status(500).json({
101
+ jsonrpc: "2.0",
102
+ error: { code: -32603, message: "Internal server error" },
103
+ id: null,
104
+ });
105
+ }
106
+ }
107
+ });
108
+ // --- MCP GET (SSE stream) --------------------------------------------------
109
+ app.get("/mcp", bearerAuth, async (req, res) => {
110
+ const sessionId = req.headers["mcp-session-id"];
111
+ if (!sessionId) {
112
+ res.status(400).send("Missing mcp-session-id header");
113
+ return;
114
+ }
115
+ const transport = transports.get(sessionId);
116
+ if (!transport) {
117
+ res.status(400).send("Unknown session ID");
118
+ return;
119
+ }
120
+ try {
121
+ await transport.handleRequest(req, res);
122
+ }
123
+ catch (err) {
124
+ console.error("[hevy-coach] Error handling GET /mcp:", err);
125
+ if (!res.headersSent)
126
+ res.status(500).send("Internal server error");
127
+ }
128
+ });
129
+ // --- MCP DELETE (session termination) -------------------------------------
130
+ app.delete("/mcp", bearerAuth, async (req, res) => {
131
+ const sessionId = req.headers["mcp-session-id"];
132
+ if (!sessionId) {
133
+ res.status(400).send("Missing mcp-session-id header");
134
+ return;
135
+ }
136
+ const transport = transports.get(sessionId);
137
+ if (!transport) {
138
+ res.status(400).send("Unknown session ID");
139
+ return;
140
+ }
141
+ try {
142
+ await transport.handleRequest(req, res);
143
+ transports.delete(sessionId);
144
+ }
145
+ catch (err) {
146
+ console.error("[hevy-coach] Error handling DELETE /mcp:", err);
147
+ if (!res.headersSent)
148
+ res.status(500).send("Internal server error");
149
+ }
150
+ });
151
+ // --- Start -----------------------------------------------------------------
152
+ app.listen(port, "0.0.0.0", () => {
153
+ const authNote = authToken ? " (Bearer auth enabled)" : " (no auth)";
154
+ console.log(`[hevy-coach] HTTP MCP server listening on http://0.0.0.0:${port}${authNote}`);
155
+ console.log(`[hevy-coach] Health: http://0.0.0.0:${port}/health`);
156
+ console.log(`[hevy-coach] MCP endpoint: http://0.0.0.0:${port}/mcp`);
157
+ });
158
+ // --- Graceful shutdown -----------------------------------------------------
159
+ process.on("SIGINT", async () => {
160
+ console.log("\n[hevy-coach] Shutting down...");
161
+ const closeAll = [...transports.entries()].map(async ([sid, transport]) => {
162
+ try {
163
+ await transport.close();
164
+ console.log(`[hevy-coach] Closed session ${sid}`);
165
+ }
166
+ catch (err) {
167
+ console.error(`[hevy-coach] Error closing session ${sid}:`, err);
168
+ }
169
+ });
170
+ await Promise.all(closeAll);
171
+ console.log("[hevy-coach] Shutdown complete.");
172
+ process.exit(0);
173
+ });
174
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACzC,OAAO,EAAE,mBAAmB,EAAE,MAAM,6CAA6C,CAAC;AAClF,OAAO,EAAE,6BAA6B,EAAE,MAAM,oDAAoD,CAAC;AACnG,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AAEzE,OAAO,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE1C,8EAA8E;AAE9E,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;AACxC,IAAI,CAAC,MAAM,EAAE,CAAC;IACZ,OAAO,CAAC,KAAK,CAAC,gDAAgD,CAAC,CAAC;IAChE,OAAO,CAAC,KAAK,CACX,wEAAwE,CACzE,CAAC;IACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC;AAED,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,CAAC;AAC9C,MAAM,SAAS,GAAG,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC;AAE7C,8EAA8E;AAE9E,MAAM,GAAG,GAAG,mBAAmB,CAAC,EAAE,IAAI,EAAE,SAAS,EAAE,CAAC,CAAC;AAErD,2DAA2D;AAC3D,GAAG,CAAC,GAAG,CAAC,CAAC,IAAa,EAAE,GAAa,EAAE,IAAkB,EAAE,EAAE;IAC3D,GAAG,CAAC,SAAS,CAAC,6BAA6B,EAAE,GAAG,CAAC,CAAC;IAClD,GAAG,CAAC,SAAS,CACX,8BAA8B,EAC9B,6CAA6C,CAC9C,CAAC;IACF,GAAG,CAAC,SAAS,CACX,8BAA8B,EAC9B,4BAA4B,CAC7B,CAAC;IACF,IAAI,IAAI,CAAC,MAAM,KAAK,SAAS,EAAE,CAAC;QAC9B,GAAG,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;QACpB,OAAO;IACT,CAAC;IACD,IAAI,EAAE,CAAC;AACT,CAAC,CAAC,CAAC;AAEH,mEAAmE;AACnE,SAAS,UAAU,CAAC,GAAY,EAAE,GAAa,EAAE,IAAkB;IACjE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,IAAI,EAAE,CAAC;QACP,OAAO;IACT,CAAC;IACD,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,CAAC,aAAa,IAAI,EAAE,CAAC;IAC/C,IAAI,MAAM,KAAK,UAAU,SAAS,EAAE,EAAE,CAAC;QACrC,IAAI,EAAE,CAAC;QACP,OAAO;IACT,CAAC;IACD,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,EAAE,KAAK,EAAE,cAAc,EAAE,CAAC,CAAC;AAClD,CAAC;AAED,8EAA8E;AAE9E,MAAM,UAAU,GAAG,IAAI,GAAG,EAAyC,CAAC;AAEpE,8EAA8E;AAE9E,GAAG,CAAC,GAAG,CAAC,SAAS,EAAE,CAAC,IAAa,EAAE,GAAa,EAAE,EAAE;IAClD,GAAG,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;AACnD,CAAC,CAAC,CAAC;AAEH,8EAA8E;AAE9E,GAAG,CAAC,IAAI,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IACjE,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAuB,CAAC;IAEtE,IAAI,CAAC;QACH,IAAI,SAAS,EAAE,CAAC;YACd,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;oBACnB,OAAO,EAAE,KAAK;oBACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,oBAAoB,EAAE;oBACtD,EAAE,EAAE,IAAI;iBACT,CAAC,CAAC;gBACH,OAAO;YACT,CAAC;YACD,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;YAClD,OAAO;QACT,CAAC;QAED,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YACnC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE;oBACL,IAAI,EAAE,CAAC,KAAK;oBACZ,OAAO,EAAE,8DAA8D;iBACxE;gBACD,EAAE,EAAE,IAAI;aACT,CAAC,CAAC;YACH,OAAO;QACT,CAAC;QAED,uEAAuE;QACvE,wEAAwE;QACxE,wEAAwE;QACxE,MAAM,SAAS,GAAG,IAAI,6BAA6B,CAAC;YAClD,kBAAkB,EAAE,GAAG,EAAE,CAAC,UAAU,EAAE;YACtC,oBAAoB,EAAE,CAAC,GAAG,EAAE,EAAE;gBAC5B,UAAU,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;gBAC/B,OAAO,CAAC,GAAG,CAAC,qCAAqC,GAAG,EAAE,CAAC,CAAC;YAC1D,CAAC;SACF,CAAC,CAAC;QAEH,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE;YACvB,MAAM,GAAG,GAAG,SAAS,CAAC,SAAS,CAAC;YAChC,IAAI,GAAG,EAAE,CAAC;gBACR,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBACvB,OAAO,CAAC,GAAG,CAAC,gCAAgC,GAAG,EAAE,CAAC,CAAC;YACrD,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,MAAM,GAAG,YAAY,CAAC,MAAM,CAAC,CAAC;QACpC,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChC,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,IAAI,CAAC,CAAC;IACpD,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,wCAAwC,EAAE,GAAG,CAAC,CAAC;QAC7D,IAAI,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC;YACrB,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC;gBACnB,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,uBAAuB,EAAE;gBACzD,EAAE,EAAE,IAAI;aACT,CAAC,CAAC;QACL,CAAC;IACH,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,8EAA8E;AAE9E,GAAG,CAAC,GAAG,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IAChE,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAuB,CAAC;IACtE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QACtD,OAAO;IACT,CAAC;IACD,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IACD,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC1C,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,uCAAuC,EAAE,GAAG,CAAC,CAAC;QAC5D,IAAI,CAAC,GAAG,CAAC,WAAW;YAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACtE,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,6EAA6E;AAE7E,GAAG,CAAC,MAAM,CAAC,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAY,EAAE,GAAa,EAAE,EAAE;IACnE,MAAM,SAAS,GAAG,GAAG,CAAC,OAAO,CAAC,gBAAgB,CAAuB,CAAC;IACtE,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,+BAA+B,CAAC,CAAC;QACtD,OAAO;IACT,CAAC;IACD,MAAM,SAAS,GAAG,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,oBAAoB,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IACD,IAAI,CAAC;QACH,MAAM,SAAS,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;QACxC,UAAU,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IAC/B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,0CAA0C,EAAE,GAAG,CAAC,CAAC;QAC/D,IAAI,CAAC,GAAG,CAAC,WAAW;YAAE,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,uBAAuB,CAAC,CAAC;IACtE,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,8EAA8E;AAE9E,GAAG,CAAC,MAAM,CAAC,IAAI,EAAE,SAAS,EAAE,GAAG,EAAE;IAC/B,MAAM,QAAQ,GAAG,SAAS,CAAC,CAAC,CAAC,wBAAwB,CAAC,CAAC,CAAC,YAAY,CAAC;IACrE,OAAO,CAAC,GAAG,CACT,4DAA4D,IAAI,GAAG,QAAQ,EAAE,CAC9E,CAAC;IACF,OAAO,CAAC,GAAG,CAAC,uCAAuC,IAAI,SAAS,CAAC,CAAC;IAClE,OAAO,CAAC,GAAG,CAAC,6CAA6C,IAAI,MAAM,CAAC,CAAC;AACvE,CAAC,CAAC,CAAC;AAEH,8EAA8E;AAE9E,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,KAAK,IAAI,EAAE;IAC9B,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAC/C,MAAM,QAAQ,GAAG,CAAC,GAAG,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,GAAG,CAAC,KAAK,EAAE,CAAC,GAAG,EAAE,SAAS,CAAC,EAAE,EAAE;QACxE,IAAI,CAAC;YACH,MAAM,SAAS,CAAC,KAAK,EAAE,CAAC;YACxB,OAAO,CAAC,GAAG,CAAC,+BAA+B,GAAG,EAAE,CAAC,CAAC;QACpD,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,OAAO,CAAC,KAAK,CAAC,sCAAsC,GAAG,GAAG,EAAE,GAAG,CAAC,CAAC;QACnE,CAAC;IACH,CAAC,CAAC,CAAC;IACH,MAAM,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IAC5B,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;IAC/C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAClB,CAAC,CAAC,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAQpE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAetD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AASpE,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAgBtD"}
package/dist/index.js CHANGED
@@ -5,16 +5,18 @@ import { registerRoutineTools } from "./tools/routines.js";
5
5
  import { registerExerciseTools } from "./tools/exercises.js";
6
6
  import { registerCoachingTools } from "./tools/coaching.js";
7
7
  import { registerUserTools } from "./tools/users.js";
8
+ import { registerBodyMeasurementTools } from "./tools/body-measurements.js";
8
9
  export function createServer(apiKey) {
9
10
  const server = new McpServer({
10
11
  name: "hevy-coach",
11
- version: "0.1.2",
12
+ version: "0.2.0",
12
13
  });
13
14
  const client = new HevyClient(apiKey);
14
15
  registerUserTools(server, client);
15
16
  registerWorkoutTools(server, client);
16
17
  registerRoutineTools(server, client);
17
18
  registerExerciseTools(server, client);
19
+ registerBodyMeasurementTools(server, client);
18
20
  registerCoachingTools(server, client);
19
21
  return server;
20
22
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AAErD,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IAEtC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEtC,OAAO,MAAM,CAAC;AAChB,CAAC"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,qBAAqB,CAAC;AAC3D,OAAO,EAAE,qBAAqB,EAAE,MAAM,sBAAsB,CAAC;AAC7D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAC;AAE5E,MAAM,UAAU,YAAY,CAAC,MAAc;IACzC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC;QAC3B,IAAI,EAAE,YAAY;QAClB,OAAO,EAAE,OAAO;KACjB,CAAC,CAAC;IAEH,MAAM,MAAM,GAAG,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC;IAEtC,iBAAiB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAClC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,oBAAoB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACrC,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACtC,4BAA4B,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC7C,qBAAqB,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEtC,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import type { HevyClient } from "../utils/hevy-client.js";
3
+ export declare function registerBodyMeasurementTools(server: McpServer, client: HevyClient): void;
4
+ //# sourceMappingURL=body-measurements.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"body-measurements.d.ts","sourceRoot":"","sources":["../../src/tools/body-measurements.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAEzE,OAAO,KAAK,EAA8B,UAAU,EAAE,MAAM,yBAAyB,CAAC;AAyBtF,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,UAAU,QA6EjF"}