hevy-mcp 3.0.0 → 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,415 +1,447 @@
1
- # hevy-mcp: Model Context Protocol Server for Hevy Fitness API
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
- A Model Context Protocol (MCP) server implementation that interfaces with the [Hevy fitness tracking app](https://www.hevyapp.com/) and its [API](https://api.hevyapp.com/docs/). This server enables AI assistants like **Claude Desktop** and **Cursor** to access and manage workout data, routines, and exercise templates through the Hevy API (requires PRO subscription).
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)
9
16
 
10
- ---
17
+ </div>
11
18
 
12
- ## 📋 Table of Contents
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.
13
24
 
14
- - [Features](#features)
15
- - [Quick Start](#quick-start)
16
- - [Prerequisites](#prerequisites)
17
- - [Installation](#installation)
18
- - [Run with Docker](#run-with-docker)
19
- - [Claude Desktop Configuration](#claude-desktop-configuration)
20
- - [Cursor Configuration](#cursor-configuration)
21
- - [Other MCP Clients (via add-mcp)](#other-mcp-clients-via-add-mcp)
22
- - [Why hevy-mcp?](#why-hevy-mcp)
23
- - [Configuration](#configuration)
24
- - [Available MCP Tools](#available-mcp-tools)
25
- - [Available MCP Resources](#available-mcp-resources)
26
- - [Development & Contributing](#development--contributing)
25
+ > A Hevy API key, available with **Hevy PRO**, is required.
27
26
 
28
- ---
27
+ ## See it in action
29
28
 
30
- ## 🚀 Features
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)
31
30
 
32
- - **Workout Management**: Fetch, create, and update workouts.
33
- - **Routine Management**: Access and manage workout routines.
34
- - **Exercise Templates**: Browse available exercise templates with in-memory caching.
35
- - **Folder Organization**: Manage routine folders.
31
+ <p align="center"><sub>Click the preview to play the full-quality 18-second demo.</sub></p>
36
32
 
37
- ---
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.
38
35
 
39
- ## 🏁 Quick Start
36
+ ## What can you do with it?
40
37
 
41
- Pick the workflow that fits your setup:
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.
42
52
 
43
- | Scenario | Command | Requirements |
44
- | :-------------------- | :-------------------------------------------------------------------------------------- | :------------------------- |
45
- | **One-off stdio run** | `HEVY_API_KEY=your_key npx -y hevy-mcp` or `HEVY_API_KEY=your_key bunx hevy-mcp@latest` | Node.js ≥ 20, Hevy API key |
46
- | **Docker stdio run** | `docker run -i --rm -e HEVY_API_KEY ghcr.io/chrisdoc/hevy-mcp:latest` | Docker, Hevy API key |
47
- | **Local development** | `npm install && npm run build && npm start` | `.env` with `HEVY_API_KEY` |
53
+ Try asking:
48
54
 
49
- ---
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.
50
58
 
51
- ## 🛠️ Prerequisites
59
+ > Find my push-day routine and show its exercises and sets.
52
60
 
53
- - **Node.js**: v20 or higher (strongly recommended to use the exact version pinned in `.nvmrc`).
54
- - **npm**: v10 or higher.
55
- - **Bun** (optional): If you want to launch with `bunx`.
56
- - **Docker** (optional): If you want an isolated container-based stdio setup.
57
- - **Hevy API key**: Required for all operations (available with Hevy PRO).
61
+ > Compare my recent body measurements with my training consistency.
58
62
 
59
- ---
63
+ > Create a completed workout from my saved routine. Ask me for any missing set
64
+ > results before writing it to Hevy.
60
65
 
61
- ## 📦 Installation
66
+ ## Quick start
62
67
 
63
- ### Run via npx or bunx
68
+ ### 1. Get your Hevy API key
64
69
 
65
- You can launch the server directly without cloning. Both launchers are covered
66
- by nightly smoke tests:
70
+ Create an API key in Hevy, then keep it somewhere secure. API access currently
71
+ requires a Hevy PRO subscription.
67
72
 
68
- ```bash
69
- # npm launcher
70
- HEVY_API_KEY=your_hevy_api_key_here npx -y hevy-mcp
71
-
72
- # bun launcher
73
- HEVY_API_KEY=your_hevy_api_key_here bunx hevy-mcp@latest
74
- ```
73
+ ### 2. Connect `hevy-mcp` to your client
75
74
 
76
- ### Manual Installation
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
77
 
78
- ```bash
79
- # Clone the repository
80
- git clone https://github.com/chrisdoc/hevy-mcp.git
81
- cd hevy-mcp
78
+ #### Connect to the hosted endpoint
82
79
 
83
- # Install dependencies
84
- npm install
80
+ Production URL:
85
81
 
86
- # Create .env and add your keys
87
- cp .env.sample .env
88
- # Edit .env and add your HEVY_API_KEY
82
+ ```text
83
+ https://hevy.chrisdoc.dev/mcp
89
84
  ```
90
85
 
91
- ### Run with Docker
86
+ The endpoint uses Streamable HTTP. Send your Hevy API key as a bearer token on
87
+ every request.
88
+
89
+ ##### Codex
92
90
 
93
- Official multi-platform images are published to GitHub Container Registry for
94
- `linux/amd64` and `linux/arm64`:
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:
95
94
 
96
95
  ```bash
97
- export HEVY_API_KEY=your_hevy_api_key_here
98
- docker run -i --rm -e HEVY_API_KEY ghcr.io/chrisdoc/hevy-mcp:latest
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
99
100
  ```
100
101
 
101
- The server uses stdio, so `-i` keeps standard input open for the MCP client.
102
- `--rm` removes the stopped container automatically. The `-e HEVY_API_KEY`
103
- form forwards the variable from the host environment without putting the key
104
- in the command arguments.
105
-
106
- The image uses the official Node.js LTS Alpine base, runs as the non-root
107
- `node` user, and ships the application and its third-party runtime dependencies
108
- as a standalone bundle. It does not include an application `/app/node_modules`
109
- directory; the official Node base image may still contain its own globally
110
- packaged npm or Corepack files.
111
-
112
- Use `latest` to follow the newest stable release. For reproducible deployments,
113
- pin the exact version shown on the release, using a tag such as
114
- `ghcr.io/chrisdoc/hevy-mcp:X.Y.Z`. Major (`:X`) and major.minor (`:X.Y`) tags
115
- are also published for controlled automatic updates.
116
-
117
- ---
118
-
119
- ## 🔗 Integration
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.
120
105
 
121
- ### Claude Desktop Configuration
106
+ ##### Other Streamable HTTP clients
122
107
 
123
- To use this server with Claude Desktop, add the following to your `claude_desktop_config.json`:
124
-
125
- **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
126
- **Windows**: `%APPDATA%\Claude\claude_desktop_config.json`
108
+ Clients that accept a remote MCP URL and fixed headers commonly use this shape:
127
109
 
128
110
  ```json
129
111
  {
130
112
  "mcpServers": {
131
- "hevy-mcp": {
132
- "command": "npx",
133
- "args": ["-y", "hevy-mcp"],
134
- "env": {
135
- "HEVY_API_KEY": "sk_live_your_key_here"
113
+ "hevy": {
114
+ "url": "https://hevy.chrisdoc.dev/mcp",
115
+ "headers": {
116
+ "Authorization": "Bearer your-hevy-api-key"
136
117
  }
137
118
  }
138
119
  }
139
120
  }
140
121
  ```
141
122
 
142
- If you prefer Bun, swap the launcher fields:
123
+ Exact configuration keys vary by client. The hosted server requires support for
124
+ Streamable HTTP and a fixed `Authorization` header.
143
125
 
144
- ```json
145
- {
146
- "command": "bunx",
147
- "args": ["hevy-mcp@latest"]
148
- }
149
- ```
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.
150
130
 
151
- To run Claude Desktop through Docker instead, first create an environment file
152
- outside the repository containing your real key:
131
+ #### Run locally instead
153
132
 
154
- ```dotenv
155
- HEVY_API_KEY=replace_with_your_real_key
156
- ```
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.
157
135
 
158
- Restrict access to that file where supported (for example,
159
- `chmod 600 /absolute/path/to/hevy-mcp.env`), then use its absolute path in the
160
- Claude Desktop configuration:
136
+ ##### Codex
161
137
 
162
- ```json
163
- {
164
- "mcpServers": {
165
- "hevy-mcp": {
166
- "command": "docker",
167
- "args": [
168
- "run",
169
- "-i",
170
- "--rm",
171
- "--env-file",
172
- "/absolute/path/to/hevy-mcp.env",
173
- "ghcr.io/chrisdoc/hevy-mcp:latest"
174
- ]
175
- }
176
- }
177
- }
138
+ ```bash
139
+ codex mcp add hevy \
140
+ --env HEVY_API_KEY=your-hevy-api-key \
141
+ -- npx -y hevy-mcp
178
142
  ```
179
143
 
180
- This configuration runs the same stdio server inside the container; it does
181
- not expose an HTTP port or start a detached service. Docker reads the key from
182
- the environment file, so the Claude configuration does not replace an
183
- inherited key with a placeholder. Replace `latest` with an exact version tag if
184
- you want Claude Desktop to stay on a pinned release.
185
-
186
- ### Cursor Configuration
144
+ ##### Claude Desktop or Cursor
187
145
 
188
- Add this server under `"mcpServers"` in `~/.cursor/mcp.json`:
146
+ Add this `mcpServers` entry to your client configuration:
189
147
 
190
148
  ```json
191
149
  {
192
150
  "mcpServers": {
193
- "hevy-mcp": {
151
+ "hevy": {
194
152
  "command": "npx",
195
153
  "args": ["-y", "hevy-mcp"],
196
154
  "env": {
197
- "HEVY_API_KEY": "your-api-key-here"
155
+ "HEVY_API_KEY": "your-hevy-api-key"
198
156
  }
199
157
  }
200
158
  }
201
159
  }
202
160
  ```
203
161
 
204
- If you prefer Bun, swap the launcher fields:
205
-
206
- ```json
207
- {
208
- "command": "bunx",
209
- "args": ["hevy-mcp@latest"]
210
- }
211
- ```
212
-
213
- ### Other MCP Clients (via add-mcp)
214
-
215
- For a generic setup flow across MCP clients, use [`add-mcp`](https://github.com/neon-solutions/add-mcp):
216
-
217
- ```bash
218
- npx add-mcp hevy-mcp --env "HEVY_API_KEY=secret"
219
- ```
220
-
221
- This bootstraps the `hevy-mcp` entry in your client config without manual JSON edits.
222
-
223
- ---
224
-
225
- ## ✨ Why hevy-mcp?
162
+ Common local configuration locations:
226
163
 
227
- - 🚀 **High Performance**: Built with the **Oxc** toolchain (`oxlint`/`oxfmt`) for near-instant linting and formatting.
228
- - 🛡️ **Type Safety**: Fully type-safe implementation using **Zod** and **Kubb**-generated API clients.
229
- - 📉 **Observability**: Built-in **Sentry** monitoring for error tracking, lifecycle and tool tracing, and stdio parse diagnostics.
230
- - ⚡ **Optimized**: Includes in-memory caching for exercise templates to reduce API latency.
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`
231
169
 
232
- ---
170
+ Restart or reconnect the client after saving the file.
233
171
 
234
- ## ⚙️ Configuration
172
+ ##### Any stdio MCP client
235
173
 
236
- Supply your Hevy API key via the `HEVY_API_KEY` environment variable (in
237
- `.env` or system environment).
174
+ Configure your client to launch this command with `HEVY_API_KEY` in the child
175
+ process environment:
238
176
 
239
- Set `HEVY_MCP_API_TIMEOUT` to override the default 30-second Hevy API request
240
- timeout. Its value is in milliseconds.
241
-
242
- Set `HEVY_MCP_DEBUG=1` to emit verbose, privacy-bounded diagnostics to stderr.
243
- Debug records include tool invocations and sanitized Hevy API response timing
244
- and status details. Other values leave diagnostics disabled, and stdout remains
245
- reserved for the MCP JSON-RPC stream.
246
-
247
- ```env
248
- # Example .env
249
- HEVY_API_KEY=your_hevy_api_key_here
250
- # Optional: customize Hevy API request timeout (milliseconds)
251
- HEVY_MCP_API_TIMEOUT=30000
252
- # Optional: enable verbose stderr diagnostics (only the value 1 enables it)
253
- HEVY_MCP_DEBUG=1
177
+ ```bash
178
+ npx -y hevy-mcp
254
179
  ```
255
180
 
256
- ### 🧠 Exercise Template Cache Behavior
257
-
258
- `search-exercise-templates` and the `hevy://exercise-templates` resource use a
259
- shared in-memory async cache for the full exercise template catalog:
260
-
261
- - **TTL**: 5 minutes per cached catalog entry.
262
- - **Memory bound**: max 1 catalog entry (LRU bounded cache).
263
- - **In-flight de-duplication**: concurrent requests share the same active
264
- fetch when possible.
265
- - **Manual refresh**: set `refresh: true` in the tool input to invalidate the
266
- cached catalog and force a re-fetch from the Hevy API.
267
-
268
- Paginated `get-exercise-templates` requests still call the API directly to keep
269
- paging behavior explicit and avoid cross-page invalidation complexity.
270
-
271
- ### 📡 Sentry Monitoring
272
-
273
- `hevy-mcp` includes Sentry monitoring to observe errors and usage in production. It initializes `@sentry/node` with tracing enabled and PII collection disabled by default. Recent observability changes also add:
274
-
275
- - lifecycle spans around server build, run, and stdio connect
276
- - per-tool execution spans plus captured handler exceptions
277
- - stdio parse diagnostics, including leading UTF-8 BOM stripping and invalid JSON context
278
- - a deterministic pseudonymous Sentry user ID derived from `HEVY_API_KEY`, so the raw key is never sent to Sentry
279
-
280
- ---
181
+ `npx` requires Node.js 20 or newer. Restart or reconnect your client after
182
+ saving its configuration.
281
183
 
282
184
  <details>
283
- <summary><strong>⚠️ Migration Note (v1.18.0)</strong></summary>
185
+ <summary><strong>Use bunx instead</strong></summary>
284
186
 
285
- As of **v1.18.0**, `hevy-mcp` removed HTTP/SSE transport and its previous
286
- Docker packaging. Docker support is now available again for the stdio server.
187
+ Requires [Bun](https://bun.sh/):
287
188
 
288
- Both `npx hevy-mcp` and the official container image use stdio; HTTP ports and
289
- detached-container deployment are not supported.
189
+ ```json
190
+ {
191
+ "mcpServers": {
192
+ "hevy": {
193
+ "command": "bunx",
194
+ "args": ["hevy-mcp@latest"],
195
+ "env": {
196
+ "HEVY_API_KEY": "your-hevy-api-key"
197
+ }
198
+ }
199
+ }
200
+ }
201
+ ```
290
202
 
291
203
  </details>
292
204
 
293
- ---
294
-
295
- ## 🛠️ Available MCP Tools
205
+ <details>
206
+ <summary><strong>Use Docker instead</strong></summary>
296
207
 
297
- | Category | Tools |
298
- | :-------------------- | :--------------------------------------------------------------------------------------------------------------------------------- |
299
- | **Workouts** | `get-workouts`, `get-workout`, `create-workout`, `update-workout`, `get-workout-count`, `get-workout-events` |
300
- | **Routines** | `get-routines`, `get-routine`, `create-routine`, `update-routine` |
301
- | **Templates** | `get-exercise-templates`, `get-exercise-template`, `search-exercise-templates`, `create-exercise-template`, `get-exercise-history` |
302
- | **Folders** | `get-routine-folders`, `get-routine-folder`, `create-routine-folder` |
303
- | **Body Measurements** | `get-body-measurements`, `get-body-measurement`, `create-body-measurement`, `update-body-measurement` |
304
- | **User** | `get-user-info` |
208
+ Official images support `linux/amd64` and `linux/arm64`. Keep stdin open with
209
+ `-i` because the container runs the stdio MCP server:
305
210
 
306
- > **Delete operations are currently unsupported:** The upstream Hevy OpenAPI
307
- > spec does not expose `DELETE` endpoints for workouts, routines, routine
308
- > folders, exercise templates, or body measurements, so `hevy-mcp` does not
309
- > provide delete tools for these resources.
211
+ ```bash
212
+ export HEVY_API_KEY=your-hevy-api-key
213
+ docker run -i --rm -e HEVY_API_KEY ghcr.io/chrisdoc/hevy-mcp:latest
214
+ ```
310
215
 
311
- ## 💬 Available MCP Prompts
216
+ For an MCP client, store the key in a protected environment file and configure
217
+ the client to launch Docker:
312
218
 
313
- | Prompt | Arguments | Guided workflow |
314
- | :---------------------------- | :------------------------------------------------------------------------------------- | :---------------------------------------------------- |
315
- | `analyze-workout-progress` | Optional `weeks` (1-12; defaults to `4` when omitted from a supplied arguments object) | Analyze recent workout and body-measurement trends. |
316
- | `create-workout-from-routine` | `routineId`, `startTime` (UTC ISO seconds) | Record a completed workout using a routine as a plan. |
219
+ ```json
220
+ {
221
+ "mcpServers": {
222
+ "hevy": {
223
+ "command": "docker",
224
+ "args": [
225
+ "run",
226
+ "-i",
227
+ "--rm",
228
+ "--env-file",
229
+ "/absolute/path/to/hevy-mcp.env",
230
+ "ghcr.io/chrisdoc/hevy-mcp:latest"
231
+ ]
232
+ }
233
+ }
234
+ }
235
+ ```
317
236
 
318
- Compatibility note: with MCP SDK v1.29.0, clients using the default must send
319
- `arguments: {}` because the SDK rejects requests that omit the entire
320
- `arguments` object before prompt field defaults are evaluated.
237
+ Pin an exact image tag such as `ghcr.io/chrisdoc/hevy-mcp:X.Y.Z` when you need
238
+ reproducible upgrades.
321
239
 
322
- ---
240
+ </details>
323
241
 
324
- ## 📚 Available MCP Resources
242
+ You can also add the npm server to supported clients with
243
+ [`add-mcp`](https://github.com/neon-solutions/add-mcp):
325
244
 
326
- | Name | URI |
327
- | :------------------- | :-------------------------- |
328
- | `user-profile` | `hevy://user` |
329
- | `workout-count` | `hevy://workout-count` |
330
- | `exercise-templates` | `hevy://exercise-templates` |
331
- | `routine-folders` | `hevy://routine-folders` |
245
+ ```bash
246
+ npx add-mcp hevy-mcp --env "HEVY_API_KEY=your-hevy-api-key"
247
+ ```
332
248
 
333
- ---
249
+ ### 3. Ask your first question
334
250
 
335
- ## 👨‍💻 Development & Contributing
251
+ Try one of these after restarting or reconnecting your MCP client:
336
252
 
337
- ### Quick Commands
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?”
338
258
 
339
- - **Build**: `npm run build`
340
- - **Lint/Format**: `npm run check` (uses oxlint/oxfmt)
341
- - **Type Check**: `npm run check:types`
342
- - **Unit Tests**: `npm run test:unit`
343
- - **Full Vitest Discovery**: `npm test` (builds first; live tests skip when
344
- `HEVY_API_KEY` is absent)
345
- - **Changeset Check**: `npm run check:changeset`
346
- - **Tool Token Cost**: `npm run measure:tokens` ([measurement guide](./docs/token-cost-tracking.md))
259
+ Your assistant should ask for approval before mutation tools when the client
260
+ supports tool confirmations.
347
261
 
348
- For a detailed senior engineer guide, please refer to [AGENTS.md](./AGENTS.md).
262
+ ## How it works
349
263
 
350
- ### Pull Request Checks
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
+ ```
351
268
 
352
- - **Conventional Commits**: CI lints commit messages on pull requests, so use
353
- prefixes such as `feat:`, `fix:`, `docs:`, `ci:`, `chore:`, `refactor:`,
354
- `test:`, or `style:`.
355
- - **Type Checking**: CI runs `npm run check:types` on pull requests and pushes
356
- to `main`; run this locally before opening a PR.
357
- - **Changesets**: Contributor pull requests targeting `main` must include a
358
- changeset. Dependabot PRs and automated `changeset-release/main` release PRs
359
- are handled by automation and skip this check.
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:
341
+
342
+ ```text
343
+ https://hevy.chrisdoc.dev/mcp
344
+ ```
360
345
 
361
- ### API Client Generation
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.
362
349
 
363
- The API client is automatically generated from the OpenAPI spec using [Kubb](https://kubb.dev/):
350
+ The Cloudflare Worker uses stateless **Streamable HTTP** at `POST /mcp`.
351
+ Clients must send their Hevy API key as a fixed authorization header:
364
352
 
365
- ```bash
366
- npm run build:client
353
+ ```json
354
+ {
355
+ "mcpServers": {
356
+ "hevy": {
357
+ "url": "https://hevy.chrisdoc.dev/mcp",
358
+ "headers": {
359
+ "Authorization": "Bearer your-hevy-api-key"
360
+ }
361
+ }
362
+ }
363
+ }
367
364
  ```
368
365
 
369
- ### Versioning & Releases
370
-
371
- This project uses [Changesets](https://github.com/changesets/changesets) to
372
- manage versioning, changelogs, releases, and pull request validation.
373
-
374
- 1. **Routine Release Cadence**: Merge the automated
375
- `changeset-release/main` (**"Version Packages"**) Pull Request on a regular
376
- cadence (weekly is a good default) instead of ad-hoc frequent merges.
377
- 2. **Urgent Release Exception**: Security fixes and high-impact,
378
- user-facing bug fixes can be released immediately outside the routine
379
- cadence.
380
- 3. **Use Bump Changesets Only for User-Facing Runtime Changes**: If your
381
- change is user-facing/runtime-visible, run:
382
- ```bash
383
- npx changeset
384
- ```
385
- Follow the prompts to choose `patch`, `minor`, or `major`, then write a
386
- short summary. This creates a markdown file under `.changeset/`.
387
- 4. **Use Empty Changesets for Internal-Only Work**: Docs, CI, test-only,
388
- refactor, and chore changes should use an empty changeset:
389
- ```bash
390
- npx changeset --empty
391
- ```
392
- 5. **Validate Before Opening a PR**: Contributor pull requests targeting
393
- `main` are checked for a changeset in CI. Dependabot PRs and automated
394
- `changeset-release/main` release PRs are handled separately. You can run the
395
- same validation locally with:
396
- ```bash
397
- npm run check:changeset
398
- ```
399
- 6. **Automated Releases**:
400
- - Pushing changesets to `main` triggers a GitHub Action that automatically
401
- creates or updates a **"Version Packages"** Pull Request.
402
- - When this Pull Request is merged, the package is automatically built,
403
- published to npm (via OIDC Trusted Publishing), and a GitHub Release is
404
- created.
405
-
406
- ---
407
-
408
- ## 📄 License & Acknowledgements
409
-
410
- - **License**: [MIT](./LICENSE)
411
- - **Credits**: [Model Context Protocol](https://github.com/modelcontextprotocol), [Hevy Fitness](https://www.hevyapp.com/).
412
-
413
- ---
414
-
415
- **Contributions are welcome!** Please open an issue or PR for any major changes.
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.
369
+
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.
373
+
374
+ ### Self-host the Worker
375
+
376
+ See [CONTRIBUTING.md](./CONTRIBUTING.md) to deploy the Cloudflare Worker for
377
+ self-hosted Streamable HTTP.
378
+
379
+ ## Advanced configuration
380
+
381
+ | Setting | Default | Scope | Notes |
382
+ | ---------------------- | ------------------------------ | ----------------------------- | --------------------------------------------------------------------------------------------------------------------------------------- |
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. |
389
+ | `SENTRY_RELEASE` | `hevy-mcp@<installed-version>` | Optional local Node telemetry | Overrides the release label attached to local Sentry events and traces. |
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. |
392
+
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.
396
+
397
+ ### Cache behavior
398
+
399
+ `search-exercise-templates` and `hevy://exercise-templates` share a
400
+ server-scoped in-memory catalog cache:
401
+
402
+ - Entries live for five minutes, and the cache holds at most one catalog.
403
+ - Concurrent catalog requests share an in-flight fetch when possible.
404
+ - `search-exercise-templates` accepts `refresh: true` to invalidate the cache.
405
+ - Paginated `get-exercise-templates` calls always fetch their requested page.
406
+ - Each hosted Worker request gets a fresh cache, preventing cross-key sharing.
407
+
408
+ ## Security and mutations
409
+
410
+ - Keep `HEVY_API_KEY` out of source control, URLs, logs, and screenshots.
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.
415
+ - Browser requests to a self-hosted Worker must exactly match an origin in
416
+ `MCP_ALLOWED_ORIGINS`; wildcard CORS is intentionally unsupported.
417
+ - Create operations can produce duplicates when retried. Update operations
418
+ replace existing records. Review tool inputs and use client confirmations.
419
+
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
438
+
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).
442
+
443
+ ## License and acknowledgements
444
+
445
+ - **License:** [MIT](./LICENSE)
446
+ - **Credits:** [Model Context Protocol](https://github.com/modelcontextprotocol)
447
+ and [Hevy Fitness](https://www.hevyapp.com/)