Skip to main content
Glama
karlhsueh

Hevy MCP Server

by karlhsueh
README.md
# Hevy MCP Server

An MCP server that gives AI assistants (Claude, etc.) access to your [Hevy](https://hevy.com) workout data via the [Model Context Protocol](https://modelcontextprotocol.io).

Supports both **Streamable HTTP** (for Claude web/mobile/desktop connector UI with OAuth) and **SSE** (for Claude Desktop config / CLI).

---

## Deploy

### Option 1 — Railway (recommended, free tier available)

1. Fork this repo and connect it to a new Railway project
2. In the Railway dashboard, go to your service → **Variables** and add:

   | Variable | Value |
   |---|---|
   | `HEVY_API_KEY` | Your Hevy API key (from [hevy.com/settings?developer](https://hevy.com/settings?developer)) |
   | `MCP_AUTH_TOKEN` | A secret token — run `openssl rand -hex 32` to generate one |
   | `MCP_TRANSPORT` | `sse` |
   | `SERVER_BASE_URL` | Your Railway public URL (set after generating a domain below) |

3. Go to **Settings → Networking → Generate Domain**, enter port `3847`, click **Generate Domain**
4. Copy the generated URL and update `SERVER_BASE_URL` to match — Railway will redeploy automatically
5. Check **Deploy Logs** for `Hevy MCP server running`

> **Token persistence on Railway:** OAuth tokens are stored in `DATA_DIR` (defaults to `/data`). On Railway's free tier the filesystem is ephemeral — tokens won't survive redeploys and users will need to re-authorize. To persist tokens, add a Railway volume mounted at `/data` and set `DATA_DIR=/data`.

### Option 2 — Docker (self-hosted)

```bash
git clone https://github.com/karlhsueh/hevyapp-mcp.git
cd hevyapp-mcp
cp .env.example .env
# Edit .env with your values
docker compose up -d
```

Verify:
```bash
curl http://localhost:3847/health
# {"status":"ok","server":"hevyapp-mcp"}
```

Expose remotely with [Cloudflare Tunnel](https://developers.cloudflare.com/cloudflare-one/connections/connect-networks/) or any reverse proxy pointing at `localhost:3847`.

The included `docker-compose.yml` mounts a named volume at `/data` for OAuth token persistence across container restarts.

### Option 3 — Fly.io (free tier available)

1. Install the [Fly CLI](https://fly.io/docs/hands-on/install-flyctl/) and run `fly auth login`
2. From the repo root: `fly launch` (accept defaults)
3. Set secrets:
   ```bash
   fly secrets set \
     HEVY_API_KEY=your-key \
     MCP_AUTH_TOKEN=your-token \
     MCP_TRANSPORT=sse \
     SERVER_BASE_URL=https://your-app.fly.dev \
     DATA_DIR=/data
   ```
4. Add a volume for token persistence:
   ```bash
   fly volumes create mcp_data --size 1
   ```
5. Mount the volume by adding to `fly.toml`:
   ```toml
   [mounts]
     source = "mcp_data"
     destination = "/data"
   ```
6. Deploy: `fly deploy`

---

## Connect to Claude

### Claude web / mobile / desktop (connector UI) — OAuth

The server implements OAuth 2.0 so Claude can authenticate without any config files.

1. In Claude, open **Settings → Integrations** (web/mobile) or **Preferences → Integrations** (desktop)
2. Click **Add custom integration**
3. Enter your server URL (e.g. `https://your-app.up.railway.app`)
4. Claude opens a browser window — enter your `MCP_AUTH_TOKEN`
5. Done

### Claude Desktop (config file)

Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "hevy": {
      "type": "sse",
      "url": "https://your-server/sse",
      "headers": {
        "Authorization": "Bearer your-secret-token"
      }
    }
  }
}
```

### Claude Code (CLI)

```bash
claude mcp add hevy --transport sse https://your-server/sse \
  --header "Authorization: Bearer your-secret-token"
```

---

## Available tools

| Tool | What it does |
|---|---|
| `get_workouts` | List workouts (paginated) |
| `get_workout_count` | Total workout count |
| `get_workout` | Single workout details |
| `get_workout_events` | Changes since a date (for sync) |
| `create_workout` | Log a new workout |
| `update_workout` | Edit an existing workout |
| `get_user_info` | Your profile |
| `get_routines` | List saved routines |
| `get_routine` | Single routine |
| `create_routine` / `update_routine` | Manage routines |
| `get_exercise_templates` | Full exercise library |
| `get_exercise_template` | Single exercise info |
| `get_exercise_history` | Progress over time for any exercise |
| `get_routine_folders` | Routine folder list |
| `create_routine_folder` / `update_routine_folder` | Manage folders |
| `get_body_measurements` | Weight/body fat history |
| `get_body_measurement_by_date` | Measurements for a date |
| `upsert_body_measurement` | Log body measurements |

---

## Updating

```bash
git pull
docker compose up -d --build
```

## Logs

```bash
docker compose logs -f hevyapp-mcp
```

TDQS

B3.2/5.0

Scored across 21 tools

Disambiguation5/5

Each tool targets a distinct resource and action. Workout-related tools are differentiated by purpose (listing, counting, events, details). Exercise and measurement tools are similarly distinct.

Naming Consistency5/5

All tool names follow a consistent verb_noun pattern in snake_case (e.g., create_routine, get_workouts, upsert_body_measurement). No mixing of conventions.

Tool Count4/5

21 tools is slightly above the ideal range but still reasonable for a fitness app covering routines, folders, exercises, workouts, and measurements. Each tool serves a clear purpose.

Completeness3/5

Covers create, read, update, and upsert for key resources, but notably missing delete operations (e.g., delete_routine, delete_workout, delete_body_measurement). Also lacks search/filter tools. Notable gap.

Maintenance

ActivityStale
ResponsivenessNo issues