WHOOP MCP Server
# WHOOP MCP Server
A [Model Context Protocol](https://modelcontextprotocol.io) server that gives Claude access to your WHOOP health data via the [WHOOP Developer API](https://developer.whoop.com/) (API **v2**).
## Tools
| Tool | Description |
|---|---|
| `authenticate` | Start the OAuth 2.0 flow — call this once to connect your WHOOP account |
| `get_recovery` | Latest recovery score, HRV, resting heart rate, SpO2, skin temperature |
| `get_sleep` | Sleep duration, efficiency, stage breakdown, disturbances, respiratory rate |
| `get_workouts` | Recent workouts with strain, sport type, HR zones, calories |
| `get_cycles` | Physiological cycles (days) with strain and recovery summary |
| `get_body_measurements` | Height, weight, and max heart rate |
| `get_profile` | Basic profile (name, email) |
**Parameters:** the data tools (`get_recovery`, `get_sleep`, `get_workouts`, `get_cycles`) accept optional filters:
- `limit` — number of records to return (default 1 for recovery/sleep, 5 for workouts/cycles; max 25)
- `start_date` / `end_date` — ISO 8601 timestamps, e.g. `2024-01-01T00:00:00.000Z`
- `include_naps` — `get_sleep` only; include nap records (default `false`)
`get_body_measurements` and `get_profile` take no parameters.
## Prerequisites
- Node.js 18 or later
- A WHOOP Developer account and OAuth app
## Setup
### 1. Create a WHOOP Developer App
1. Go to [https://developer.whoop.com/](https://developer.whoop.com/) and sign in.
2. Create a new application.
3. Add `http://localhost:8080/callback` as a **Redirect URI** (or use a custom port — just keep it consistent with `WHOOP_REDIRECT_URI`).
4. Enable the following **scopes** on the app — the server requests all of them, and data tools will return empty or fail if any are missing:
- `offline` (required — grants the refresh token so you only authenticate once)
- `read:recovery`
- `read:sleep`
- `read:workout`
- `read:cycles`
- `read:body_measurement`
- `read:profile`
5. Copy your **Client ID** and **Client Secret**.
### 2. Install and build
```bash
git clone <this-repo>
cd whoop-mcp
npm install
npm run build
```
### 3. Configure environment variables
```bash
cp .env.example .env
```
Edit `.env`:
```
WHOOP_CLIENT_ID=your_client_id_here
WHOOP_CLIENT_SECRET=your_client_secret_here
WHOOP_REDIRECT_URI=http://localhost:8080/callback
```
> **Security note:** `.env` is never committed. Tokens are stored in `~/.whoop-mcp-tokens.json` with `600` permissions (owner read/write only).
### 4. Add to Claude's MCP configuration
#### Claude Desktop (`~/Library/Application Support/Claude/claude_desktop_config.json`)
```json
{
"mcpServers": {
"whoop": {
"command": "node",
"args": ["/absolute/path/to/whoop-mcp/dist/index.js"],
"env": {
"WHOOP_CLIENT_ID": "your_client_id_here",
"WHOOP_CLIENT_SECRET": "your_client_secret_here",
"WHOOP_REDIRECT_URI": "http://localhost:8080/callback"
}
}
}
}
```
> You can either set the env vars here **or** rely on a `.env` file in the project root (loaded by `dotenv`).
#### Claude Code (`.claude/settings.json` or via `claude mcp add`)
```bash
claude mcp add whoop node /absolute/path/to/whoop-mcp/dist/index.js \
-e WHOOP_CLIENT_ID=your_client_id \
-e WHOOP_CLIENT_SECRET=your_client_secret \
-e WHOOP_REDIRECT_URI=http://localhost:8080/callback
```
Or manually in `.claude/settings.json`:
```json
{
"mcpServers": {
"whoop": {
"command": "node",
"args": ["/absolute/path/to/whoop-mcp/dist/index.js"],
"env": {
"WHOOP_CLIENT_ID": "...",
"WHOOP_CLIENT_SECRET": "...",
"WHOOP_REDIRECT_URI": "http://localhost:8080/callback"
}
}
}
}
```
### 5. Authenticate
Once the server is running in Claude, call the `authenticate` tool:
> **You:** Use the `authenticate` tool to connect my WHOOP account.
Claude will display an authorization URL. Open it in your browser, approve access, and the tokens will be saved automatically to `~/.whoop-mcp-tokens.json`.
Tokens refresh automatically — you only need to authenticate once.
## Example prompts
```
What was my recovery score this morning?
Show me my last 7 days of sleep data.
How has my HRV trended over the past month?
What workouts did I do this week and what was my strain?
What are my body measurements on WHOOP?
```
## Token storage
- Tokens are stored in `~/.whoop-mcp-tokens.json` (or the path in `WHOOP_TOKEN_FILE`).
- The file is created with `0600` permissions so only your user can read it.
- Access tokens are refreshed automatically 60 seconds before expiry using the stored refresh token.
## Development
```bash
# Compile TypeScript in watch mode
npm run dev
# Run directly (after building)
npm start
```
## Troubleshooting
| Problem | Fix |
|---|---|
| `Missing required environment variable` | Ensure `WHOOP_CLIENT_ID` and `WHOOP_CLIENT_SECRET` are set in `.env` or the MCP config `env` block |
| `Not authenticated` | Call the `authenticate` tool and complete the browser flow |
| Port 8080 already in use | Change `WHOOP_REDIRECT_URI` to use a different port (e.g. `http://localhost:9090/callback`) and update your WHOOP app's redirect URI list |
| Token refresh fails | Delete `~/.whoop-mcp-tokens.json` and re-authenticate |
TDQS
Scored across 7 tools
Each tool targets a distinct data domain: authentication, recovery, sleep, workouts, cycles, body measurements, and profile. There is no meaningful overlap between these resource types, and the descriptions make the boundary between similar health metrics clear.
The data tools all follow a clean get_<resource> naming convention, making the tool surface highly predictable. authenticate is the only exception, but it is clearly a distinct action verb appropriate for the OAuth flow.
Seven tools is well-scoped for a read-only health data integration. Each tool represents a meaningful endpoint or data category, with no redundant or filler tools.
The server covers the main WHOOP data domains: recovery, sleep, workouts, daily cycles, body measurements, and user profile, plus the required authentication step. For a read-only personal health API, this is a complete and usable surface with no obvious dead ends.