{
  "markdown": "# whoop-ai-mcp\n\n[![npm version](https://img.shields.io/npm/v/whoop-ai-mcp.svg)](https://www.npmjs.com/package/whoop-ai-mcp)\n[![npm downloads](https://img.shields.io/npm/dw/whoop-ai-mcp.svg)](https://www.npmjs.com/package/whoop-ai-mcp)\n[![GitHub stars](https://img.shields.io/github/stars/shashankswe2020-ux/whoop-mcp.svg)](https://github.com/shashankswe2020-ux/whoop-mcp/stargazers)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)\n[![Node.js >= 20](https://img.shields.io/badge/node-%3E%3D20-brightgreen.svg)](https://nodejs.org)\n[![TypeScript](https://img.shields.io/badge/TypeScript-5.x-blue.svg)](https://www.typescriptlang.org/)\n[![MCP](https://img.shields.io/badge/MCP-compatible-purple.svg)](https://modelcontextprotocol.io/)\n\n[![MCP Registry](https://img.shields.io/badge/MCP_Registry-published-green.svg)](https://registry.modelcontextprotocol.io/)\n\nAn [MCP (Model Context Protocol)](https://modelcontextprotocol.io/) server that connects AI assistants like Claude to your [WHOOP](https://www.whoop.com/) health and fitness data. Ask questions about your recovery, sleep, workouts, and more — all through natural conversation.\n\n> 📦 **Published on the [MCP Registry](https://registry.modelcontextprotocol.io/)** as `io.github.shashankswe2020-ux/whoop` — discoverable by any MCP-compatible client.\n\n## Features\n\n- 🏋️ **14 health data tools** — recovery, sleep, workouts, cycles, body measurements, profile, weekly summaries, trend analysis, period comparisons, individual record lookups, today's snapshot, and calendar grid\n- 📊 **4 MCP Resources** — ambient health context (latest recovery, sleep, cycle, profile) available without explicit tool calls\n- 💬 **5 MCP Prompts** — guided conversation starters for common health queries\n- 📅 **Rich natural date expressions** — use \"last 7 days\", \"this week\", \"last 2 weeks\", \"last 3 months\", \"this quarter\", \"last year\", \"2026-05\", and more\n- 📈 **Built-in analytics** — weekly summaries, trend detection (linear regression), and period comparisons computed server-side\n- 🔐 **Secure OAuth2** — browser-based authentication with automatic token refresh\n- 🔄 **Resilient** — automatic retry on rate limits, token refresh on expiry, auto-pagination, clear error messages\n- 💾 **Secure token storage** — tokens stored at `~/.whoop-mcp/tokens.json` with `0600` permissions\n- ⚡ **Zero config** — just add your WHOOP app credentials and go\n- 📦 **Lightweight** — only two runtime dependencies (`@modelcontextprotocol/sdk` + `zod`)\n\n## SOTA scan (WHOOP MCP packages on npm)\n\n_Registry snapshot collected 2026-08-30. Versions and publish dates can change;\nthis is an ecosystem comparison, not a source-code security audit._\n\n| Package | Latest | Published (UTC) | MCP Registry identity | Runtime deps | Notable signals |\n|------|------:|-----------------|----------------------|-------------:|-----------------|\n| **whoop-ai-mcp (this repo)** | **0.6.1** | 2026-08-07 | **✅ `io.github.shashankswe2020-ux/whoop`** | **2** | 14 tools, 4 resources, 5 prompts, analytics, HTTP + stdio, OAuth 2.1 connector |\n| whoop-mcp-unofficial | 0.6.5 | 2026-08-29 | ✅ `io.github.davidmosiah/whoop-mcp` | 6 | 20+ tools, SQLite cache, privacy modes |\n| mcp-server-whoop | 0.2.2 | 2026-07-17 | ✅ `io.github.Yadheedhya06/mcp-server-whoop` | 2 | Read-only/local-first, npm provenance, SBOM and security checks |\n| @souravpn/whoop-mcp | 1.0.2 | 2026-05-27 | ✅ `io.github.souravpn/whoop-mcp` | 1 | Simple standalone server with OAuth setup |\n| @nchemb/whoop-mcp | 0.2.0 | 2026-04-27 | — | 4 | Shared OAuth relay and local SQLite cache |\n| whoop-mcp-server | 0.0.5 | 2026-03-13 | — | 2 | WHOOP Developer Platform API server |\n| whoop-mcp | 0.1.2 | 2026-03-11 | — | 1 | Server built with the `xmcp` framework |\n| @roebot0/whoop-mcp | 1.0.0 | 2026-04-06 | — | 3 | Axios-based server and separate auth command |\n| @alacore/whoop-mcp-server | 1.0.1 | 2025-10-09 | — | 2 | API v2 integration; requires pnpm |\n\n**Findings**\n\n- MCP Registry discoverability is now table stakes: at least three alternatives also\n  publish `mcpName` identities.\n- The leading portability trade-off remains local-first/no-infrastructure\n  operation versus richer remote hosting, caching, or relay features.\n- Current best practice is to document security controls, test/verification\n  commands, provenance or SBOM metadata, and the exact transport/auth model.\n  This project provides the first two and supports both local stdio and\n  authenticated Streamable HTTP; it does not claim to be a security audit.\n\n**Why this package stands out**\n\n- 14 domain and analytical tools, 4 ambient resources, and 5 prompts in one\n  standalone package.\n- No database, relay service, or framework runtime dependency; only the MCP SDK\n  and Zod are required.\n- Published to npm and the official MCP Registry, with documented OAuth,\n  token refresh, retries, caching, HTTP hardening, and Inspector verification.\n\n**Evidence and reproducibility:** package names, versions, publish dates,\ndependency counts, descriptions, and `mcpName` values come from the npm Registry\nsearch and package manifests. Feature notes were checked against each package's\npublished metadata/README where available. Re-run the scan with:\n\n```bash\ncurl -s 'https://registry.npmjs.org/-/v1/search?text=whoop%20mcp&size=20'\n```\n\n## 🎥 Video Walkthrough\n\nWatch a detailed walkthrough of setting up and using whoop-ai-mcp with Claude Desktop:\n\n[![Watch the video](https://img.youtube.com/vi/2vwxEjctcWs/maxresdefault.jpg)](https://youtu.be/2vwxEjctcWs?si=ncIr0fmXT0MUarYL)\n\n> Covers: creating a WHOOP Developer App, configuring Claude Desktop, OAuth authentication, and querying your health data through natural conversation.\n\n## Prerequisites\n\n1. A [WHOOP](https://www.whoop.com/) account with an active membership\n2. A WHOOP Developer App — create one at [developer.whoop.com](https://developer.whoop.com)\n   - Set the redirect URI to `http://localhost:3000/callback`\n3. [Node.js](https://nodejs.org/) >= 20\n\n## Get a WHOOP\n\nDon't have a WHOOP yet? Here's how to get started:\n\n- 🛒 **Buy a WHOOP on Amazon** — [WHOOP peak on Amazon](https://amzn.to/4st9B2r)\n- 🔗 **Join WHOOP directly** — [whoop.com/membership](https://join.whoop.com/63E6C805)\n\n## Quickstart (MCP Registry)\n\nThis server is published on the official [MCP Registry](https://registry.modelcontextprotocol.io/). MCP clients that support the registry can discover and install it automatically:\n\n```\nServer name: io.github.shashankswe2020-ux/whoop\n```\n\nYou can also browse it via the registry API:\n\n```bash\ncurl \"https://registry.modelcontextprotocol.io/v0.1/servers?search=io.github.shashankswe2020-ux/whoop\"\n```\n\n## Quickstart (Claude Desktop)\n\nAdd this to your Claude Desktop configuration file:\n\n**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`\n**Windows:** `%APPDATA%\\Claude\\claude_desktop_config.json`\n\n```json\n{\n  \"mcpServers\": {\n    \"whoop\": {\n      \"command\": \"npx\",\n      \"args\": [\"whoop-ai-mcp\"],\n      \"env\": {\n        \"WHOOP_CLIENT_ID\": \"your_client_id\",\n        \"WHOOP_CLIENT_SECRET\": \"your_client_secret\"\n      }\n    }\n  }\n}\n```\n\nReplace `your_client_id` and `your_client_secret` with the credentials from your [WHOOP Developer App](https://developer.whoop.com).\n\nOn first launch, a browser window will open for you to authorize access to your WHOOP data. After authorizing, tokens are cached locally and refresh automatically.\n\nThen ask Claude something like:\n\n> *\"How am I doing today?\"*\n>\n> *\"Show me my sleep data from the last 3 days\"*\n>\n> *\"What workouts did I do this month?\"*\n>\n> *\"Is my HRV trending up or down?\"*\n>\n> *\"Give me a weekly health summary\"*\n>\n> *\"Show me my recovery calendar for last 2 weeks\"*\n\n**whoop-mcp connected in Claude Desktop:**\n\n![whoop-mcp connected in Claude Desktop](images/whoop-mcp-connected.png)\n\n**Chatting with WHOOP data through Claude:**\n\n![Claude chat with whoop-mcp integrated](images/Claude-chat-with-whoop-mcp-integrated.png)\n\n**Weekly Health Report demo (Claude Desktop):**\n\n![Weekly health report — asking Claude](images/Screenshot%202026-05-30%20at%201.36.39%E2%80%AFPM.png)\n\n![Recommendations and breakdowns](images/Screenshot%202026-05-30%20at%201.37.06%E2%80%AFPM.png)\n\n![summary and connector view](images/Screenshot%202026-05-30%20at%201.37.39%E2%80%AFPM.png)\n\n## Installation\n\n### Via npx (recommended)\n\nNo installation needed — Claude Desktop runs it automatically with the config above.\n\n### Global install\n\n```bash\nnpm install -g whoop-ai-mcp\n```\n\n### From source\n\n```bash\ngit clone https://github.com/shashankswe2020-ux/whoop-mcp.git\ncd whoop-mcp\nnpm install\nnpm run build\n```\n\n### Setup wizard (`whoop-ai-mcp setup`)\n\nFor a guided installation that writes the Claude Desktop config (or prints the\nregistration command for Claude Code, Codex, or GitHub Copilot) and verifies\nyour WHOOP credentials in one go:\n\n```bash\nnpx whoop-ai-mcp setup\n```\n\nFlags:\n\n- `--client=claude-desktop` (default) writes/merges `claude_desktop_config.json`\n  with an automatic `.bak` backup.\n- `--client=claude-code` prints the equivalent `claude mcp add` command.\n- `--client=codex` prints the equivalent `codex mcp add` command (registers the\n  server in `~/.codex/config.toml`).\n- `--client=copilot` prints the equivalent `code --add-mcp` command for GitHub\n  Copilot in VS Code.\n- `--verify` runs the OAuth flow end-to-end and fetches your profile to confirm\n  everything is wired correctly before exiting.\n- `--client-id` / `--client-secret` skip the interactive prompts (useful for\n  scripts; secrets entered interactively are masked).\n\nIf `WHOOP_CLIENT_ID` and `WHOOP_CLIENT_SECRET` are already exported in your\nshell, the wizard uses them automatically — no prompts. Combine with\n`--verify` to do a one-shot config-correctness check:\n\n```bash\nWHOOP_CLIENT_ID=... WHOOP_CLIENT_SECRET=... npx whoop-ai-mcp setup --verify\n```\n\nIf the Claude Desktop config file already contains a `whoop` MCP entry from\na previous setup, the wizard short-circuits — it reads the existing\ncredentials, prints `Existing whoop entry found in <path>`, and either\nverifies them (with `--verify`) or exits without rewriting the file. To\noverwrite an existing entry, pass explicit `--client-id` / `--client-secret`\nflags.\n\nPrecedence: `--client-id` / `--client-secret` flags > existing claude-desktop\nconfig > `WHOOP_CLIENT_ID` / `WHOOP_CLIENT_SECRET` env vars > interactive\nprompts.\n\nExample session:\n\n```text\nshashankmishra@Shashanks-MacBook-Pro ~ % npx whoop-ai-mcp setup --client=claude-desktop\nWHOOP MCP — Setup Wizard\n------------------------\n\nWHOOP Client ID (from https://developer.whoop.com): xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx\nWHOOP Client Secret (input hidden): ****************************************************************\n\nClaude Desktop config written: /Users/shashankmishra/Library/Application Support/Claude/claude_desktop_config.json\nPrevious config backed up to: /Users/shashankmishra/Library/Application Support/Claude/claude_desktop_config.json.bak\nRestart Claude Desktop to load the new server.\n```\n\nRe-running against an already-configured Claude Desktop install (existing\n`whoop` entry in `claude_desktop_config.json`) short-circuits to a\nverification-only flow — no prompts, no rewrite:\n\n```text\nshashankmishra@Shashanks-MacBook-Pro ~ % whoop-ai-mcp setup --verify\nWHOOP MCP — Setup Wizard\n------------------------\n\nTarget client (claude-desktop / claude-code) [claude-desktop]:\nExisting whoop entry found in /Users/shashankmishra/Library/Application Support/Claude/claude_desktop_config.json.\n\nVerifying credentials with WHOOP...\nCached tokens expired, attempting refresh...\nToken refresh successful.\nOAuth flow complete. Fetching profile...\nProfile OK: {\"user_id\":35253045,\"email\":\"shashank.swe.2020@gmail.com\",\"first_name\":\"Shashank\",\"last_name\":\"Mishra\"}\n\nExisting config verified — no changes made.\n```\n\n## Configuration\n\n### Environment Variables\n\n| Variable | Required | Description |\n|----------|----------|-------------|\n| `WHOOP_CLIENT_ID` | Yes | Your WHOOP Developer App client ID |\n| `WHOOP_CLIENT_SECRET` | Yes | Your WHOOP Developer App client secret |\n\nSet these in your Claude Desktop config (see [Quickstart](#quickstart-claude-desktop)) or as shell environment variables:\n\n```bash\nexport WHOOP_CLIENT_ID=your_client_id\nexport WHOOP_CLIENT_SECRET=your_client_secret\n```\n\n### Creating a WHOOP Developer App\n\n1. Go to [developer.whoop.com](https://developer.whoop.com)\n2. Create a new application\n3. Set the **Redirect URI** to `http://localhost:3000/callback`\n4. Set the **Privacy Policy URL** (required by WHOOP) — you can use `https://github.com/shashankswe2020-ux/whoop-mcp` or your own URL\n5. Enable the following scopes:\n   - `read:profile`\n   - `read:recovery`\n   - `read:sleep`\n   - `read:workout`\n   - `read:cycles`\n   - `read:body_measurement`\n6. Copy the **Client ID** and **Client Secret**\n\n## Tools\n\n### `get_profile`\n\nGet the authenticated user's basic profile — name and email.\n\n**Parameters:** None\n\n---\n\n### `get_body_measurement`\n\nGet the user's body measurements — height, weight, and max heart rate.\n\n**Parameters:** None\n\n---\n\n### `get_recovery_collection`\n\nGet recovery scores for a date range. Returns HRV, resting heart rate, SpO2, and skin temp for each day.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `start` | string | No | ISO 8601 or relative expression (\"today\", \"last 7 days\", \"this week\"). |\n| `end` | string | No | ISO 8601 or relative expression. Defaults to now. |\n| `limit` | number | No | Max records to return (1–25). Defaults to 10. |\n| `nextToken` | string | No | Pagination token from a previous response. |\n\n---\n\n### `get_sleep_collection`\n\nGet sleep records for a date range. Returns sleep stages, duration, respiratory rate, and performance scores.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `start` | string | No | ISO 8601 or relative expression (\"today\", \"last 7 days\", \"this week\"). |\n| `end` | string | No | ISO 8601 or relative expression. Defaults to now. |\n| `limit` | number | No | Max records to return (1–25). Defaults to 10. |\n| `nextToken` | string | No | Pagination token from a previous response. |\n\n---\n\n### `get_workout_collection`\n\nGet workout records for a date range. Returns strain, heart rate zones, calories, and sport type.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `start` | string | No | ISO 8601 or relative expression (\"today\", \"last 7 days\", \"this week\"). |\n| `end` | string | No | ISO 8601 or relative expression. Defaults to now. |\n| `limit` | number | No | Max records to return (1–25). Defaults to 10. |\n| `nextToken` | string | No | Pagination token from a previous response. |\n\n---\n\n### `get_cycle_collection`\n\nGet physiological cycles for a date range. Returns strain, calories, and heart rate data per cycle.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `start` | string | No | ISO 8601 or relative expression (\"today\", \"last 7 days\", \"this week\"). |\n| `end` | string | No | ISO 8601 or relative expression. Defaults to now. |\n| `limit` | number | No | Max records to return (1–25). Defaults to 10. |\n| `nextToken` | string | No | Pagination token from a previous response. |\n\n---\n\n### `get_sleep_by_id`\n\nGet a single sleep record by ID. Returns sleep stages, duration, respiratory rate, and performance scores.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | string | Yes | The sleep record ID. |\n\n---\n\n### `get_workout_by_id`\n\nGet a single workout record by ID. Returns strain, heart rate zones, calories, and sport type.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | string | Yes | The workout record ID. |\n\n---\n\n### `get_cycle_by_id`\n\nGet a single physiological cycle by ID. Returns strain, calories, and heart rate data.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `id` | number | Yes | The cycle record ID. |\n\n---\n\n### `get_weekly_summary`\n\nGet a summarized health report for a given week — average recovery, HRV, RHR, sleep duration and quality, workout count and strain, plus recovery trend direction.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `week_start` | string | No | ISO 8601 or relative expression (\"last week\", \"this week\"). Defaults to most recent Monday. |\n\n---\n\n### `compare_periods`\n\nCompare health metrics between two time periods — shows improvement or regression in recovery, sleep, and strain.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `period_a_start` | string | Yes | ISO 8601 start of the first period. |\n| `period_a_end` | string | Yes | ISO 8601 end of the first period. |\n| `period_b_start` | string | Yes | ISO 8601 start of the second period. |\n| `period_b_end` | string | Yes | ISO 8601 end of the second period. |\n\n---\n\n### `get_trend`\n\nAnalyze a health metric trend over time — detects direction (improving/declining/stable), variability, and anomalies using linear regression.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `metric` | string | Yes | One of: `recovery`, `hrv`, `rhr`, `sleep_duration`, `sleep_performance`, `strain`. |\n| `days` | number | No | Number of days to analyze (7–90). Default: 30. |\n\n---\n\n### `get_today`\n\nGet today's complete health snapshot — recovery score, last night's sleep, current strain, and last workout in one call. Perfect for \"how am I doing today?\" questions.\n\n**Parameters:** None\n\n**Returns:** Recovery score with zone, sleep breakdown (hours, stages, performance), current strain, last workout (sport + strain), and a human-readable summary.\n\n---\n\n### `get_calendar`\n\nGet a day-by-day grid of recovery, sleep, and strain for a date range. Perfect for weekly/monthly overviews.\n\n**Parameters:**\n\n| Parameter | Type | Required | Description |\n|-----------|------|----------|-------------|\n| `days` | number | No | Number of days to show (1–90). Default: 7. |\n| `start` | string | No | Start date — ISO 8601 or relative expression (\"last 14 days\", \"this month\"). Defaults to N days ago. |\n\n**Returns:** Per-day grid with recovery score + zone (green/yellow/red), sleep hours, sleep performance, and strain. Includes period averages.\n\n---\n\n## Supported Date Expressions\n\nAll collection tools and `get_calendar` accept natural language date expressions (case-insensitive):\n\n| Expression | Example Result |\n|------------|----------------|\n| `\"today\"` | Today's UTC day boundaries |\n| `\"yesterday\"` | Yesterday's UTC day boundaries |\n| `\"last N days\"` (1–365) | N days back from today |\n| `\"last N weeks\"` (1–52) | N×7 days back from today |\n| `\"last N months\"` (1–12) | N calendar months back |\n| `\"this week\"` | Monday to today |\n| `\"last week\"` | Previous Monday–Sunday |\n| `\"this month\"` | 1st of month to today |\n| `\"last month\"` | Full previous month |\n| `\"this quarter\"` | Quarter start (Jan/Apr/Jul/Oct) to today |\n| `\"last quarter\"` | Full previous quarter |\n| `\"last year\"` | Jan 1–Dec 31 of previous year |\n| `\"YYYY-MM\"` (e.g., `\"2026-05\"`) | Full calendar month |\n| ISO 8601 | Pass-through (e.g., `\"2026-03-15T00:00:00Z\"`) |\n\n---\n\n## Resources\n\nMCP Resources provide ambient health context — AI assistants can read your current health state without explicit tool calls.\n\n| Resource URI | Description | Cache TTL |\n|--------------|-------------|-----------|\n| `whoop://v2/user/recovery/latest` | Most recent recovery score, HRV, RHR | 5 min |\n| `whoop://v2/user/sleep/latest` | Most recent sleep record | 5 min |\n| `whoop://v2/user/cycle/latest` | Current physiological cycle (strain) | 2 min |\n| `whoop://v2/user/profile` | User profile (name, email) | 1 hr |\n\n**Privacy:** Resources expose the same data available through tools — they simply make it accessible as ambient context. No additional WHOOP scopes are required. Data is cached in-memory with short TTLs and invalidated on token refresh.\n\nTo disable resources: set `WHOOP_MCP_DISABLE_RESOURCES=1`.\n\n---\n\n## Caching\n\nRead requests can be served from a shared in-memory cache (LRU + TTL) to cut\nredundant WHOOP API calls and improve latency. The same cache backs both MCP\nresources and tools such as `get_today`, so a warm cache answers repeat queries\nwithout hitting the API.\n\n| Data | TTL |\n|------|-----|\n| Profile | 1 hr |\n| Recovery, Sleep | 5 min |\n| Cycle | 2 min |\n| Collections (date-range queries) | Uncached |\n\n- Cache keys are normalized by request path with sorted query params; **no tokens are ever part of a cache key**.\n- Concurrent identical requests are de-duplicated (single in-flight fetch — stampede prevention).\n- The entire cache is cleared on token refresh.\n\n---\n\n## Write Operations\n\nThe server is **read-only today** — WHOOP does not currently expose public write\nendpoints, so no write tools are registered. The codebase ships a\n*future-ready* write-safety pattern (`withPreview()`) so that mutations, if WHOOP\nadds them, follow a safe two-phase flow:\n\n1. **Preview** (`confirm: false`) — returns a `WritePreview` describing exactly\n   what would change, plus a generated `idempotency_key`. Nothing is written.\n2. **Confirm** (`confirm: true`) — executes the write and returns a\n   `WriteReceipt` carrying the same `idempotency_key`, so retried confirms never\n   create duplicate records.\n\nThis gives an AI assistant a built-in \"show me before you do it\" checkpoint and\nmakes retries safe by construction. See [src/tools/write-safety.ts](src/tools/write-safety.ts).\n\n---\n\n## Prompts\n\nPre-built conversation starters that guide you into useful health queries:\n\n| Prompt | Description |\n|--------|-------------|\n| `weekly_health_review` | Comprehensive review of recovery, sleep, and workouts (accepts optional `days` arg) |\n| `sleep_analysis` | Analyze recent sleep patterns and quality |\n| `recovery_trend` | How is recovery trending? HRV, RHR, recovery score analysis |\n| `workout_recap` | Summarize recent workouts, strain, and training load |\n| `health_check` | Quick health status using cached resource data |\n\n## Authentication\n\n`whoop-ai-mcp` uses OAuth2 Authorization Code flow with PKCE:\n\n1. **First run:** A browser window opens for you to authorize with WHOOP\n2. **Token caching:** Access and refresh tokens are saved to `~/.whoop-mcp/tokens.json`\n3. **Auto-refresh:** When the access token expires, it's automatically refreshed using the stored refresh token\n4. **Re-authentication:** If the refresh token expires, you'll be prompted to authorize again\n\nToken files are stored with `0600` permissions (user-only read/write).\n\n## Troubleshooting\n\n### \"Missing required environment variable: WHOOP_CLIENT_ID\"\n\nYour WHOOP credentials aren't set. Add them to your Claude Desktop config or set them as environment variables. See [Configuration](#configuration).\n\n### \"Network error: Unable to reach the WHOOP API\"\n\nCheck your internet connection. The WHOOP API must be reachable at `https://api.prod.whoop.com`.\n\n### \"WHOOP API returned 429\"\n\nYou've hit the rate limit. The server retries automatically with exponential backoff (up to 3 attempts). If this persists, reduce the frequency of your requests.\n\n### \"WHOOP API returned 401\"\n\nYour access token has expired. The server attempts an automatic refresh. If that fails, delete `~/.whoop-mcp/tokens.json` and restart to re-authenticate:\n\n```bash\nrm ~/.whoop-mcp/tokens.json\n```\n\n### Browser doesn't open during authentication\n\nIf the browser doesn't open automatically, check the terminal output for the authorization URL and open it manually.\n\n## Testing with MCP Inspector\n\nYou can interactively test the server using the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) — a browser-based tool for exploring and invoking MCP tools.\n\n```bash\nWHOOP_CLIENT_ID=your_client_id \\\nWHOOP_CLIENT_SECRET=your_client_secret \\\nWHOOP_REDIRECT_URI=http://localhost:3000/callback \\\nnpx @modelcontextprotocol/inspector node dist/index.js\n```\n\nThen open `http://localhost:6274` in your browser. The Inspector connects to the server, lists all available tools, and lets you invoke them with custom parameters.\n\n**OAuth grant access screen (first-run authorization):**\n\n![WHOOP OAuth grant access](images/Screenshot%202026-04-12%20at%202.40.55%E2%80%AFAM.png)\n\n**Testing `get_profile` tool in MCP Inspector:**\n\n![MCP Inspector — get_profile tool result](images/Screenshot%202026-04-12%20at%202.43.02%E2%80%AFAM.png)\n\n\n## Deployment (Docker + Cloud Hosting)\n\nThe HTTP transport (`MCP_TRANSPORT=http`) makes this server suitable for remote\nhosting so that web/mobile MCP clients (e.g. claude.ai connectors) can connect\nto your personal WHOOP data over the network. A production-ready\n[Dockerfile](Dockerfile) is included.\n\n> **Security warning.** When running over HTTP you are exposing your WHOOP data\n> behind a single bearer token. Use a strong random `MCP_AUTH_TOKEN`\n> (`openssl rand -hex 32`), only deploy behind TLS, restrict\n> `MCP_ALLOWED_ORIGINS`, and treat the host as a personal-use deployment — not\n> a multi-tenant service.\n\n### Image characteristics\n\n- Multi-stage build on `node:22-alpine` (compressed pull size **~58 MB**;\n  uncompressed ~258 MB — the floor is set by the Node.js runtime itself).\n- Runs as the unprivileged built-in `node` user (UID 1000).\n- `tini` as PID 1 for clean signal forwarding (graceful shutdown).\n- Health check uses Node's native `fetch` against `/health` — no `curl`/`wget`\n  baked into the image.\n- All configuration is supplied at runtime via env vars; no secrets are baked\n  into image layers.\n\n### Build & run locally\n\n```bash\ndocker build -t whoop-mcp .\n\n# Smoke test (runs node, prints \"ok\", exits)\ndocker run --rm whoop-mcp node -e \"console.log('ok')\"\n\n# Run the HTTP server\ndocker run --rm -p 3000:3000 \\\n  -e MCP_AUTH_TOKEN=\"$(openssl rand -hex 32)\" \\\n  -e WHOOP_CLIENT_ID=\"your-client-id\" \\\n  -e WHOOP_CLIENT_SECRET=\"your-client-secret\" \\\n  -e MCP_ALLOWED_ORIGINS=\"https://claude.ai\" \\\n  whoop-mcp\n\n# Health check\ncurl http://localhost:3000/health\n```\n\nRequired env vars (HTTP mode):\n\n| Variable                | Required | Default      | Notes                                                       |\n| ----------------------- | -------- | ------------ | ----------------------------------------------------------- |\n| `MCP_TRANSPORT`         | no       | `http`       | Image default; override with `stdio` or `both` if needed.   |\n| `MCP_AUTH_TOKEN`        | **yes**  | —            | Bearer token clients must send. Generate ≥32 random bytes.  |\n| `WHOOP_CLIENT_ID`       | **yes**  | —            | From your WHOOP developer app.                              |\n| `WHOOP_CLIENT_SECRET`   | **yes**  | —            | From your WHOOP developer app.                              |\n| `MCP_PORT`              | no       | `3000`       | Listen port.                                                |\n| `MCP_HOST`              | no       | `0.0.0.0`    | Listen interface.                                           |\n| `MCP_ALLOWED_ORIGINS`   | no       | (none)       | Comma-separated CORS allowlist.                             |\n| `MCP_TRUST_PROXY`       | no       | `0`          | Set `1` when behind a reverse proxy (Fly/Railway).          |\n| `LOG_LEVEL`             | no       | `info`       | `debug`/`info`/`warn`/`error`.                              |\n| `LOG_FORMAT`            | no       | `json`       | `json` for prod, `pretty` for local dev.                    |\n| `MCP_CONNECTOR_PASSWORD`| no       | —            | If set (≥12 chars), enables the OAuth 2.1 connector for claude.ai web/mobile. Requires `PUBLIC_URL` + `ALLOWED_REDIRECT_URIS`. |\n| `PUBLIC_URL`            | no       | —            | Public `https://` origin used as OAuth issuer.              |\n| `ALLOWED_REDIRECT_URIS` | no       | —            | Comma-separated exact-match list of OAuth redirect URIs.    |\n| `MCP_JWT_SECRET`        | no       | (HKDF)       | Override JWT signing key. Defaults to HKDF derivation from `MCP_AUTH_TOKEN`. |\n| `MCP_OAUTH_CLIENT_ID`   | no       | `whoop-mcp-connector` | OAuth client identifier advertised by the connector. |\n\n### Fly.io\n\n[Fly.io](https://fly.io) deploys directly from the Dockerfile and gives you a\nfree TLS-terminated public URL.\n\n```bash\n# One-time: install flyctl, sign in, and create the app from this repo's Dockerfile\nbrew install flyctl\nfly auth login\nfly launch --no-deploy --copy-config --name whoop-mcp-<your-suffix>\n\n# Set secrets (these are encrypted and injected as env at runtime — never baked in)\nfly secrets set \\\n  MCP_AUTH_TOKEN=\"$(openssl rand -hex 32)\" \\\n  WHOOP_CLIENT_ID=\"...\" \\\n  WHOOP_CLIENT_SECRET=\"...\" \\\n  MCP_TRUST_PROXY=1\n\n# Deploy\nfly deploy\nfly status\nfly logs\n```\n\nIn your generated `fly.toml`, make sure the HTTP service points at port 3000\nand that `force_https = true` is set under `[[http_service]]`. Fly handles\nTLS termination, so `MCP_TRUST_PROXY=1` is required for accurate client IPs\nin logs and rate-limit decisions.\n\n### Railway\n\n[Railway](https://railway.app) auto-detects the Dockerfile.\n\n1. Create a new project from this GitHub repo (or `railway up` from a clone).\n2. In **Variables**, add `MCP_AUTH_TOKEN`, `WHOOP_CLIENT_ID`,\n   `WHOOP_CLIENT_SECRET`, and `MCP_TRUST_PROXY=1`.\n3. Under **Settings → Networking**, generate a public domain. Railway\n   terminates TLS for you.\n4. Deploy. Health check path: `/health`.\n\n### Other platforms\n\nThe image is a stock OCI artifact and runs anywhere Docker does — Render, Cloud\nRun, Kubernetes, Hetzner, etc. The only platform-specific knob is\n`MCP_TRUST_PROXY=1` whenever you sit behind a TLS-terminating proxy.\n\n### Connecting from claude.ai (OAuth 2.1 connector)\n\nClaude Desktop and Claude Code can use the static `MCP_AUTH_TOKEN` bearer\ndirectly. The **claude.ai web/mobile** clients expect an OAuth 2.1 connector\nwith PKCE — set the three env vars below and the server mounts the connector\nautomatically on the same port as `/mcp`:\n\n```bash\nfly secrets set \\\n  MCP_CONNECTOR_PASSWORD=\"$(openssl rand -base64 24)\" \\\n  PUBLIC_URL=\"https://whoop-mcp-<your-suffix>.fly.dev\" \\\n  ALLOWED_REDIRECT_URIS=\"https://claude.ai/api/mcp/auth_callback\"\n```\n\n- `MCP_CONNECTOR_PASSWORD` (≥12 chars) — the human-facing password you'll type\n  into the claude.ai connector dialog. Treat it like any other shared secret.\n- `PUBLIC_URL` — the public `https://` origin claude.ai will reach. Used as\n  the OAuth issuer (e.g. `https://example.com` → metadata at\n  `/.well-known/oauth-authorization-server`).\n- `ALLOWED_REDIRECT_URIS` — comma-separated **exact-match** allowlist. For\n  claude.ai the value is `https://claude.ai/api/mcp/auth_callback`.\n- Optional: `MCP_JWT_SECRET` overrides the JWT signing key (defaults to an\n  HKDF derivation from `MCP_AUTH_TOKEN`); `MCP_OAUTH_CLIENT_ID` overrides the\n  advertised client id (default `whoop-mcp-connector`).\n\nIn claude.ai → Settings → Connectors → Add custom connector, point it at\n`PUBLIC_URL/mcp` and supply `MCP_CONNECTOR_PASSWORD` when prompted.\n\n## Development\n\n### Setup\n\n```bash\ngit clone https://github.com/shashankswe2020-ux/whoop-mcp.git\ncd whoop-mcp\nnpm install\n```\n\n### Commands\n\n| Command | Description |\n|---------|-------------|\n| `npm run build` | Build TypeScript |\n| `npm test` | Run tests (Vitest) |\n| `npm run typecheck` | Type check (`tsc --noEmit`) |\n| `npm run lint` | Lint (ESLint) |\n| `npm run lint:fix` | Lint + auto-fix |\n| `npm run format` | Format (Prettier) |\n| `npm run dev` | Run in dev mode (tsx) |\n\n### Project Structure\n\n```\nsrc/\n├── index.ts              # Entry point — auth, client, server, stdio\n├── server.ts             # MCP server + tool/resource/prompt registration\n├── auth/\n│   ├── oauth.ts          # OAuth2 Authorization Code flow\n│   ├── token-store.ts    # Secure token persistence\n│   └── callback-server.ts # Local OAuth callback server\n├── api/\n│   ├── client.ts         # HTTP client with retry + refresh\n│   ├── pagination.ts     # Auto-pagination utility (fetchAllPages)\n│   ├── types.ts          # WHOOP API response types\n│   └── endpoints.ts      # API URL constants\n├── resources/\n│   └── index.ts          # MCP Resource handlers (4 resources)\n├── tools/\n│   ├── get-profile.ts\n│   ├── get-recovery.ts\n│   ├── get-sleep.ts\n│   ├── get-workout.ts\n│   ├── get-cycle.ts\n│   ├── get-body-measurement.ts\n│   ├── get-sleep-by-id.ts\n│   ├── get-workout-by-id.ts\n│   ├── get-cycle-by-id.ts\n│   ├── get-weekly-summary.ts   # Analytical: weekly health report\n│   ├── compare-periods.ts      # Analytical: period comparison\n│   ├── get-trend.ts            # Analytical: trend detection\n│   ├── get-today.ts            # Composite: today's snapshot\n│   ├── get-calendar.ts         # Grid: multi-day calendar view\n│   ├── date-utils.ts           # Relative date expression parser\n│   ├── stats-utils.ts          # Statistics (mean, median, regression)\n│   └── collection-utils.ts\n├── prompts/\n│   └── index.ts                # MCP Prompt handlers (5 prompts)\n└── resources/\n    └── index.ts                # MCP Resource handlers (4 resources)\n```\n\n## Releases & npm Package\n\nThis project is published on npm as [`whoop-ai-mcp`](https://www.npmjs.com/package/whoop-ai-mcp).\n\n```bash\nnpm install -g whoop-ai-mcp\n```\n\nOr run directly with `npx`:\n\n```bash\nnpx whoop-ai-mcp\n```\n\n### Release Process\n\n1. Update the version in `package.json` and add a new entry in `CHANGELOG.md`\n2. Commit the changes: `git commit -am \"Release vX.Y.Z\"`\n3. Tag the release: `git tag vX.Y.Z`\n4. Push the commit and tag: `git push origin main vX.Y.Z`\n5. The [Release workflow](.github/workflows/release.yml) automatically creates a GitHub Release with notes extracted from the changelog\n6. The [npm publish workflow](.github/workflows/npm-publish.yml) automatically publishes the new version to npm\n\n### Changelog\n\nSee [CHANGELOG.md](CHANGELOG.md) for a full list of changes in each release.\n\n## Privacy notes for analytical tools\n\nThe analytical tools — `get_weekly_summary`, `get_trend`, and\n`compare_periods` — return pre-computed statistical summaries derived from\nyour underlying recovery / sleep / cycle / workout records. No new health\ndata is exposed beyond what the per-record collection tools already return\n(`get_recovery_collection`, `get_sleep_collection`, etc.), but the\naggregated form is more concentrated and easier to scan over time. In\nparticular, the `anomalies` array returned by `get_trend` flags days that\ndeviate from your personal baseline — such days may correlate with\nillness, injury, travel, or lifestyle changes.\n\nIf you connect this MCP server to a remote AI assistant (rather than a\nlocal one), be aware that those summaries will be sent to that assistant\nin the same way any other tool result is. All data continues to flow only\nbetween the WHOOP API, this MCP server running on your machine, and the\nassistant you explicitly invoke — there is no third-party telemetry.\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for development workflow, coding conventions, and the project's Copilot agent/skill configuration.\n\n## License\n\n[MIT](LICENSE)\n",
  "bytes": 35400,
  "sha": "0c874bc1c94c24ceb051d344b8f8d48191c2002643f553ccb1462a2cf1cf9bea",
  "repo_slug": "shashankswe2020-ux/whoop-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_shashankswe2020_ux_whoop_aa2c27dc/readme"
}