hevy-mcp-server

hevy-mcp-server

Enables LLMs to read and write Hevy workout tracking data, including workouts, routines, exercise templates, per-exercise history, and body measurements through all 15 Hevy public API endpoints.

Category
Visit Server

README

hevy-mcp-server

MCP server for the Hevy workout tracking API. Gives an LLM read and write access to workouts, routines, exercise templates, per-exercise history, and body measurements.

Covers all 15 endpoints of the Hevy public API (v0.0.1) across 27 tools.

Requirements

  • Node.js 18+
  • A Hevy Pro subscription — API access is Pro-only
  • An API key from https://hevy.com/settings?developer

Install

pnpm install
pnpm run build

Configure

Set HEVY_API_KEY in your MCP client config. For Claude Desktop, in claude_desktop_config.json:

{
  "mcpServers": {
    "hevy": {
      "command": "node",
      "args": ["/absolute/path/to/hevy-mcp-server/dist/index.js"],
      "env": { "HEVY_API_KEY": "your-key-here" }
    }
  }
}
Variable Required Default Purpose
HEVY_API_KEY yes — Your Hevy API key
HEVY_API_BASE_URL no https://api.hevyapp.com Override the API host
HEVY_REQUEST_TIMEOUT_MS no 30000 Per-request timeout
TRANSPORT no stdio stdio or http
PORT / HOST no 3000 / 127.0.0.1 HTTP transport bind address
MCP_PATH_SECRET when hosted — Serves the endpoint at /mcp/<secret>. Required when HOST is not loopback
ALLOWED_ORIGINS no localhost + claude.ai Comma-separated origin allowlist

Remote/HTTP mode, locally:

TRANSPORT=http PORT=3000 pnpm start   # POST JSON-RPC to http://127.0.0.1:3000/mcp

Inspect the tools interactively:

HEVY_API_KEY=your-key pnpm run inspect

Deploying (for Claude mobile / claude.ai connectors)

Claude connects to custom connectors from Anthropic's cloud, not from your device, so mobile and claude.ai need this reachable over public HTTPS. Claude Code and Claude Desktop don't — use stdio there instead.

1. Generate a path secret

openssl rand -hex 32

The server refuses to start on a non-loopback interface without MCP_PATH_SECRET set, because a public endpoint holding your Hevy key is an open proxy to your account. With it set, the endpoint moves to /mcp/<secret> and every other path returns 404 — including a wrong secret, so probing the host doesn't reveal that an MCP server lives there.

2. Deploy

The included Dockerfile and railway.json work as-is on Railway, Render, or Fly. The image sets TRANSPORT=http and HOST=0.0.0.0 and runs as a non-root user. Set two variables in the platform's dashboard:

Variable Value
HEVY_API_KEY your key from https://hevy.com/settings?developer
MCP_PATH_SECRET the value from step 1

PORT is injected by the platform. /healthz is an unauthenticated liveness probe.

3. Verify

curl -s https://your-app.up.railway.app/healthz
# {"status":"ok","server":"hevy-mcp-server","version":"1.0.0"}

4. Add the connector

On claude.ai in a browser — connectors can't be added from the mobile app:

  1. Customize → Connectors → Add custom connector
  2. URL: https://your-app.up.railway.app/mcp/<secret>
  3. On your phone, open a chat and enable it under + → Connectors

Treat that URL like a password: it's the only thing standing between the internet and your training log. If it leaks, rotate MCP_PATH_SECRET and re-add the connector.

Tools

Workouts — hevy_list_workouts, hevy_get_workout, hevy_count_workouts, hevy_list_workout_events, hevy_create_workout, hevy_update_workout

Sessions — hevy_start_session, hevy_get_active_session, hevy_finish_session, hevy_cancel_session

Routines — hevy_list_routines, hevy_get_routine, hevy_create_routine, hevy_update_routine

Routine folders — hevy_list_routine_folders, hevy_get_routine_folder, hevy_create_routine_folder

Exercise templates — hevy_search_exercise_templates, hevy_list_exercise_templates, hevy_get_exercise_template, hevy_create_exercise_template

Progress — hevy_get_exercise_history, hevy_list_body_measurements, hevy_get_body_measurement, hevy_create_body_measurement, hevy_update_body_measurement

