hevy-mcp 3.1.1 → 3.2.1

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 CHANGED
@@ -1,39 +1,149 @@
1
- # hevy-mcp: Hevy workouts for your AI assistant
1
+ # Hevy MCP Server
2
2
 
3
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://opensource.org/licenses/MIT)
3
+ <div align="center">
4
+
5
+ **Talk to your Hevy workout data from Claude, Cursor, Codex, and other MCP clients.**
6
+
7
+ [![npm version](https://img.shields.io/npm/v/hevy-mcp.svg)](https://www.npmjs.com/package/hevy-mcp)
8
+ [![npm downloads](https://img.shields.io/npm/dm/hevy-mcp.svg)](https://www.npmjs.com/package/hevy-mcp)
4
9
  [![Build and Test](https://github.com/chrisdoc/hevy-mcp/actions/workflows/build-and-test.yml/badge.svg)](https://github.com/chrisdoc/hevy-mcp/actions/workflows/build-and-test.yml)
5
10
  [![Codecov](https://codecov.io/gh/chrisdoc/hevy-mcp/branch/main/graph/badge.svg)](https://codecov.io/gh/chrisdoc/hevy-mcp)
6
- [![npm version](https://img.shields.io/npm/v/hevy-mcp.svg)](https://www.npmjs.com/package/hevy-mcp)
11
+ [![GitHub stars](https://img.shields.io/github/stars/chrisdoc/hevy-mcp?style=flat)](https://github.com/chrisdoc/hevy-mcp/stargazers)
12
+ [![Hosted on Cloudflare](https://img.shields.io/badge/Hosted_on-Cloudflare-F38020?logo=cloudflare&logoColor=white)](#hosted-cloudflare-endpoint)
13
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](./LICENSE)
7
14
 
8
- `hevy-mcp` connects MCP-compatible assistants such as Claude Desktop and Cursor
9
- to the [Hevy](https://www.hevyapp.com/) fitness API. Ask about workout history,
10
- analyze progress, browse routines and exercises, or create and update Hevy data
11
- without leaving your assistant.
15
+ [Connect to the hosted MCP](#connect-to-the-hosted-endpoint) · [Watch the 18-second demo](https://raw.githubusercontent.com/chrisdoc/hevy-mcp/main/docs/assets/hevy-mcp-demo.mp4) · [Explore all 25 tools](#tools)
12
16
 
13
- A Hevy API key, available with Hevy PRO, is required.
17
+ </div>
14
18
 
15
- ## Quick Start
19
+ `hevy-mcp` is an open-source [Model Context Protocol (MCP)](https://modelcontextprotocol.io/)
20
+ server for the [Hevy](https://www.hevyapp.com/) fitness and workout tracking
21
+ app. It lets AI assistants read, analyze, create, and update your Hevy workouts,
22
+ routines, exercise templates, and body measurements through authenticated Hevy
23
+ API requests.
16
24
 
17
- Use local stdio when your MCP client can launch a command. Hosted Streamable
18
- HTTP setup is documented below but is temporarily unavailable.
25
+ > A Hevy API key, available with **Hevy PRO**, is required.
19
26
 
20
- ### Option A: Local stdio
27
+ ## See it in action
21
28
 
22
- The npm package and official container are **stdio-only** MCP executables. Your
23
- client starts the process and communicates through standard input/output; this
24
- is not an interactive terminal command or an HTTP service.
29
+ [![Hevy MCP demo showing an AI assistant analyzing six weeks of Hevy training data](https://raw.githubusercontent.com/chrisdoc/hevy-mcp/main/docs/assets/hevy-mcp-demo.gif)](https://raw.githubusercontent.com/chrisdoc/hevy-mcp/main/docs/assets/hevy-mcp-demo.mp4)
25
30
 
26
- #### npx
31
+ <p align="center"><sub>Click the preview to play the full-quality 18-second demo.</sub></p>
27
32
 
28
- Requires Node.js 20 or newer, as declared by the package metadata.
33
+ In the demo, the assistant retrieves real Hevy data and answers a multi-part
34
+ training question with evidence from the user's workout history.
29
35
 
30
- Claude Desktop (`claude_desktop_config.json`) and Cursor (`~/.cursor/mcp.json`)
31
- both accept an `mcpServers` entry like this:
36
+ ## What can you do with it?
32
37
 
33
- - **Claude Desktop on macOS:**
34
- `~/Library/Application Support/Claude/claude_desktop_config.json`
35
- - **Claude Desktop on Windows:**
36
- `%APPDATA%\Claude\claude_desktop_config.json`
38
+ - **Analyze training progress:** summarize 1-12 weeks of workouts and body
39
+ measurements in one tool call.
40
+ - **Ask questions in plain language:** find recent sessions, frequently trained
41
+ exercises, consistency gaps, routine details, or exercise history.
42
+ - **Plan and log training:** create or update workouts, routines, routine folders,
43
+ custom exercises, and body measurements.
44
+ - **Search without huge responses:** discover routines and exercise templates with
45
+ compact, AI-friendly results.
46
+ - **Connect from your preferred MCP client:** use the hosted Streamable HTTP
47
+ endpoint or run locally with Codex, Claude Desktop, Cursor, and other clients.
48
+ - **Start without installing anything:** connect directly to the production
49
+ Cloudflare Worker—no Node.js, package download, or Docker container required.
50
+ - **Keep local control when you want it:** run the same server with `npx`, `bunx`,
51
+ or the official Docker image.
52
+
53
+ Try asking:
54
+
55
+ > Analyze my training over the last six weeks. Show workouts per week, my most
56
+ > frequently trained exercises, any obvious gaps or inconsistencies, and cite the
57
+ > workout evidence you used.
58
+
59
+ > Find my push-day routine and show its exercises and sets.
60
+
61
+ > Compare my recent body measurements with my training consistency.
62
+
63
+ > Create a completed workout from my saved routine. Ask me for any missing set
64
+ > results before writing it to Hevy.
65
+
66
+ ## Quick start
67
+
68
+ ### 1. Get your Hevy API key
69
+
70
+ Create an API key in Hevy, then keep it somewhere secure. API access currently
71
+ requires a Hevy PRO subscription.
72
+
73
+ ### 2. Connect `hevy-mcp` to your client
74
+
75
+ The hosted Cloudflare endpoint is the fastest way to start. It runs remotely,
76
+ so your client does not need Node.js, Bun, Docker, or a local server process.
77
+
78
+ #### Connect to the hosted endpoint
79
+
80
+ Production URL:
81
+
82
+ ```text
83
+ https://hevy.chrisdoc.dev/mcp
84
+ ```
85
+
86
+ The endpoint uses Streamable HTTP. Send your Hevy API key as a bearer token on
87
+ every request.
88
+
89
+ ##### Codex
90
+
91
+ Codex CLI, the Codex desktop app, and the IDE extension share the same MCP
92
+ configuration. Make your Hevy API key available in the environment that starts
93
+ Codex, then add the hosted server:
94
+
95
+ ```bash
96
+ export HEVY_API_KEY=your-hevy-api-key
97
+ codex mcp add hevy \
98
+ --url https://hevy.chrisdoc.dev/mcp \
99
+ --bearer-token-env-var HEVY_API_KEY
100
+ ```
101
+
102
+ Codex stores the environment variable name, not the key itself, in its MCP
103
+ configuration. Restart Codex or begin a new session, then run `codex mcp list`
104
+ to verify the server is configured.
105
+
106
+ ##### Other Streamable HTTP clients
107
+
108
+ Clients that accept a remote MCP URL and fixed headers commonly use this shape:
109
+
110
+ ```json
111
+ {
112
+ "mcpServers": {
113
+ "hevy": {
114
+ "url": "https://hevy.chrisdoc.dev/mcp",
115
+ "headers": {
116
+ "Authorization": "Bearer your-hevy-api-key"
117
+ }
118
+ }
119
+ }
120
+ }
121
+ ```
122
+
123
+ Exact configuration keys vary by client. The hosted server requires support for
124
+ Streamable HTTP and a fixed `Authorization` header.
125
+
126
+ > [!IMPORTANT]
127
+ > Treat the bearer value like a password. The Worker validates it with Hevy for
128
+ > each request, does not store it, and forwards it to Hevy only as the required
129
+ > `api-key` header.
130
+
131
+ #### Run locally instead
132
+
133
+ Choose local stdio if you prefer to run the server on your own machine or your
134
+ client cannot attach a fixed authorization header to remote MCP requests.
135
+
136
+ ##### Codex
137
+
138
+ ```bash
139
+ codex mcp add hevy \
140
+ --env HEVY_API_KEY=your-hevy-api-key \
141
+ -- npx -y hevy-mcp
142
+ ```
143
+
144
+ ##### Claude Desktop or Cursor
145
+
146
+ Add this `mcpServers` entry to your client configuration:
37
147
 
38
148
  ```json
39
149
  {
@@ -49,10 +159,32 @@ both accept an `mcpServers` entry like this:
49
159
  }
50
160
  ```
51
161
 
52
- #### bunx
162
+ Common local configuration locations:
53
163
 
54
- Requires [Bun](https://bun.sh/). Use the same client configuration with a Bun
55
- launcher:
164
+ - **Claude Desktop on macOS:**
165
+ `~/Library/Application Support/Claude/claude_desktop_config.json`
166
+ - **Claude Desktop on Windows:**
167
+ `%APPDATA%\Claude\claude_desktop_config.json`
168
+ - **Cursor:** `~/.cursor/mcp.json`
169
+
170
+ Restart or reconnect the client after saving the file.
171
+
172
+ ##### Any stdio MCP client
173
+
174
+ Configure your client to launch this command with `HEVY_API_KEY` in the child
175
+ process environment:
176
+
177
+ ```bash
178
+ npx -y hevy-mcp
179
+ ```
180
+
181
+ `npx` requires Node.js 20 or newer. Restart or reconnect your client after
182
+ saving its configuration.
183
+
184
+ <details>
185
+ <summary><strong>Use bunx instead</strong></summary>
186
+
187
+ Requires [Bun](https://bun.sh/):
56
188
 
57
189
  ```json
58
190
  {
@@ -68,10 +200,13 @@ launcher:
68
200
  }
69
201
  ```
70
202
 
71
- #### Docker
203
+ </details>
204
+
205
+ <details>
206
+ <summary><strong>Use Docker instead</strong></summary>
72
207
 
73
208
  Official images support `linux/amd64` and `linux/arm64`. Keep stdin open with
74
- `-i` because the container runs the same stdio server:
209
+ `-i` because the container runs the stdio MCP server:
75
210
 
76
211
  ```bash
77
212
  export HEVY_API_KEY=your-hevy-api-key
@@ -102,29 +237,118 @@ the client to launch Docker:
102
237
  Pin an exact image tag such as `ghcr.io/chrisdoc/hevy-mcp:X.Y.Z` when you need
103
238
  reproducible upgrades.
104
239
 
105
- You can also add the local npm server to supported clients with
240
+ </details>
241
+
242
+ You can also add the npm server to supported clients with
106
243
  [`add-mcp`](https://github.com/neon-solutions/add-mcp):
107
244
 
108
245
  ```bash
109
246
  npx add-mcp hevy-mcp --env "HEVY_API_KEY=your-hevy-api-key"
110
247
  ```
111
248
 
112
- ### Option B: Hosted Streamable HTTP — temporarily unavailable
249
+ ### 3. Ask your first question
250
+
251
+ Try one of these after restarting or reconnecting your MCP client:
252
+
253
+ - “Give me a training summary for the last four weeks.”
254
+ - “What routines do I have saved on Hevy?”
255
+ - “Show my three most recent workouts.”
256
+ - “Find exercise templates containing squat.”
257
+ - “Which Hevy account is connected?”
113
258
 
114
- > [!WARNING]
115
- > `https://hevy.chrisdoc.dev/mcp` is currently intercepted by an interactive
116
- > Cloudflare challenge, so non-browser MCP clients cannot connect. Use local
117
- > stdio until the route is restored.
259
+ Your assistant should ask for approval before mutation tools when the client
260
+ supports tool confirmations.
118
261
 
119
- When available, the hosted endpoint does not require Node.js, Bun, or Docker:
262
+ ## How it works
263
+
264
+ ```text
265
+ Hosted: Your AI assistant → Streamable HTTP → Cloudflare Worker → Hevy API
266
+ Local: Your AI assistant → MCP over stdio → local hevy-mcp → Hevy API
267
+ ```
268
+
269
+ The hosted endpoint creates a fresh MCP server and Hevy client for each request.
270
+ It validates the supplied key with Hevy, keeps no shared user session, and does
271
+ not persist the key. The local server follows the same tool contract but runs on
272
+ your machine and receives the key through its child-process environment.
273
+
274
+ In either mode, read tools retrieve data; mutation tools create or replace data
275
+ only when your assistant calls them.
276
+
277
+ ## Guided prompts
278
+
279
+ These server-provided MCP prompts coordinate common multi-step workflows:
280
+
281
+ | Prompt | Arguments | Workflow |
282
+ | ----------------------------- | ---------------------------------------- | ---------------------------------------------------------------------------------------------------------------------- |
283
+ | `analyze-workout-progress` | Optional `weeks` from 1-12; default `4` | Calls `get-training-summary`, then analyzes workout activity and body-measurement trends from the returned evidence. |
284
+ | `create-workout-from-routine` | Required `routineId` and UTC `startTime` | Loads a routine, collects actual completed-set data and an end time, then creates a workout without inventing results. |
285
+
286
+ > [!NOTE]
287
+ > With MCP SDK v1.29.0, clients invoking `analyze-workout-progress` with its
288
+ > default value must send `arguments: {}`. Omitting the entire `arguments`
289
+ > object is rejected by that SDK version before the default is applied.
290
+
291
+ ## Tools
292
+
293
+ `hevy-mcp` registers 25 tools. Read-only tools are safe for exploration; create
294
+ and update tools are exposed with MCP mutation annotations so compatible clients
295
+ can request confirmation.
296
+
297
+ | Category | Tool | Description |
298
+ | ------------------ | --------------------------- | --------------------------------------------------------------------------------- |
299
+ | Training analysis | `get-training-summary` | Summarize 1-12 weeks of workout activity and body-measurement trends in one call. |
300
+ | Workouts | `get-workouts` | List workouts from newest to oldest with exercise and timing details. |
301
+ | Workouts | `get-workout` | Get complete details for one workout by ID. |
302
+ | Workouts | `get-workout-count` | Return the account's total workout count. |
303
+ | Workouts | `get-workout-events` | List workout update and delete events since a timestamp. |
304
+ | Workouts | `create-workout` | Create a completed workout in Hevy. |
305
+ | Workouts | `update-workout` | Replace an existing workout by ID. |
306
+ | Routines | `search-routines` | Search routine titles and return compact metadata for discovery. |
307
+ | Routines | `get-routines` | List custom and default workout routines. |
308
+ | Routines | `get-routine` | Get one routine and its exercise configuration by ID. |
309
+ | Routines | `create-routine` | Create a reusable workout routine. |
310
+ | Routines | `update-routine` | Replace an existing routine's content. |
311
+ | Routine folders | `get-routine-folders` | List default and custom routine folders. |
312
+ | Routine folders | `get-routine-folder` | Get one routine folder's metadata by ID. |
313
+ | Routine folders | `create-routine-folder` | Create a routine folder. |
314
+ | Exercise templates | `get-exercise-templates` | List exercise templates with equipment and muscle metadata. |
315
+ | Exercise templates | `get-exercise-template` | Get complete metadata for one exercise template by ID. |
316
+ | Exercise templates | `search-exercise-templates` | Search the full exercise catalog by title substring. |
317
+ | Exercise templates | `create-exercise-template` | Create a custom exercise template. |
318
+ | Exercise history | `get-exercise-history` | Get past performed sets for one exercise template. |
319
+ | Body measurements | `get-body-measurements` | List dated body measurements. |
320
+ | Body measurements | `get-body-measurement` | Get the body measurement entry for one date. |
321
+ | Body measurements | `create-body-measurement` | Create a dated body measurement. |
322
+ | Body measurements | `update-body-measurement` | Update the body measurement for an existing date. |
323
+ | Account | `get-user-info` | Return the user's ID, display name, and public profile URL. |
324
+
325
+ The Hevy API currently exposes no delete endpoints for workouts, routines,
326
+ routine folders, exercise templates, or body measurements, so there are no
327
+ corresponding delete tools.
328
+
329
+ ### Resources
330
+
331
+ | Name | URI | Description |
332
+ | -------------------- | --------------------------- | -------------------------------------------- |
333
+ | `user-profile` | `hevy://user` | Authenticated Hevy user profile. |
334
+ | `workout-count` | `hevy://workout-count` | Total number of workouts in the account. |
335
+ | `exercise-templates` | `hevy://exercise-templates` | Full formatted exercise template catalog. |
336
+ | `routine-folders` | `hevy://routine-folders` | Full formatted list of Hevy routine folders. |
337
+
338
+ ## Hosted Cloudflare endpoint
339
+
340
+ The production MCP server is live at:
120
341
 
121
342
  ```text
122
343
  https://hevy.chrisdoc.dev/mcp
123
344
  ```
124
345
 
125
- Configure a remote MCP server in your client and send your Hevy API key as a
126
- fixed authorization header. Exact configuration keys vary by client; clients
127
- that use `url` and `headers` commonly accept this shape:
346
+ It is the quickest way to use `hevy-mcp`: there is nothing to install or keep
347
+ running locally, and it exposes the same 25 tools as the npm package and Docker
348
+ image.
349
+
350
+ The Cloudflare Worker uses stateless **Streamable HTTP** at `POST /mcp`.
351
+ Clients must send their Hevy API key as a fixed authorization header:
128
352
 
129
353
  ```json
130
354
  {
@@ -139,108 +363,43 @@ that use `url` and `headers` commonly accept this shape:
139
363
  }
140
364
  ```
141
365
 
142
- The hosted transport is stateless **Streamable HTTP** at `POST /mcp`. The bearer
143
- value is a custom Hevy API credential, not OAuth. The endpoint does not expose a
144
- legacy SSE or `GET` event stream, and `GET` and `DELETE` requests return `405`.
145
- Clients that require OAuth discovery, dynamic registration, token refresh, or a
146
- legacy SSE transport are not compatible unless they can send the fixed custom
147
- header above.
366
+ The bearer value is your Hevy API key, not an OAuth token. The Worker validates
367
+ the key with Hevy on each request, does not store it, and forwards it upstream
368
+ only as Hevy's required `api-key` header.
148
369
 
149
- ### How to verify it is working
370
+ The endpoint does not expose legacy SSE or a `GET` event stream. Clients that
371
+ require OAuth discovery, dynamic registration, token refresh, or legacy SSE are
372
+ not compatible unless they can send the fixed custom header above.
150
373
 
151
- Restart or reconnect your MCP client after saving the configuration, then try:
374
+ ### Self-host the Worker
152
375
 
153
- - "What routines do I have saved on Hevy?"
154
- - "Show my most recent workouts."
155
- - "Which Hevy account is connected?"
156
- - "Find exercise templates containing squat."
157
-
158
- The assistant should ask for approval before mutation tools when the client
159
- supports tool confirmations.
160
-
161
- ## Guided MCP prompts
162
-
163
- These server-provided prompts coordinate multiple tools for common workflows:
164
-
165
- | Prompt | Arguments | Workflow |
166
- | ----------------------------- | ------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------- |
167
- | `analyze-workout-progress` | Optional `weeks` from 1-12; default is `4` | Paginates through recent workouts and body measurements, then analyzes frequency, volume, variety, consistency, and measurement trends from retrieved evidence. |
168
- | `create-workout-from-routine` | Required `routineId` and UTC `startTime` | Loads a routine, asks for actual completed-set data and an end time, then creates a workout without inventing results or copying unsupported routine-only data. |
169
-
170
- > [!IMPORTANT]
171
- > With MCP SDK v1.29.0, invoking `analyze-workout-progress` with its default
172
- > `weeks` value requires clients to send `arguments: {}`. Omitting the entire
173
- > `arguments` object is rejected by that SDK version before the default is
174
- > applied.
175
-
176
- ## Capabilities
177
-
178
- `hevy-mcp` registers 23 tools:
179
-
180
- | Category | Tool | Description |
181
- | -------------------------- | --------------------------- | --------------------------------------------------------------------- |
182
- | Workouts | `get-workouts` | List workouts from newest to oldest with exercise and timing details. |
183
- | Workouts | `get-workout` | Get complete details for one workout by ID. |
184
- | Workouts | `get-workout-count` | Return the account's total workout count. |
185
- | Workouts | `get-workout-events` | List workout update and delete events since a timestamp. |
186
- | Workouts | `create-workout` | Create a completed workout in Hevy. |
187
- | Workouts | `update-workout` | Replace an existing workout by ID. |
188
- | Routines | `get-routines` | List custom and default workout routines. |
189
- | Routines | `get-routine` | Get one routine and its exercise configuration by ID. |
190
- | Routines | `create-routine` | Create a reusable workout routine. |
191
- | Routines | `update-routine` | Replace an existing routine's content. |
192
- | Routine folders | `get-routine-folders` | List default and custom routine folders. |
193
- | Routine folders | `get-routine-folder` | Get one routine folder's metadata by ID. |
194
- | Routine folders | `create-routine-folder` | Create a routine folder. |
195
- | Exercise templates/history | `get-exercise-templates` | List exercise templates with equipment and muscle metadata. |
196
- | Exercise templates/history | `get-exercise-template` | Get complete metadata for one exercise template by ID. |
197
- | Exercise templates/history | `search-exercise-templates` | Search the full exercise catalog by title substring. |
198
- | Exercise templates/history | `create-exercise-template` | Create a custom exercise template. |
199
- | Exercise templates/history | `get-exercise-history` | Get past performed sets for one exercise template. |
200
- | Body measurements | `get-body-measurements` | List dated body measurements. |
201
- | Body measurements | `get-body-measurement` | Get the body measurement entry for one date. |
202
- | Body measurements | `create-body-measurement` | Create a dated body measurement. |
203
- | Body measurements | `update-body-measurement` | Update the body measurement for an existing date. |
204
- | Account | `get-user-info` | Return the user's ID, display name, and public profile URL. |
205
-
206
- The Hevy API currently exposes no delete endpoints for workouts, routines,
207
- routine folders, exercise templates, or body measurements, so there are no
208
- corresponding delete tools.
209
-
210
- ### Resources
211
-
212
- | Name | URI | Description |
213
- | -------------------- | --------------------------- | -------------------------------------------- |
214
- | `user-profile` | `hevy://user` | Authenticated Hevy user profile. |
215
- | `workout-count` | `hevy://workout-count` | Total number of workouts in the account. |
216
- | `exercise-templates` | `hevy://exercise-templates` | Full formatted exercise template catalog. |
217
- | `routine-folders` | `hevy://routine-folders` | Full formatted list of Hevy routine folders. |
376
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) to deploy the Cloudflare Worker for
377
+ self-hosted Streamable HTTP.
218
378
 
219
379
  ## Advanced configuration
220
380
 
221
381
  | Setting | Default | Scope | Notes |
222
382
  | ---------------------- | ------------------------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
223
- | `HEVY_API_KEY` | None; required | Local stdio | Hevy API key from the Hevy app. Use the hosted `Authorization` header instead for Streamable HTTP. Never pass the key in a URL. |
224
- | `HEVY_MCP_API_TIMEOUT` | `30000` ms | Local stdio | Positive Hevy API request timeout in milliseconds. Invalid or non-positive values fall back to 30,000 ms. |
225
- | `HEVY_MCP_DEBUG` | Disabled | Local stdio | Only the exact value `1` enables privacy-bounded diagnostics on stderr. Stdout stays reserved for MCP JSON-RPC. |
226
- | `MCP_ALLOWED_ORIGINS` | No browser origins allowed | Self-hosted Cloudflare Worker | Optional comma-separated exact origins. Wildcards are unsupported. Requests without `Origin`, such as desktop clients, remain accepted. |
227
- | `XDG_CACHE_HOME` | `~/.cache` | Local stdio | Changes the root for the best-effort npm version-check cache at `hevy-mcp/update-check.json`. |
228
- | `SENTRY_DSN` | Packaged project DSN | Optional local Node telemetry | Overrides the Sentry destination. An empty value disables Sentry export. The Worker entry point does not import Node telemetry. |
383
+ | `HEVY_API_KEY` | None; required | Local stdio | Hevy API key from the Hevy app. Never pass it in a URL. |
384
+ | `HEVY_MCP_API_TIMEOUT` | `30000` ms | Local stdio | Positive Hevy API timeout in milliseconds. Invalid values fall back to 30 seconds. |
385
+ | `HEVY_MCP_DEBUG` | Disabled | Local stdio | Set to exactly `1` for privacy-bounded diagnostics on stderr. Stdout remains reserved for MCP JSON-RPC. |
386
+ | `MCP_ALLOWED_ORIGINS` | No browser origins allowed | Self-hosted Worker | Optional comma-separated exact origins. Wildcards are unsupported. Requests without `Origin`, such as desktop clients, remain accepted. |
387
+ | `XDG_CACHE_HOME` | `~/.cache` | Local stdio | Changes the root for the npm update-check cache at `hevy-mcp/update-check.json`. |
388
+ | `SENTRY_DSN` | Packaged project DSN | Optional local Node telemetry | Overrides the Sentry destination. An empty value disables Sentry export. The Worker does not import Node telemetry. |
229
389
  | `SENTRY_RELEASE` | `hevy-mcp@<installed-version>` | Optional local Node telemetry | Overrides the release label attached to local Sentry events and traces. |
230
- | `-h`, `--help` | N/A | Local stdio CLI | Print supported options and exit without starting the server. |
231
- | `-v`, `--version` | N/A | Local stdio CLI | Print the installed version and exit without starting the server. |
390
+ | `-h`, `--help` | N/A | Local stdio CLI | Print supported options and exit. |
391
+ | `-v`, `--version` | N/A | Local stdio CLI | Print the installed version and exit. |
232
392
 
233
- The local executable does **not** support `PORT`, `HEVY_MCP_TRANSPORT`, or
234
- `--transport`. It always uses stdio and does not provide local HTTP or SSE
235
- behavior. Use the hosted endpoint after its route is restored, or deploy the
236
- separate Cloudflare Worker when Streamable HTTP is required now.
393
+ The local executable is stdio-only. It does not support `PORT`,
394
+ `HEVY_MCP_TRANSPORT`, or `--transport`, and it does not provide local HTTP or
395
+ SSE behavior.
237
396
 
238
- ## Cache behavior
397
+ ### Cache behavior
239
398
 
240
399
  `search-exercise-templates` and `hevy://exercise-templates` share a
241
400
  server-scoped in-memory catalog cache:
242
401
 
243
- - Entries live for five minutes and the cache holds at most one catalog.
402
+ - Entries live for five minutes, and the cache holds at most one catalog.
244
403
  - Concurrent catalog requests share an in-flight fetch when possible.
245
404
  - `search-exercise-templates` accepts `refresh: true` to invalidate the cache.
246
405
  - Paginated `get-exercise-templates` calls always fetch their requested page.
@@ -249,20 +408,37 @@ server-scoped in-memory catalog cache:
249
408
  ## Security and mutations
250
409
 
251
410
  - Keep `HEVY_API_KEY` out of source control, URLs, logs, and screenshots.
252
- - Local clients provide the key through the child process environment. Hosted
253
- clients send it only in `Authorization: Bearer <HEVY_API_KEY>`.
254
- - The hosted Worker validates each key with Hevy, does not store it, and sends
255
- it upstream only as Hevy's `api-key` header.
411
+ - Local clients provide the key through the child process environment.
412
+ - Hosted clients send the key only in the `Authorization: Bearer` header. The
413
+ Worker validates each key with Hevy, does not store it, and sends it upstream
414
+ only as Hevy's `api-key` header.
256
415
  - Browser requests to a self-hosted Worker must exactly match an origin in
257
416
  `MCP_ALLOWED_ORIGINS`; wildcard CORS is intentionally unsupported.
258
417
  - Create operations can produce duplicates when retried. Update operations
259
418
  replace existing records. Review tool inputs and use client confirmations.
260
419
 
261
- ## Contributing and self-hosting
420
+ ## Troubleshooting
421
+
422
+ - **The server does not appear:** restart or reconnect your MCP client after
423
+ changing its configuration.
424
+ - **`npx` fails:** confirm that Node.js 20 or newer is installed, then run
425
+ `npx -y hevy-mcp --version` in a terminal.
426
+ - **Codex cannot see the server:** run `codex mcp list`, then start a new Codex
427
+ session after confirming the `hevy` entry exists.
428
+ - **Hosted authentication fails:** confirm the key is active, belongs to a Hevy
429
+ PRO account, and is sent as `Authorization: Bearer <HEVY_API_KEY>`.
430
+ - **Local authentication fails:** confirm the key is active and available to the
431
+ MCP child process as `HEVY_API_KEY`.
432
+ - **Need diagnostics:** set `HEVY_MCP_DEBUG=1`. Diagnostic output goes to stderr
433
+ and does not interfere with MCP messages on stdout.
434
+
435
+ If you find a bug or have a feature request, [open an issue](https://github.com/chrisdoc/hevy-mcp/issues).
436
+
437
+ ## Contributing
262
438
 
263
- Developer setup, testing lanes, generated-client workflows, Cloudflare Worker
264
- deployment, and pull request rules live in the
265
- [contributor guide](https://github.com/chrisdoc/hevy-mcp/blob/main/CONTRIBUTING.md).
439
+ Contributions are welcome. Developer setup, testing lanes, generated-client
440
+ workflows, Cloudflare Worker deployment, and pull request rules are documented
441
+ in [CONTRIBUTING.md](./CONTRIBUTING.md).
266
442
 
267
443
  ## License and acknowledgements
268
444
 
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@3.1.1" };
7
+ e.SENTRY_RELEASE = { id: "hevy-mcp@3.2.1" };
8
8
  var n = new e.Error().stack;
9
9
  n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "47a79c69-c982-44cf-abda-d010f962b955", e._sentryDebugIdIdentifier = "sentry-dbid-47a79c69-c982-44cf-abda-d010f962b955");
10
10
  } catch (e) {}
11
11
  })();
12
- import { i as createSafeErrorDiagnostic, r as runServer } from "./src-CkkrTrrg.mjs";
12
+ import { i as createSafeErrorDiagnostic, r as runServer } from "./src-D1O3O9f2.mjs";
13
13
  //#region src/cli.ts
14
14
  runServer().catch((error) => {
15
15
  console.error("Fatal error in main()", createSafeErrorDiagnostic(error));
package/dist/index.d.mts CHANGED
@@ -1,6 +1,5 @@
1
1
 
2
2
  import { z } from "zod";
3
-
4
3
  //#region src/index.d.ts
5
4
  declare const serverConfigSchema: z.ZodObject<{
6
5
  apiKey: z.ZodString;
@@ -9,9 +8,7 @@ declare const configSchema: z.ZodObject<{
9
8
  apiKey: z.ZodString;
10
9
  }, z.core.$strip>;
11
10
  type ServerConfig = z.infer<typeof serverConfigSchema>;
12
- declare function createServer({
13
- config
14
- }: {
11
+ declare function createServer({ config }: {
15
12
  config: ServerConfig;
16
13
  }): Promise<import("@modelcontextprotocol/sdk/server/mcp").McpServer>;
17
14
  declare function runServer(): Promise<void>;
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@3.1.1" };
7
+ e.SENTRY_RELEASE = { id: "hevy-mcp@3.2.1" };
8
8
  var n = new e.Error().stack;
9
9
  n && (e._sentryDebugIds = e._sentryDebugIds || {}, e._sentryDebugIds[n] = "5b077b94-9ef8-4f24-a0b0-8dcfbf491be1", e._sentryDebugIdIdentifier = "sentry-dbid-5b077b94-9ef8-4f24-a0b0-8dcfbf491be1");
10
10
  } catch (e) {}
11
11
  })();
12
- import { n as createServer, r as runServer, t as configSchema } from "./src-CkkrTrrg.mjs";
12
+ import { n as createServer, r as runServer, t as configSchema } from "./src-D1O3O9f2.mjs";
13
13
  export { configSchema, createServer, createServer as default, runServer };