WHOOP MCP

io.github.cunicopia-devPublished by GitHub account cunicopia-devv0.1.0Updated Oct 24, 2026

Sync WHOOP recovery, sleep, strain, and workouts into Postgres and query them from any MCP client.

Overview

AI-generated overview

Syncs WHOOP recovery, sleep, strain and workout data into a Postgres database you own, then lets an assistant query it offline through read-only MCP tools.

What you can do
  • Set up and authorize the WHOOP connection: get an OAuth authorization URL and exchange the returned code for stored tokens
  • Sync WHOOP data into Postgres: pull cycles, recovery, sleep, workouts and body measurements for a chosen window or the full history, with per-collection counts and errors
  • Check sync health: last sync time, watermark, row counts and last error per collection
  • Read recovery and vitals: recent recovery scores, resting heart rate, HRV, SpO2 and skin temperature, plus a 30-day mean and standard deviation baseline
  • Read sleep, workouts and cycles: stage breakdowns, sleep need and efficiency, workout strain, heart rate, energy, distance and zone minutes, and daily strain
When to use it
Useful when you want an assistant to answer questions about your own WHOOP history, such as comparing this week's HRV to a baseline, without hitting WHOOP API rate limits. It suits users who already run Postgres and are comfortable registering a WHOOP developer app and completing an OAuth flow.
Requirements
Runs locally over stdio as a Python package (Python 3.12+), typically via uvx or uv tool install. Needs a Postgres database (14+ is fine) and a WHOOP developer app. Required environment variables: WHOOP_CLIENT_ID, WHOOP_CLIENT_SECRET, WHOOP_REDIRECT_URI and WHOOP_DB_URL. The database schema must be created first, and network access to WHOOP is needed for sync.
Before you install
WHOOP OAuth tokens are stored in plaintext in the whoop_tokens table, so anyone who can read it can act as you against the WHOOP API; restrict database grants and treat WHOOP_DB_URL as a secret. WHOOP_CLIENT_SECRET is also a credential. Sync writes to your database and the full-history option walks the entire account history. Scopes are read-only, so nothing in the WHOOP account is modified.

Installation

In SourceWeft

  1. Open WHOOP MCP in the dashboard and add it to a workspace.
  2. Enable the server for the chats that should use its tools.

Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.

Other MCP clients

Follow the launch instructions in the repository.

README

whoop-mcp

[Python] [License: MIT] [storage: Postgres] [MCP]

An MCP server that syncs your WHOOP data into Postgres and lets AI agents query it.

WHOOP's public API is rate-limited, cursor-paginated, and returns one record at a time. That is fine for a sync job and terrible for an agent that wants to answer "how does my HRV this week compare to my baseline?". So this server splits the job in two:

  • a sync path that pulls cycles, recovery, sleep, workouts, and body measurements from the WHOOP API into a documented Postgres schema, keeping the raw JSON of every record alongside the typed columns;
  • a query path of MCP tools that read Postgres only. They are fast, never hit WHOOP's rate limits, and keep working offline once data is synced.

Your data lands in a database you own, in a schema you can read with any SQL client, and nothing leaves your machine except calls to WHOOP itself.

Python 3.12+ · MIT · stdio MCP server + CLI · Postgres storage


Contents


Tools

Two write-side tools talk to the WHOOP API; everything else reads Postgres only.

ToolArgsWhat it does
whoop_auth_urlnoneReturns the OAuth authorization URL to open in a browser.
whoop_connectcodeExchanges the OAuth code for tokens, stores them, returns the connected user.
whoop_syncdays=7, full=falsePulls data from WHOOP into Postgres. Returns per-collection counts and errors.
whoop_statusnonePer-collection sync health: last sync, watermark, row count, last error.
whoop_overviewdays=7Latest recovery and vitals vs. 30-day baseline, last night's sleep, recent workouts and strain.
whoop_recoverydays=7, limit=50Recent recovery scores, resting HR, HRV, SpO2, skin temperature.
whoop_sleepdays=7, limit=50Recent sleeps and naps with stage breakdown, need, performance, efficiency.
whoop_workoutsdays=14, limit=50Recent workouts with strain, HR, energy, distance, and zone minutes.
whoop_cyclesdays=7, limit=50Recent physiological cycles (WHOOP days) with day strain and HR.
whoop_baselinenone30-day mean and standard deviation per vital.

days is capped at 365 and limit at 200. All tools return JSON text.

Install

bash
uv tool install whoop-postgres-mcp      # or: pipx install whoop-postgres-mcp

Or run it without installing:

bash
uvx whoop-postgres-mcp --help

You also need a Postgres database (any recent version; 14+ is fine) and a WHOOP developer app. docs/SETUP.md walks through both.

Quickstart

bash
export WHOOP_CLIENT_ID=...export WHOOP_CLIENT_SECRET=...export WHOOP_REDIRECT_URI=http://localhost:8765/callbackexport WHOOP_DB_URL=postgresql://whoop:whoop@localhost:5432/whoop
whoop-mcp init-db          # create the `whoop` schema (idempotent)whoop-mcp auth-url         # print the URL to visit; approve access in a browserwhoop-mcp connect <code>   # paste the `code` from the redirect URLwhoop-mcp sync --all       # first backfill; later runs: whoop-mcp sync --days 7whoop-mcp                  # serve MCP over stdio

