MCP server for the Hevy workout API (axum + rmcp). Bearer Hevy API key. Self-host.
  • Rust 98.9%
  • Dockerfile 1.1%
Find a file
Julian Lindner 8d6f0a7679
Some checks failed
CI / cargo (push) Failing after 2m44s
CI / docker (push) Has been skipped
Merge pull request 'ci: name which audit failure happened' (#13) from ci/name-which-audit-failure into main
2026-09-07 04:04:37 +00:00
.forgejo/workflows ci: name which audit failure happened 2026-09-02 10:53:47 +08:00
src fix: keep the retry interval in the human message 2026-08-28 12:10:02 +08:00
.gitignore feat: first-party Hevy MCP server with Logto streamable HTTP 2026-08-17 09:05:28 +08:00
AGENTS.md ci: name which audit failure happened 2026-09-02 10:53:47 +08:00
Cargo.lock fix: keep the retry interval in the human message 2026-08-28 12:10:02 +08:00
Cargo.toml fix: keep the retry interval in the human message 2026-08-28 12:10:02 +08:00
CLAUDE.md chore: take h2 0.4.19 for RUSTSEC-2026-0258, and two documentation fixes 2026-08-26 13:39:01 +08:00
deny.toml feat: first-party Hevy MCP server with Logto streamable HTTP 2026-08-17 09:05:28 +08:00
Dockerfile feat: authenticate MCP with the request Hevy API key 2026-08-17 09:56:16 +08:00
LICENSE feat: first-party Hevy MCP server with Logto streamable HTTP 2026-08-17 09:05:28 +08:00
README.md fix: take the public origin out of the published default host list 2026-08-27 09:57:41 +08:00
rustfmt.toml feat: first-party Hevy MCP server with Logto streamable HTTP 2026-08-17 09:05:28 +08:00

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

  • whoami
  • list_workouts, get_workout, create_workout, update_workout, count_workouts
  • list_workout_events
  • list_routines, get_routine, create_routine, update_routine
  • list_exercise_templates, search_exercise_templates, get_exercise_template, create_exercise_template
  • list_routine_folders, get_routine_folder, create_routine_folder
  • get_exercise_history
  • list_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. 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.

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