Account — hevy_get_user_info

Every read tool takes response_format: "markdown" | "json". Markdown is the default and is optimized for an LLM reading it; JSON is the full structured payload. structuredContent is always populated regardless of format.

Examples

"What did I train this week?" → hevy_list_workouts with page_size=5. Returns titles, duration, exercise list, and total volume per session.

"Log today's bench: 3x8 at 60kg" → hevy_search_exercise_templates with query="bench press" to get the id, then hevy_create_workout with three sets of { weight_kg: 60, reps: 8 }.

"I'm starting legs now" → hevy_start_session with title="Leg Day". The start time is stamped server-side and the session shows in Hevy as in-progress. When you're done, hevy_finish_session with what you performed closes it out with the real duration.

"Am I getting stronger on squats?" → hevy_search_exercise_templates with query="squat", then hevy_get_exercise_history with a start_date. Returns every logged set newest-first, plus the best set by estimated 1RM.

Design notes

Search before writing. Hevy has no server-side exercise search, but every write needs an exercise_template_id. hevy_search_exercise_templates pages through the catalogue (up to 30 pages of 100) and filters locally on title, muscle group, equipment, and custom-only. Point the model at this tool first — ids cannot be guessed.

Updates are replacements, not patches. hevy_update_workout, hevy_update_routine, and hevy_update_body_measurement overwrite the entire resource; anything omitted is deleted or nulled. All three carry destructiveHint: true, and their descriptions tell the model to read the current state first. These are the only three destructive tools — the Hevy API has no delete endpoints.

Live sessions are a title convention, not server state. Hevy's API has no start-workout endpoint and cannot drive the in-app timer, so hevy_start_session creates a real workout up front titled 🔴 In Progress — <title>, and hevy_finish_session rewrites it with the true end time. That marker is the only handle that persists — the server holds no state between requests, so any chat on any device finds the open session by scanning recent workouts. The cost is that an unfinished session stays visible in the log, and since Hevy exposes no delete, hevy_cancel_session can only relabel it, never remove it.

Everything is kilograms. The API has no unit field. Input fields are named weight_kg so there's no ambiguity about what the model is sending, and markdown output renders both (60 kg (132.3 lb)) so a US-based reader doesn't have to convert mentally.

Page-size caps are enforced client-side. Hevy returns a bare 400 for an oversized page. The Zod schemas cap each endpoint at its documented limit (10 for most, 100 for exercise templates), so the model gets a precise message instead of a failed request.

Errors resolve to next actions. A 404 names the tool that produces valid ids for that resource. A 409 on a body measurement points at the update tool. A 403 explains that API access requires Pro.

Permissive output schemas. Hevy's docs warn that this 0.0.1 API may change structure without notice. Output schemas use passthrough() with optional fields so an upstream field addition doesn't turn into a hard tool failure.

Project layout

src/
├── index.ts               # entry point, transport selection
├── constants.ts           # API limits, enums, character limit
├── types.ts               # interfaces for every Hevy entity
├── services/
│   └── hevy-client.ts     # fetch wrapper, auth, error → guidance mapping
├── schemas/
│   ├── inputs.ts          # Zod input schemas
│   └── outputs.ts         # structuredContent schemas
├── formatters/
│   ├── response.ts        # pagination, truncation, format dispatch
│   └── entities.ts        # per-entity markdown rendering
└── tools/
    ├── workouts.ts
    ├── sessions.ts         # in-progress workout tracking
    ├── routines.ts
    ├── exercise-templates.ts
    └── progress.ts

Caveats

  • The Hevy API is officially version 0.0.1 and its own docs warn the structure may change or be abandoned.
  • A routine's folder can't be changed after creation — the update endpoint doesn't accept folder_id.
  • Equipment filtering in search matches against the exercise title, since the API doesn't expose equipment as a field on templates.
  • hevy_create_exercise_template returns a numeric id, unlike the string ids used everywhere else in the API.

Tests

pnpm run build
pnpm test         # 45 checks: MCP handshake, tools, sessions, formatting, errors (mocked API)
pnpm run test:http  # 13 checks: path-secret gating, health check, origin allowlist

Both suites run against a local mock, so no API key or network access is needed.

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured