Skip to main content
Glama
colesmcintosh

whoop-chatgpt-app

README.md
# WHOOP ChatGPT App

![Node.js >= 20](https://img.shields.io/badge/node-%3E%3D20-339933?logo=node.js&logoColor=white)
![TypeScript](https://img.shields.io/badge/typescript-5.x-3178C6?logo=typescript&logoColor=white)
![React](https://img.shields.io/badge/react-18-61DAFB?logo=react&logoColor=111111)
![MCP](https://img.shields.io/badge/MCP-server-6f42c1)
![ChatGPT Apps SDK](https://img.shields.io/badge/ChatGPT%20Apps%20SDK-widget-10A37F)
![WHOOP API](https://img.shields.io/badge/WHOOP-API-111111)
![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)

A ChatGPT Apps SDK project that connects WHOOP health tracker data to ChatGPT through a remote MCP server and renders an interactive WHOOP dashboard widget in ChatGPT.

The app is a read-only health-data connector. It can search WHOOP records, fetch individual records, summarize recent recovery/sleep/strain/workout data, and render a dashboard UI from either freshly loaded WHOOP data or previously returned structured content.

> This project is for software integration and personal health-data exploration. It is not medical advice.

## Screenshots

These screenshots use synthetic demo data and are safe to publish.

| Desktop | Mobile |
| --- | --- |
| ![WHOOP dashboard desktop screenshot](docs/screenshots/whoop-dashboard-desktop.jpg) | ![WHOOP dashboard mobile screenshot](docs/screenshots/whoop-dashboard-mobile.jpg) |

## Features

- ChatGPT Apps SDK-compatible MCP server at `/mcp`
- Connector-style `search` and `fetch` tools for read-only WHOOP data retrieval
- WHOOP OAuth helper for local development
- React widget rendered inside ChatGPT
- Dashboard cards for recovery, strain, sleep performance, and latest workout
- Recent records timeline with filters for recovery, sleep, workout, and cycle strain
- Widget actions for refresh, interpretation follow-up, and fullscreen display
- Synthetic demo mode for safe screenshots and README assets

## Architecture

```text
ChatGPT
  |
  | remote MCP over HTTPS
  v
server/
  - MCP tools
  - WHOOP OAuth helper
  - WHOOP API client
  - widget resource registration
  |
  | embeds bundled widget resource
  v
web/
  - React dashboard widget
  - MCP Apps bridge integration
```

App shape:

- Archetype: `react-widget`
- Architecture: decoupled data/render
- Connector surface: standard read-only `search` and `fetch` tools
- Widget rendering: `render_whoop_dashboard`

## Tools

All tools are read-only.

| Tool | Purpose |
| --- | --- |
| `search(query)` | Finds recent WHOOP profile, recovery, cycle, sleep, and workout records. |
| `fetch(id)` | Fetches one record returned by `search`. |
| `get_whoop_summary(days, includeProfile)` | Returns a compact model-readable WHOOP summary. |
| `render_whoop_dashboard(days, includeProfile, dashboard)` | Renders the React widget. It can load data directly using `days`/`includeProfile`, or render a dashboard object returned by `get_whoop_summary`. |

## Requirements

- Node.js 20 or newer
- npm
- A WHOOP Developer app for live data
- An HTTPS tunnel for ChatGPT Developer Mode testing, such as ngrok

## Quick Start

```bash
npm install
cp .env.example .env
npm run build
npm start
```

The server listens on:

```text
http://localhost:8787/mcp
```

## WHOOP Setup

Create a WHOOP Developer app and configure these read scopes:

```text
read:profile read:body_measurement read:cycles read:recovery read:sleep read:workout
```

For local development:

1. Start a public HTTPS tunnel to port `8787`.
2. Set `PUBLIC_BASE_URL` to the tunnel origin.
3. Set `WHOOP_CLIENT_ID`, `WHOOP_CLIENT_SECRET`, and `WHOOP_REDIRECT_URI` in `.env`.
4. Register the same redirect URI in WHOOP, for example `https://example.ngrok.app/oauth/callback`.
5. Restart the server.
6. Open `https://example.ngrok.app/oauth/start` in your browser and link WHOOP.

The local OAuth helper stores the WHOOP access token in server memory. Restarting the server clears the link.

## ChatGPT Developer Mode

ChatGPT requires a public HTTPS MCP URL for remote app testing.

```bash
npm start
ngrok http 8787
```

Use the tunneled MCP URL:

```text
https://example.ngrok.app/mcp
```

In ChatGPT:

1. Enable Developer Mode under **Settings -> Apps & Connectors -> Advanced settings**.
2. Create a new app/connector.
3. Paste the tunneled `/mcp` URL.
4. Use **No Auth** for local development with `CHATGPT_APP_AUTH=none`.
5. Refresh or reconnect the app after tool, metadata, or widget changes.

Example prompt:

```text
Use the Whoop app to show my WHOOP dashboard for the last 7 days.
```

## Environment Variables

Copy `.env.example` to `.env` and fill in local values.

| Variable | Required | Description |
| --- | --- | --- |
| `PORT` | No | Local HTTP port. Defaults to `8787`. |
| `PUBLIC_BASE_URL` | Yes for OAuth/ChatGPT | Public origin for OAuth redirects and metadata. |
| `WHOOP_CLIENT_ID` | Yes for OAuth | WHOOP Developer app client ID. |
| `WHOOP_CLIENT_SECRET` | Yes for OAuth | WHOOP Developer app client secret. Do not commit it. |
| `WHOOP_REDIRECT_URI` | Yes for OAuth | Redirect URI registered in WHOOP. |
| `CHATGPT_APP_AUTH` | No | Use `none` for local Developer Mode testing. |
| `WHOOP_ACCESS_TOKEN` | No | Local single-user shortcut. Prefer OAuth for normal testing. |
| `AUTHORIZATION_SERVER_URL` | Production only | OAuth 2.1 authorization server for production ChatGPT linking. |
| `WHOOP_API_BASE_URL` | No | WHOOP API override for tests or proxies. |

## Development

```bash
npm run dev      # run the TypeScript server with tsx
npm run build    # build web widget and server
npm run check    # type-check web and server
npm start        # run the built server
```

MCP Inspector:

```bash
npx @modelcontextprotocol/inspector@latest --server-url http://localhost:8787/mcp --transport http
```

## Project Structure

```text
.
├── docs/screenshots/        # publishable screenshots with synthetic data
├── server/
│   └── src/
│       ├── index.ts         # MCP server, tools, OAuth routes, resource registration
│       ├── whoop-client.ts  # WHOOP API client
│       └── whoop-format.ts  # record formatting and dashboard summarization
├── web/
│   └── src/
│       ├── main.tsx         # React widget and Apps bridge integration
│       └── styles.css       # responsive widget styling
├── .env.example
├── package.json
└── README.md
```

## Security and Privacy

- `.env` is ignored by git.
- Do not commit WHOOP client secrets, access tokens, refresh tokens, or tunnel URLs.
- WHOOP tokens stay server-side and are never exposed to the widget.
- The local OAuth helper stores tokens in memory only.
- Screenshots in `docs/screenshots` use synthetic data.
- Production apps should validate token issuer, audience/resource, expiry, and scopes before calling WHOOP.

## Production Notes

The local setup uses `CHATGPT_APP_AUTH=none` so ChatGPT Developer Mode can connect while the server uses the locally linked WHOOP token. For production, put a ChatGPT-compatible OAuth 2.1 authorization layer in front of WHOOP and advertise OAuth security schemes from the MCP server.

Production hosting should include:

- Stable public HTTPS endpoint
- Secure secret storage
- Token verification and refresh handling
- Request logging without sensitive data
- Rate-limit and WHOOP API error handling
- Re-test in ChatGPT Developer Mode before submission

## Open Source Checklist

Before publishing:

- Confirm `.env` is not staged.
- Replace any local tunnel URLs in docs or examples with placeholders.
- Run `npm run check`.
- Run `npm run build`.
- Review screenshots for synthetic data only.

## License

MIT. See [LICENSE](LICENSE).

Maintenance

ActivityInactive
ResponsivenessNo issues