The same flow is available as MCP tools (whoop_auth_url, whoop_connect, whoop_sync) so an agent can drive the whole setup.

Configuration

All configuration is by environment variable. The server validates every variable at startup and exits with a message naming each missing one.

VariableRequiredMeaning
WHOOP_CLIENT_IDyesClient ID of your WHOOP developer app.
WHOOP_CLIENT_SECRETyesClient secret of your WHOOP developer app.
WHOOP_REDIRECT_URIyesRedirect URI, exactly as registered on the app. Any URL works; the server does not listen on it. You copy the code from the address bar.
WHOOP_DB_URLyesPostgres DSN, e.g. postgresql://user:pass@host:5432/db. Tokens and data live here.

Register with an MCP client

Claude Code:

bash
claude mcp add whoop -e WHOOP_CLIENT_ID=... -e WHOOP_CLIENT_SECRET=... \  -e WHOOP_REDIRECT_URI=http://localhost:8765/callback \  -e WHOOP_DB_URL=postgresql://whoop:whoop@localhost:5432/whoop \  -- uvx whoop-postgres-mcp

Claude Desktop (claude_desktop_config.json) or any client that takes a stdio command:

json
{  "mcpServers": {    "whoop": {      "command": "uvx",      "args": ["whoop-postgres-mcp"],      "env": {        "WHOOP_CLIENT_ID": "...",        "WHOOP_CLIENT_SECRET": "...",        "WHOOP_REDIRECT_URI": "http://localhost:8765/callback",        "WHOOP_DB_URL": "postgresql://whoop:whoop@localhost:5432/whoop"      }    }  }}

How sync works

WHOOP's collection endpoints filter on when a record occurred, not when it was last modified, and records change after creation (a sleep is created as PENDING_SCORE and scored later). The sync therefore:

  1. always re-fetches the last days days, which catches late re-scores;
  2. tracks a per-collection watermark (newest_updated_at in whoop_sync_state). If the last sync is older than days, the window is stretched back to the watermark minus a two-day lookback so a gap never leaves a hole;
  3. upserts every record on its natural key (id, or cycle_id for recovery), so overlapping windows are harmless and re-running is safe;
  4. records per-collection errors in whoop_sync_state and carries on with the other collections rather than aborting the run.

full=true (or whoop-mcp sync --all) drops the lower bound and walks the account's entire history. Body measurements are a single current record and are refreshed on every sync.

Token refresh is proactive (five minutes before expiry) and serialized through a Postgres advisory lock, so the MCP server and a cron-driven whoop-mcp sync can share one token row without racing.

The full data model is documented in docs/SCHEMA.md.

Security model

  • Database access is token access. OAuth tokens are stored in plaintext in whoop.whoop_tokens. Anyone who can read that table can call the WHOOP API as you until the refresh token is revoked. Restrict database grants accordingly and treat WHOOP_DB_URL as a secret.
  • Read tools never reach the network. Only whoop_connect and whoop_sync talk to WHOOP. Everything else is a SQL query against your database.
  • Nothing is written outside Postgres. No files, no caches, no telemetry.
  • Scopes are read-only. The app requests read:* scopes plus offline for refresh tokens. It cannot modify anything in your WHOOP account.
  • To revoke access, delete the row from whoop_tokens and remove the app from your WHOOP account settings.

Development

bash
git clone https://github.com/cunicopia-dev/whoop-mcpcd whoop-mcpuv venv && source .venv/bin/activateuv pip install -e ".[dev]"
ruff check .mypy srcpytest                       # pure-logic testsWHOOP_TEST_DB_URL=postgresql://whoop:whoop@localhost:5432/whoop pytest   # + live DB tests

The live tests apply the schema and truncate every table in the target database before each test. Point them at a scratch database.

A throwaway Postgres for local testing:

bash
docker run -d --rm --name whoop-pg -e POSTGRES_USER=whoop -e POSTGRES_PASSWORD=whoop \  -e POSTGRES_DB=whoop -p 5432:5432 postgres:16-alpine

Project layout

src/whoop_mcp/  config.py     environment variables, validated at startup  auth.py       OAuth2 flow, token persistence, locked refresh  client.py     httpx client: pagination, backoff, Retry-After  schema.sql    the Postgres DDL (applied by `whoop-mcp init-db`)  db.py         connection + schema helpers  sync.py       incremental sync with per-collection watermarks  queries.py    read-side SQL behind the MCP tools  server.py     MCP server over stdio + CLI entry pointdocs/  SETUP.md      WHOOP app registration, OAuth walkthrough, DB init, first sync  SCHEMA.md     column-by-column data modeltests/          config, schema, client, auth, sync, and stdio protocol tests

License

MIT. See LICENSE.

Source: README.md at commit 328722c

Tools

0
SourceWeft has not started this package in its sandbox yet, so its tools are not known.

Version history

1
  1. v0.1.0LatestSep 16, 2026

Score

50% of the applicable checks met

How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.

  • Reached in the last 30 days25 pts

    Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.

  • Auth declared10 pts

    Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.

  • Tools listed15 pts

    Answer tools/list without a credential, or ship a package that starts in a sandbox without one.

  • DescriptionRequired15 pts
  • Logo10 pts
  • Documentation15 pts
  • License10 pts