Skip to main content
Glama
Marholoubek

Health MCP Server

by Marholoubek
README.md
# Health MCP Server

A Model Context Protocol (MCP) server for aggregating and analyzing health and fitness data from multiple sources. Currently supports **Whoop** and **Strava** with an extensible adapter architecture for future integrations (Withings, Oura, Garmin, etc.).

## Features

### Multi-Provider Support
- **Modular Architecture**: Each adapter is optional and independently configurable
- **Auto-Enable**: Adapters are automatically enabled when credentials are configured
- **Unified Auth**: Single OAuth callback server shared across all providers

### Whoop Integration
- **Sleep Analysis**: Track sleep duration, stages (deep, REM, light), efficiency, and consistency
- **Recovery Tracking**: Monitor recovery scores, HRV, resting heart rate, and SpO2
- **Strain Monitoring**: View daily strain, workout history, and heart rate zones
- **Advanced Insights**: Get personalized recommendations, trend analysis, and correlations

### Strava Integration
- **Activity Tracking**: View runs, rides, swims, and all activity types with full stats
- **Performance Metrics**: Distance, pace, speed, elevation, heart rate, power, and cadence
- **Training Zones**: Heart rate and power zone configuration and per-activity distribution
- **Athlete Stats**: All-time totals, year-to-date, and recent activity summaries
- **Gear Tracking**: Monitor distance on bikes, shoes, and other equipment

## Available Tools

### General
| Tool | Description |
|------|-------------|
| `list_adapters` | List all available adapters and their authentication status |

### Whoop Tools

#### Authentication
| Tool | Description |
|------|-------------|
| `whoop_authenticate` | Initiate OAuth2 login flow for Whoop |
| `whoop_check_auth` | Check current authentication status |

#### Profile
| Tool | Description |
|------|-------------|
| `get_user_profile` | Get user profile and body measurements |

#### Sleep
| Tool | Description |
|------|-------------|
| `get_sleep_summary` | Recent sleep with performance, stages, and needs |
| `get_sleep_history` | Sleep history over date range with trends |

#### Recovery
| Tool | Description |
|------|-------------|
| `get_recovery_score` | Latest recovery with HRV and status |
| `get_recovery_history` | Recovery trends over time |

#### Strain & Workouts
| Tool | Description |
|------|-------------|
| `get_strain_today` | Current day strain and heart rate |
| `get_strain_history` | Daily strain patterns over time |
| `get_workout_history` | Workout details with HR zones and calories |

#### Analysis & Insights
| Tool | Description |
|------|-------------|
| `get_health_overview` | Comprehensive health dashboard |
| `analyze_sleep_patterns` | Sleep timing, consistency, and recommendations |
| `analyze_recovery_factors` | Correlations affecting recovery |
| `get_weekly_report` | Week-over-week comparison with trends |
| `get_training_readiness` | Workout intensity recommendations |

### Strava Tools

#### Authentication
| Tool | Description |
|------|-------------|
| `strava_authenticate` | Initiate OAuth2 login flow for Strava |
| `strava_check_auth` | Check current Strava authentication status |

#### Profile & Stats
| Tool | Description |
|------|-------------|
| `get_strava_profile` | Athlete profile with all-time stats and gear |

#### Activities
| Tool | Description |
|------|-------------|
| `get_strava_activities` | Recent activities with distance, pace, HR, etc. |
| `get_strava_activity_detail` | Detailed activity with laps, segments, and full stats |
| `get_strava_weekly_summary` | Weekly training summary by activity type |

#### Training Zones
| Tool | Description |
|------|-------------|
| `get_strava_zones` | Your configured HR and power training zones |
| `get_strava_activity_zones` | Zone distribution for a specific activity |

## Installation

### Prerequisites

- Python 3.10 or higher
- API credentials for at least one provider (Whoop and/or Strava)

### Setup

1. **Clone the repository**
   ```bash
   cd /path/to/health_mcp
   ```

2. **Create a virtual environment**
   ```bash
   python -m venv venv
   source venv/bin/activate  # On Windows: venv\Scripts\activate
   ```

3. **Install dependencies**
   ```bash
   pip install -r requirements.txt
   ```

