Skip to main content
Glama
J-O-WORK-REDESIGN-FDE-COHORT

Sapphire Wellness MCP Server

README.md
# Sapphire Wellness MCP Server

A Python [Model Context Protocol (MCP)](https://modelcontextprotocol.io) server that exposes health metrics from the Sapphire Wellness App to AI assistants.

## Metrics Exposed

| Metric | Tool | Data Points |
|--------|------|-------------|
| Activity | `get_activity` | Steps, calories, distance, active minutes |
| Blood Pressure | `get_blood_pressure` | Systolic/diastolic (mmHg), AHA category |
| Glucose | `get_glucose` | Blood glucose (mg/dL), meal context, time-in-range |
| Heart Rate | `get_heart_rate` | BPM readings, avg/min/max, resting HR |
| Sleep | `get_sleep` | Duration, deep/light/REM/awake stages, efficiency |
| SpO2 | `get_spo2` | Oxygen saturation %, low-saturation event count |
| Summary | `get_health_summary` | All 6 metrics in a single call |

## Architecture

```
Agent Container
      │  HTTP SSE
      ▼
sapphire-mcp:8000  ──asyncpg──▶  PostgreSQL:5432
```

- **Transport**: HTTP SSE — required for multi-container deployments (stdio only works when the agent spawns the MCP server as a child process)
- **Database**: PostgreSQL with OpenTelemetry-style metric tables (`time`, `metric_name`, `metric_value`, `attributes JSONB`, ...)
- **Framework**: [FastMCP](https://github.com/modelcontextprotocol/python-sdk) with Pydantic v2 response models

See [Design.md](Design.md) for the full architecture document.

## Project Structure

```
MCPServers/
├── sapphire_wellness/
│   ├── server.py           # FastMCP app + SSE entry point
│   ├── config.py           # Settings (DB_URL, HOST, PORT via env)
│   ├── models/             # Pydantic response models per metric
│   ├── db/                 # asyncpg pool + shared base query
│   ├── repositories/       # DB → model mapping (one per metric)
│   └── tools/              # MCP tool definitions (one per metric)
├── Design.md               # Architecture reference
├── pyproject.toml
├── Dockerfile
├── podman-compose.yml
└── .env.example
```

## Prerequisites

- Python 3.11+
- PostgreSQL 14+ with the 6 wellness metric tables created
- [podman-compose](https://github.com/containers/podman-compose) or Docker Compose (for containerised deployment)

## Quick Start

### Local Development

```bash
# 1. Create and activate a virtual environment
python -m venv .venv

# Windows
.venv\Scripts\activate

# macOS / Linux
source .venv/bin/activate

# 2. Install dependencies
pip install -e .

# 3. Configure environment
cp .env.example .env
# Edit .env — set DB_URL to your PostgreSQL connection string

# 4. Run the server
python -m sapphire_wellness.server
# Server starts at http://0.0.0.0:8000
```

### Containerised (podman-compose)

```bash
# Build and start all services (postgres + mcp server)
podman-compose up --build

# Tear down
podman-compose down
```

The MCP server will be available at `http://localhost:10002/sse`.

To connect your agent container, set:
```
MCP_SERVER_URL=http://sapphire-mcp:10002/sse
```

## Configuration

All settings are read from environment variables (or a `.env` file):

| Variable | Default | Description |
|----------|---------|-------------|
| `DB_USER` | `wellness` | PostgreSQL username |
| `DB_PASSWORD` | `wellness` | PostgreSQL password |
| `DB_HOST` | `localhost` | PostgreSQL host (`postgres` inside podman-compose) |
| `DB_PORT` | `5432` | PostgreSQL port |
| `DB_NAME` | `wellness` | PostgreSQL database name |
| `HOST` | `0.0.0.0` | MCP server bind address |
| `PORT` | `8000` | MCP server bind port |

## Tool Reference

All tools share these parameters:

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `user_id` | `str` | — | User whose data to query |
| `date` | `str` | `"today"` | ISO date `YYYY-MM-DD` or `"today"` |
| `period` | `str` | `"day"` | `"day"` (24 h), `"week"` (7 days), `"month"` (30 days) |

### `get_activity`
Returns steps, calories, distance, and active minutes. Totals are summed across the period.

### `get_blood_pressure`
Returns systolic/diastolic readings in mmHg. Each reading is classified using AHA categories:
- **Normal** — systolic <120 and diastolic <80
- **Elevated** — systolic 120–129 and diastolic <80
- **High Stage 1** — systolic 130–139 or diastolic 80–89
- **High Stage 2** — systolic ≥140 or diastolic ≥90
- **Hypertensive Crisis** — systolic >180 or diastolic >120

### `get_glucose`
Returns glucose readings in mg/dL with meal context (`fasting`, `pre_meal`, `post_meal`, `bedtime`, `random`) and statistics including time-in-range (target: 70–180 mg/dL).

### `get_heart_rate`
Returns heart rate readings in BPM (active and resting) with average, min, max, and average resting BPM.

### `get_sleep`
Returns sleep stage breakdown (deep, light, REM, awake) in minutes, total duration, and sleep efficiency percentage.

### `get_spo2`
Returns SpO2 readings in %, with average, min, max, and a count of low-saturation events (below 95%).

### `get_health_summary`
Calls all 6 metric repos concurrently and returns a single combined response — ideal for daily health briefings.

## Inspecting Tools

Use the [MCP Inspector](https://github.com/modelcontextprotocol/inspector) to explore tool schemas and make test calls:

```bash
npx @modelcontextprotocol/inspector http://localhost:8000/sse
```

## Connecting to Claude Desktop

Add to your `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "sapphire-wellness": {
      "url": "http://localhost:8000/sse"
    }
  }
}
```

Then ask Claude: *"What was my blood pressure this week?"* and it will call `get_blood_pressure` with `period="week"`.

## Database Schema

All 6 tables (`heartrate`, `bloodpressure`, `glucose`, `spo2`, `activity`, `sleep`) share the same OpenTelemetry-style schema. The `metric_name` column distinguishes sub-metrics within each table (e.g. `systolic` and `diastolic` are separate rows in `bloodpressure`). See [Design.md](Design.md) for the full DDL and sub-metric mapping.

## Extending

**Adding a new metric:**
1. Create `sapphire_wellness/models/<metric>.py` — Pydantic model
2. Create `sapphire_wellness/repositories/<metric>_repo.py` — DB query + mapping
3. Create `sapphire_wellness/tools/<metric>.py` — `@mcp.tool()` definition
4. Register in `server.py`

**Swapping the database:**
Implement a new class that mirrors the method signatures in `repositories/base.py` (`HealthRepository`) and pass it to the `register()` functions in `server.py`.

**Adding `check_health_alerts`:**
This tool is planned for Phase 2. It will flag readings outside normal thresholds (e.g. BP >140/90, SpO2 <95%) and return structured alerts with severity levels.