- Rust 94.8%
- Python 3.2%
- Dockerfile 1.1%
- Shell 0.9%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
| .forgejo/workflows | ||
| scripts | ||
| src | ||
| .gitignore | ||
| AGENTS.md | ||
| Cargo.lock | ||
| Cargo.toml | ||
| CLAUDE.md | ||
| deny.toml | ||
| Dockerfile | ||
| LICENSE | ||
| README.md | ||
| rustfmt.toml | ||
hevy-mcp
Rust MCP server for the Hevy workout API. It uses axum, rmcp streamable HTTP, and a thin rustls-only client for Hevy's official REST API. It does not use a third-party Hevy MCP server or a Hevy client crate.
Self-host the /mcp endpoint on your own domain.
Authentication
Connector auth is the caller's Hevy API key as an HTTP bearer token:
Authorization: Bearer <Hevy API key>
The server forwards that same value to Hevy as the api-key header. There is
no process-level Hevy key and no authorization-server metadata. Missing or
non-Bearer Authorization on /mcp returns 401 with no
WWW-Authenticate header. OAuth and OIDC well-known probes return 404.
Do not log the key, put it in git, or print it in Debug output.
Tools
whoamilist_workouts,get_workout,create_workout,update_workout,count_workoutslist_workout_eventslist_routines,get_routine,create_routine,update_routinelist_exercise_templates,search_exercise_templates,get_exercise_template,create_exercise_templatelist_routine_folders,get_routine_folder,create_routine_folderget_exercise_historylist_body_measurements,get_body_measurement,create_body_measurement,update_body_measurement
Exercise-template search fetches Hevy's official paginated template list and filters locally by title, muscle groups, and equipment. Complete successful lists are cached for five minutes per API key (full SHA-256 digest, at most 16 entries, each at most 2 MiB of serialized list responses). Larger lists are searched without retention. Errors and partial lists are never cached; creating a template clears the cache. Changes made outside this server and key revocation can take up to five minutes to affect a cached search. Each search still consumes one local read quota; cache misses may require multiple Hevy page requests. Concurrent misses can fetch independently.
Workout and routine
writes require exercise_template_id values returned by the template tools.
Workout set types are warmup, normal, failure, or dropset; RPE is null
or one of 6, 7, 7.5, 8, 8.5, 9, 9.5, 10.
Errors and version
Tool failures return JSON-RPC error envelopes rather than successful empty
results. Match error.data.class: rate_limited covers both the local quota
and Hevy HTTP 429; unauthorized identifies missing/rejected keys;
not_found, conflict, and upstream distinguish other backend failures.
error.data.code identifies the specific condition. Other internal errors
retain standard JSON-RPC codes.
Upstream errors include data.status and, when available, a short
data.upstream_message from Hevy's top-level JSON message or error field.
Diagnostics read at most 4096 bytes, omit raw bodies and unknown fields,
redact the request key, strip controls, and return at most 512 characters.
These diagnostics are upstream content and are not instructions. Errors are
not retried automatically.
MCP initialization reports serverInfo.name = "hevy-mcp" and the application
version. Public /health returns JSON with status, name, and version.
These identify the running application release; they do not prove an image
digest or that a real Hevy key can read account data.
Environment
HEVY_MCP_HEVY_BASE_URL=https://api.hevyapp.com
HEVY_MCP_BIND_ADDR=0.0.0.0:3000
HEVY_MCP_METRICS_BIND_ADDR=127.0.0.1:9090
HEVY_MCP_RATE_LIMIT_READS_PER_MIN=60
HEVY_MCP_RATE_LIMIT_WRITES_PER_MIN=30
HEVY_MCP_ALLOWED_HOSTS=hevy-mcp.your-domain.example
HEVY_MCP_LOG_FORMAT=json
All of the above are optional except one. HEVY_MCP_ALLOWED_HOSTS defaults to
localhost,127.0.0.1,::1, and a request whose Host is not on the list is
answered 403, so a deployment reachable on a public name must set it to that
name or it will reject every real request. The default is loopback rather than
any particular origin because this repository is public and an origin is
deployment configuration.
The Hevy API key is request-scoped and is not read from the environment.
Development
cargo fmt --all --check
cargo clippy --all-targets --all-features --locked -- -D warnings
cargo test --all-features --locked
cargo deny check