4. **Configure API credentials**

   Copy the example configuration:
   ```bash
   cp config.example.yaml config.yaml
   ```

   Edit `config.yaml` with your API credentials (configure one or both):
   ```yaml
   # Whoop - Get credentials from https://developer.whoop.com/
   whoop:
     client_id: "your_client_id_here"
     client_secret: "your_client_secret_here"
     redirect_uri: "http://localhost:8787/callback"

   # Strava - Get credentials from https://www.strava.com/settings/api
   strava:
     client_id: "your_client_id_here"
     client_secret: "your_client_secret_here"
     redirect_uri: "http://localhost:8787/callback"
   ```

   **Alternative: Environment Variables**
   ```bash
   # Whoop
   export HEALTH_MCP_WHOOP_CLIENT_ID="your_client_id"
   export HEALTH_MCP_WHOOP_CLIENT_SECRET="your_client_secret"

   # Strava
   export HEALTH_MCP_STRAVA_CLIENT_ID="your_client_id"
   export HEALTH_MCP_STRAVA_CLIENT_SECRET="your_client_secret"
   ```

### Getting API Credentials

#### Whoop
1. Go to [Whoop Developer Portal](https://developer.whoop.com/)
2. Create a new application
3. Set the redirect URI to `http://localhost:8787/callback`
4. Copy your Client ID and Client Secret

#### Strava
1. Go to [Strava API Settings](https://www.strava.com/settings/api)
2. Create a new application (or use an existing one)
3. Set the "Authorization Callback Domain" to `localhost`
4. Copy your Client ID and Client Secret

## Usage with Claude Desktop

Add the following to your Claude Desktop configuration file:

**macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows**: `%APPDATA%\Claude\claude_desktop_config.json`

```json
{
    "mcpServers": {
        "health": {
            "command": "/path/to/health_mcp/venv/bin/python",
            "args": ["-m", "src.server"],
            "cwd": "/path/to/health_mcp",
            "env": {
                "HEALTH_MCP_WHOOP_CLIENT_ID": "your_whoop_client_id",
                "HEALTH_MCP_WHOOP_CLIENT_SECRET": "your_whoop_client_secret",
                "HEALTH_MCP_STRAVA_CLIENT_ID": "your_strava_client_id",
                "HEALTH_MCP_STRAVA_CLIENT_SECRET": "your_strava_client_secret"
            }
        }
    }
}
```

## Usage with Cursor

Add the following to your Cursor MCP settings:

```json
{
  "mcpServers": {
    "health": {
      "command": "/path/to/health_mcp/venv/bin/python",
      "args": ["-m", "src.server"],
      "cwd": "/path/to/health_mcp"
    }
  }
}
```

## First-Time Authentication

After setting up the MCP server, authenticate with each provider you've configured:

### Whoop
1. Ask the AI: "Authenticate with my Whoop account"
2. A browser window will open for OAuth authorization
3. Log in and authorize the application
4. The token is automatically saved

### Strava
1. Ask the AI: "Authenticate with my Strava account"
2. A browser window will open for Strava OAuth
3. Authorize the requested permissions
4. The token is automatically saved

You can check which adapters are available and authenticated by asking: "List my health adapters"

## Example Questions

### Whoop-Specific
- "How did I sleep last night?"
- "What's my recovery score today?"
- "Show me my sleep trends for the past month"
- "Am I ready for a hard workout today?"
- "What factors are affecting my recovery?"

### Strava-Specific
- "Show me my recent Strava activities"
- "What's my weekly training summary?"
- "Show me details for my last run"
- "What are my training zones?"
- "How much have I cycled this year?"

### Combined Analysis (when both are connected)
- "Compare my workout strain from Whoop with my Strava activities"
- "Show me my overall fitness status"
- "How does my training load look across all sources?"

## Project Structure

```
health_mcp/
├── src/
│   ├── __init__.py
│   ├── server.py              # Main MCP server with dynamic adapter loading
│   ├── config.py              # Configuration management
│   ├── auth/
│   │   ├── __init__.py
│   │   ├── oauth_server.py    # Shared OAuth callback server
│   │   └── token_store.py     # Token persistence
│   ├── adapters/
│   │   ├── __init__.py
│   │   ├── base.py            # Abstract adapter interface
│   │   ├── whoop.py           # Whoop API adapter
│   │   └── strava.py          # Strava API adapter
│   └── tools/
│       ├── __init__.py
│       ├── sleep.py           # Whoop sleep tools
│       ├── recovery.py        # Whoop recovery tools
│       ├── strain.py          # Whoop strain & workout tools
│       ├── profile.py         # Whoop profile tools
│       ├── insights.py        # Whoop analysis tools
│       └── strava.py          # Strava-specific tools
├── config.example.yaml
├── requirements.txt
└── README.md
```

## Adapter Architecture

The server uses a modular adapter pattern:

- **Optional Adapters**: Each adapter is optional and independently enabled
- **Auto-Discovery**: Adapters are automatically enabled when credentials are present
- **Explicit Control**: Use `enabled: true/false` in config to override auto-detection
- **Unified Interface**: All adapters implement a common base class for consistency
- **Provider-Specific Tools**: Each adapter can expose unique tools for provider-specific features

### Configuration Options

```yaml
# Each adapter section supports:
provider_name:
  client_id: "..."
  client_secret: "..."
  redirect_uri: "http://localhost:8787/callback"
  enabled: true  # Optional: explicitly enable/disable (auto-detected by default)
```

## Extending with New Adapters

To add a new health data provider:

1. Create a new adapter in `src/adapters/` implementing the `HealthAdapter` base class
2. Add configuration properties in `src/config.py`
3. Create provider-specific tools in `src/tools/`
4. Register the adapter and tools in `src/server.py`

Example adapter skeleton:
```python
from .base import HealthAdapter, SleepRecord, RecoveryRecord, WorkoutRecord

class NewProviderAdapter(HealthAdapter):
    provider_name = "new_provider"

    async def is_authenticated(self) -> bool:
        # Check auth status
        pass

    async def authenticate(self) -> bool:
        # Initiate OAuth flow
        pass

    async def get_workouts(self, start=None, end=None, limit=10) -> list[WorkoutRecord]:
        # Implement workout data fetching
        pass

    # Implement other methods (return empty lists for unsupported features)
```

## Token Storage

OAuth tokens are stored securely at `~/.health_mcp/tokens.json` with restricted file permissions (600). Tokens are automatically refreshed when expired.

## Troubleshooting

### "Not authenticated" errors
Run the appropriate authenticate tool:
- Whoop: `whoop_authenticate`
- Strava: `strava_authenticate`

### "Missing configuration" errors
Ensure your `config.yaml` is set up correctly or environment variables are exported.

### OAuth callback fails
- Ensure port 8787 is available
- Check that your redirect URI matches exactly in the provider's developer portal
- For Strava, ensure the Authorization Callback Domain is set to `localhost`

### Token refresh fails
Delete `~/.health_mcp/tokens.json` and re-authenticate.

### Adapter not showing up
- Check that credentials are configured correctly
- Use `list_adapters` tool to see adapter status
- Check server logs for initialization errors

## License

MIT License

## Contributing

Contributions are welcome! Please feel free to submit pull requests for:
- New health data adapters (Withings, Oura, Garmin, Apple Health, etc.)
- Additional analysis tools
- Bug fixes and improvements

TDQS

A4.1/5.0

Scored across 1 tool

Disambiguation5/5

With only a single tool, there is no possibility of ambiguity between tools. The purpose of 'list_adapters' is clear and distinct by default.

Naming Consistency5/5

The single tool name 'list_adapters' follows a consistent verb_noun pattern, which is clear and predictable. No inconsistencies exist due to the singular tool.

Tool Count2/5

The server has only one tool, which feels insufficient for a server branded as 'Health MCP Server'. The scope appears extremely narrow, and a health-related server would typically require multiple tools to be useful (e.g., data retrieval, management).

Completeness1/5

The tool surface is severely incomplete. A health server should include tools for querying health data, managing adapters (add/remove/update), and possibly filtering or analyzing data. The single 'list_adapters' tool covers only a trivial subset of expected functionality.

Maintenance

ActivityInactive
ResponsivenessNo issues