Hevy MCP Pro
# @cdorneles/hevy-mcp-pro
A production-ready [Model Context Protocol](https://modelcontextprotocol.io) server for the [Hevy](https://www.hevyapp.com) fitness API. Exposes 27 tools for reading, writing, and analyzing your workout data — designed for "personal trainer via LLM" workflows in Claude Desktop, Claude Code, and Cursor.
[](https://github.com/cbotworks/mcp-hevy-pro/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/@cdorneles/hevy-mcp-pro)
[](LICENSE)
## What sets this apart
Compared to the existing community Hevy MCP server, `hevy-mcp-pro` adds:
- **Local analytics**: progression series, personal records (Epley 1RM), volume summaries, frequency stats, and stagnation detection — computed locally from your data, not via the Hevy API.
- **Smart fetching**: single-exercise analytics use Hevy's `/exercise_history` endpoint (one call, full history) instead of paginating all workouts.
- **Robust HTTP client**: token-bucket throttling, exponential backoff with jitter on 429/5xx, honors `Retry-After`, and never logs your API key.
- **Strict request validation**: Zod schemas reject malformed payloads before they hit the Hevy API.
- **Convenience tools**: `duplicate_workout`, `routine_from_workout`, `compare_workouts`.
## Requirements
- Node.js 20+
- A [Hevy PRO subscription](https://www.hevyapp.com/pro) (required to obtain an API key)
- Your Hevy API key from [hevy.com/settings?p=developer](https://www.hevy.com/settings?p=developer)
## Quick start
### Claude Desktop
Edit `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows):
```json
{
"mcpServers": {
"hevy": {
"command": "npx",
"args": ["-y", "@cdorneles/hevy-mcp-pro"],
"env": {
"HEVY_API_KEY": "your-key-here"
}
}
}
}
```
Restart Claude Desktop and you should see "hevy" in the MCP tool picker.
### Cursor
Add to `~/.cursor/mcp.json`:
```json
{
"mcpServers": {
"hevy": {
"command": "npx",
"args": ["-y", "@cdorneles/hevy-mcp-pro"],
"env": { "HEVY_API_KEY": "your-key-here" }
}
}
}
```
### Claude Code
```bash
claude mcp add hevy npx -- -y @cdorneles/hevy-mcp-pro
# then set HEVY_API_KEY in the resulting config
```
## Tools
### Reading
| Tool | Purpose |
|---|---|
| `list_workouts` | Paginate workouts (max pageSize 10 — Hevy API limit) |
| `get_workout` | Fetch a single workout with all sets |
| `get_workout_count` | Total workout count for the account |
| `get_workout_events` | Sync incremental updates/deletes since a timestamp |
| `list_routines` | Paginate routines |
| `get_routine` | Fetch a single routine |
| `list_exercise_templates` | Paginate exercise templates |
| `get_exercise_template` | Fetch one template |
| `search_exercise_templates` | Local fuzzy search across all templates (cached) |
| `get_exercise_history` | Flat history of every set for one exercise |
| `list_routine_folders` | Paginate folders |
| `get_routine_folder` | Fetch one folder |
| `get_user_info` | Authenticated user profile |
### Writing
| Tool | Purpose |
|---|---|
| `create_workout` | Log a new workout |
| `update_workout` | Modify an existing workout |
| `create_routine` | Create a routine template |
| `update_routine` | Modify an existing routine |
| `create_routine_folder` | Create a new folder |
| `create_exercise_template` | Create a custom exercise |
### Analytics
| Tool | Purpose |
|---|---|
| `get_exercise_progression` | Time series of best set per session for one exercise |
| `get_personal_records` | PRs (heaviest weight, best set, top estimated 1RM) |
| `get_volume_summary` | Volume grouped by exercise / muscle group / week |
| `get_workout_frequency` | Workouts/week, current streak, longest gap |
| `detect_stagnation` | Exercises whose 1RM has plateaued in the last N weeks |
### Convenience
| Tool | Purpose |
|---|---|
| `duplicate_workout` | Re-log a past workout starting now (or at a given time) |
| `routine_from_workout` | Convert a logged workout into a reusable routine |
| `compare_workouts` | Side-by-side diff of two workouts |
## Configuration
All configuration is via environment variables.
| Variable | Required | Default | Description |
|---|---|---|---|
| `HEVY_API_KEY` | yes | — | Your Hevy API key |
| `LOG_LEVEL` | no | `info` | `error` \| `warn` \| `info` \| `debug` |
| `HEVY_RATE_LIMIT_CAPACITY` | no | `10` | Token bucket capacity (max burst) |
| `HEVY_RATE_LIMIT_REFILL_PER_SEC` | no | `10` | Token refill rate (requests/sec) |
| `HEVY_ANALYTICS_MAX_PAGES` | no | `50` | Soft cap for analytics pagination (50 pages = 500 workouts) |
| `HEVY_CACHE_TTL_MS` | no | `3600000` | Exercise template cache TTL (default 1h) |
## Example prompts
Once installed, you can ask your LLM things like:
> "Show me my bench press progression over the last 3 months."
> "What are my current personal records on squats, deadlifts, and bench?"
> "Detect any exercises where I've stagnated in the last 8 weeks."
> "Duplicate yesterday's workout and start it now."
> "Compare my last two leg days."
> "How many times did I train chest in March?"
## Troubleshooting
### `Invalid API key or Hevy PRO subscription required`
Confirm you have a Hevy PRO subscription and that the key from [hevy.com/settings?p=developer](https://www.hevy.com/settings?p=developer) is correctly set in `HEVY_API_KEY`. The key never appears in logs, so a typo is the most common cause.
### `Rate limited by Hevy API (retries exhausted)`
The default client-side throttle is 10 req/s. If you're running heavy analytics queries against a long workout history, lower `HEVY_RATE_LIMIT_REFILL_PER_SEC` to e.g. `5` to slow down further.
### `Analysis limited to first 500 workouts`
Analytics tools paginate workouts with a soft cap. Raise `HEVY_ANALYTICS_MAX_PAGES` if you need to analyze deeper history. Each page is up to 10 workouts.
### Logs
This server writes structured JSON logs to **stderr** (stdout is reserved for the MCP protocol). To debug, set `LOG_LEVEL=debug` and check your MCP client's server log view.
## Development
```bash
git clone https://github.com/cbotworks/mcp-hevy-pro.git
cd hevy-mcp-pro
pnpm install
pnpm test # 41+ unit tests, no network
pnpm typecheck
pnpm lint
pnpm build # produces dist/ (ESM + CJS + .d.ts)
```
To regenerate the vendored OpenAPI snapshot:
```bash
pnpm fetch-openapi
```
## Architecture
```
src/
├── client/ HTTP layer (rate limiter, retry, error mapping, paginator)
├── schemas/ Zod schemas for API requests + responses
├── tools/ Tool implementations grouped by domain
│ └── analytics/ Pure analyzers (progression, PRs, volume, frequency, stagnation)
├── utils/ Logger, errors, TTL cache
├── server.ts MCP server: registers tools, wires stdio transport
└── index.ts CLI entry: parses env, fails fast on missing API key
```
The HTTP client owns all network I/O. Tools never call `fetch` directly. Analytics tools are pure functions over data fetched via the client, which makes them trivially fixture-testable.
## Contributing
Issues and PRs welcome. Please run `pnpm typecheck && pnpm lint && pnpm test` before submitting.
## License
MIT — see [LICENSE](LICENSE).
## Acknowledgements
The Hevy team for the public API. The community [chrisdoc/hevy-mcp](https://github.com/chrisdoc/hevy-mcp) server informed early API exploration but no code was reused.
TDQS
Scored across 27 tools
Each tool targets a distinct entity and action, with clear separation between list/get/create/update and analytical operations. Even similar tools like search_exercise_templates and list_exercise_templates have clearly differentiated purposes described in their summaries.
The vast majority of tools follow a consistent verb_noun snake_case pattern (e.g., list_workouts, create_workout, get_exercise_history). The single exception is 'routine_from_workout', which deviates from the pattern but remains readable and clear.
With 27 tools, the server is heavier than the ideal 3-15 range, but the breadth covers multiple entities (workouts, routines, templates, folders) plus analytics. The count feels justified for a feature-rich API, though it is borderline excessive.
The server lacks delete operations for all entities (workouts, routines, exercise templates, routine folders), preventing full lifecycle management. While CRUD for create/get/update exists, the inability to delete creates dead ends and forces workarounds.