whoop-mcp
Personal MCP server that wraps the Whoop API v2 so an MCP client (e.g. Claude Code) can pull your workouts, sleep, and recovery data.
Setup
1. Register a Whoop developer app (one-time)
- Go to https://developer-dashboard.whoop.com and sign in with your personal Whoop account.
- Create a new App.
- Set Redirect URI to
http://localhost:8765/callback(must match exactly). - Select scopes:
read:workout,read:sleep,read:recovery,offline. - Copy the Client ID and Client Secret.
2. Install
cd whoop-mcp
uv venv
source .venv/bin/activate
uv pip install -e .
3. Configure
cp .env.example .env
# edit .env and fill in WHOOP_CLIENT_ID / WHOOP_CLIENT_SECRET
4. One-time login
whoop-mcp-login
This opens a browser to approve access, captures the OAuth callback on localhost:8765, and caches tokens at ~/.whoop-mcp/tokens.json (mode 0600). The server auto-refreshes tokens using the offline scope.
5. Wire into Claude Code
Add to ~/.claude.json or use claude mcp add:
{
"mcpServers": {
"whoop": {
"command": "/absolute/path/to/whoop-mcp/.venv/bin/whoop-mcp"
}
}
}
Restart Claude Code. Tools will appear as:
mcp__whoop__list_workoutsmcp__whoop__get_workoutmcp__whoop__list_sleepmcp__whoop__get_sleepmcp__whoop__list_recovery
Tools
All list tools accept start, end (ISO-8601 datetimes), limit, and next_token (opaque pagination token). Single-item tools take a UUID.
Verification
ls -l ~/.whoop-mcp/tokens.json— should show-rw-------.- Sanity check from the repo root:
python -c "import asyncio; from whoop_mcp.client import WhoopClient; \
print(asyncio.run((lambda: (lambda c: c.list_workouts(limit=1))(WhoopClient()))()))"
- To test the refresh path, edit
expires_atintokens.jsonto a past timestamp and re-run the sanity check. - To test the auth-error path, move
tokens.jsonaside and call a tool — you should see a structured{"error": "not_authenticated", ...}response.
Notes
- Uses endpoint prefix
/developer/v2/.... If Whoop moves to bare/v2/..., changeAPI_PREFIXinsrc/whoop_mcp/client.py. - v1 of this server intentionally returns raw dicts — Whoop response schemas evolve and strict Pydantic models are not worth the churn.











