MCP Health Coach
by HamzaOuadid
README.md
# MCP Health Coach
[](https://github.com/HamzaOuadid/mcp-health-coach/actions/workflows/ci.yml)
[](LICENSE)
[](https://www.python.org/downloads/)
An MCP server that turns any MCP-compatible LLM client (Claude Desktop, etc.) into a wellness coach grounded in verified public data.
**Core design principle:** the coaching conversation lives in the LLM, but every factual claim — a nutrient value, a supplement warning, a screening recommendation — is backed by a real tool call to a government or verified source, not generated from the model's training data.
## Demo
No API keys needed to see the core logic run — `demo/run_example.py` calls the local-computation tools directly (the same functions the MCP server exposes) using the persona from the [coaching session example](#5-try-a-coaching-session) below:
```bash
python demo/run_example.py
```
<details>
<summary>Sample output</summary>
```
============================================================
1. calculate_daily_needs — establish calorie/macro targets
============================================================
{
"bmr": 1422,
"tdee": 2204,
"target_calories": 1704,
"macro_split": {
"protein_g": 122,
"carbs_g": 189,
"fat_g": 51
},
"goal": "lose",
"goal_label": "Fat loss (~0.5 kg/week deficit)",
"activity_level": "moderate",
"note": "~500 kcal/day deficit; expect ~0.5 kg loss per week",
"coaching_context": "For a 32-year-old female at 68 kg / 170 cm with moderate activity, targeting lose. Daily target: 1704 kcal (122g protein / 189g carbs / 51g fat)."
}
============================================================
2. calculate_bmi — quick screening metric
============================================================
{
"bmi": 23.5,
"category": "Normal weight",
"healthy_weight_range_kg": { "min": 53.5, "max": 72.0 },
"weight_kg": 68,
"height_cm": 170,
"note": "BMI is a population-level screening tool. It does not account for muscle mass, bone density, age, or fat distribution. Body fat percentage and waist circumference provide a fuller picture."
}
============================================================
3. calculate_water_intake — daily hydration target
============================================================
{
"daily_water_target_ml": 2780,
"range_ml": { "min": 2502, "max": 3058 },
"in_liters": 2.78,
"in_cups_8oz": 12,
"activity_level": "moderate",
"climate": "temperate",
"note": "This is an estimate for total fluid intake (water, beverages, food moisture). Pure water needs are roughly 70-80% of this figure. Urine color is the simplest real-time hydration check: pale yellow = well hydrated."
}
============================================================
4. calculate_calories_burned — factor in a planned workout
============================================================
{
"activity": "running (5mph / 12 min/mile)",
"duration_minutes": 30,
"weight_kg": 68,
"met_value": 8.3,
"intensity": "vigorous",
"calories_burned": 282,
"calories_per_minute": 9.4,
"source": "2011 Compendium of Physical Activities (Ainsworth et al.)",
"note": "MET-based estimates assume average metabolic efficiency. Individual variation (fitness level, terrain, pace consistency) typically puts real burn within ±15% of this estimate."
}
```
</details>
The full experience — chaining in `suggest_recipe`, `build_workout_plan`, and `get_preventive_care_recommendations` against live external APIs — runs through an MCP client like Claude Desktop; see [Setup](#setup) below.
## Tools (31 total)
### Core coaching
| Tool | Source | What it does |
|------|--------|-------------|
| `calculate_daily_needs` | Local (Mifflin-St Jeor) | BMR, TDEE, calorie + macro targets |
| `get_food_nutrition` | USDA FoodData Central → Open Food Facts | Unified nutrition facts by name or barcode |
| `suggest_recipe` | Edamam | Recipes matching calorie/macro/dietary targets |
| `get_exercise` | Wger + ExerciseDB | Exercises by muscle group, equipment, difficulty |
| `build_workout_plan` | Wger + program-design logic | Full weekly plan with sets/reps/rest |
| `get_health_topic_summary` | MedlinePlus (NLM/NIH) | Plain-language topic summaries + citations |
| `check_supplement_interaction` | openFDA | FDA-reported warnings and interactions |
| `get_preventive_care_recommendations` | ODPHP MyHealthfinder | Age/sex-appropriate screenings + vaccines |
### Body metrics & calculations
| Tool | What it does |
|------|-------------|
| `calculate_bmi` | Body mass index + category |
| `calculate_body_fat` | Body fat % (Navy method) |
| `calculate_water_intake` | Daily hydration target |
| `estimate_healthy_weight_range` | Healthy weight range for a given height |
| `calculate_calories_burned` | Calories burned for an activity + duration |
| `list_activities` | Browse the local calorie-burn activity table |
### Nutrition utilities
| Tool | Source | What it does |
|------|--------|-------------|
| `get_meal_totals` | Local (composes `get_food_nutrition`) | Aggregate macros/calories across a meal's items |
| `compare_foods` | USDA FoodData Central → Open Food Facts | Side-by-side nutrition comparison |
| `find_foods_high_in_nutrient` | USDA FoodData Central | Foods ranked by a target nutrient |
| `get_vitamin_mineral_info` | Local reference data | RDA, deficiency/toxicity signs, food sources |
| `search_nutrition_research` | PubMed | Peer-reviewed research summaries + citations |
### Biometrics & device integrations
Pulls live data from the user's own wearables/scales rather than static reference data. All integrations are optional and env-var gated — tools degrade gracefully with setup instructions when nothing is configured. See [Wearable Integrations](#wearable-integrations) below.
| Tool | What it does |
|------|-------------|
| `get_available_integrations` | Reports which wearable/device integrations are configured and ready |
| `get_biometric_summary` | Unified resting HR, HRV, sleep, steps, active calories, body composition |
| `get_sleep_analysis` | Per-night sleep breakdown, averages, sleep-debt and quality coaching flags |
| `get_recovery_score` | 0–100 recovery score (Oura readiness or computed from HRV/RHR/sleep) |
| `get_hrv_trends` | Daily HRV, 7-day rolling average, trend direction |
| `get_activity_summary` | Daily steps/active minutes vs. WHO 150 min/week guideline |
| `get_body_composition_trend` | Weight/body-fat trend, rate of change, aggressive-loss flag |
| `get_strain_score` | TRIMP-based training load from workouts / HR zones |
| `log_behavior_entry` | Journal lifestyle factors (sleep, alcohol, stress, caffeine, etc.) |
| `get_behavior_correlations` | Pearson correlations between journaled behaviors and next-day biometrics |
| `scan_ble_devices` | Discover nearby BLE health devices |
| `read_live_heart_rate` | Stream live HR + RMSSD HRV from a BLE heart rate monitor |
## Workflow
A typical coaching session chains tools in order:
```
1. calculate_daily_needs → establishes calorie/macro targets
2. get_food_nutrition → checks specific foods against those targets
3. suggest_recipe → finds meals that fit the daily plan
4. build_workout_plan → creates a training program for the goal
5. get_health_topic_summary → answers background health questions with citations
6. check_supplement_interaction → safety-checks supplements being considered
7. get_preventive_care_recommendations → surfaces relevant screenings
```
## Wearable Integrations
Each integration is activated purely by setting its env vars in `.env` — no code changes needed. `get_available_integrations` reports what's active and what's missing, including setup links.
| Integration | Env vars | Extra install |
|-------------|----------|----------------|
| Oura Ring | `OURA_PAT` | — |
| Polar (Accesslink) | `POLAR_ACCESS_TOKEN`, `POLAR_USER_ID` | — |
| Withings | `WITHINGS_ACCESS_TOKEN` | — |
| Fitbit | `FITBIT_ACCESS_TOKEN` | — |
| Garmin Connect | `GARMIN_EMAIL`, `GARMIN_PASSWORD` | `pip install garminconnect>=0.2.0` |
| Direct BLE (Polar H10, Bangle.js 2, PineTime, ESP32+MAX30102) | `BLE_DEVICE_ADDRESS` (optional default) | `pip install bleak>=0.21.0` |
Aggregation tools (`get_biometric_summary`, `get_sleep_analysis`, etc.) use whatever sources are active and label each metric with its source, generally preferring Oura > Withings > Garmin > Fitbit > Polar depending on the metric.
## Safety
- **Emergency hard-guard:** All tool inputs are checked against a hardcoded list of emergency phrases (chest pain, suicidal ideation, overdose, etc.) *before* any tool logic runs. Matching inputs return a fixed emergency-services redirect — this is not LLM-dependent.
- **Structural disclaimers:** Every Health Reference tool (MedlinePlus, openFDA, ODPHP) wraps its payload with a source citation and standard disclaimer before returning to the model. The LLM cannot forget to include it.
- **Scope boundary:** This tool covers general wellness, nutrition, and fitness. It does not diagnose, does not recommend medication dosages, and does not override physician guidance.
## Setup
### 1. Install dependencies
```bash
cd mcp-health-coach
pip install -r requirements.txt
```
### 2. Configure API keys
```bash
cp .env.example .env
# Edit .env with your keys
```
Required keys:
- `EDAMAM_APP_ID` + `EDAMAM_APP_KEY` — free tier at developer.edamam.com
Optional (free-tier or keyless):
- `USDA_FDC_API_KEY` — works without a key at low volume
- `EXERCISEDB_RAPIDAPI_KEY` — enables GIF links in exercise results
### 3. Test locally
```bash
pytest tests/ -v
```
### 4. Connect to Claude Desktop
Copy `config/claude_desktop_config.example.json` to your Claude Desktop config and update the path:
**macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json`
**Windows:** `%APPDATA%\Claude\claude_desktop_config.json`
```json
{
"mcpServers": {
"health-coach": {
"command": "python",
"args": ["/absolute/path/to/mcp-health-coach/server.py"],
"env": {
"EDAMAM_APP_ID": "your-id",
"EDAMAM_APP_KEY": "your-key"
}
}
}
}
```
Restart Claude Desktop. You should see the health-coach tools available.
### 5. Try a coaching session
Prompt example:
> "I'm a 32-year-old woman, 68kg, 170cm, moderately active. I want to lose weight. Help me build a meal and workout plan."
Claude will chain: `calculate_daily_needs` → `suggest_recipe` → `build_workout_plan` → `get_preventive_care_recommendations`.
## Project Structure
```
mcp-health-coach/
├── server.py # MCP entrypoint, tool registration (31 tools)
├── tools/
│ ├── nutrition.py # get_food_nutrition (USDA + OFF)
│ ├── recipes.py # suggest_recipe (Edamam)
│ ├── exercise.py # get_exercise (Wger + ExerciseDB)
│ ├── workout_plan.py # build_workout_plan (composition)
│ ├── daily_needs.py # calculate_daily_needs (pure logic)
│ ├── health_topics.py # get_health_topic_summary (MedlinePlus)
│ ├── supplement_interactions.py # check_supplement_interaction (openFDA)
│ ├── preventive_care.py # get_preventive_care_recommendations (ODPHP)
│ ├── body_metrics.py # BMI, body fat, water intake, weight range
│ ├── calorie_burn.py # calculate_calories_burned, list_activities
│ ├── meal_totals.py # get_meal_totals, compare_foods
│ ├── nutrient_search.py # find_foods_high_in_nutrient
│ ├── vitamin_info.py # get_vitamin_mineral_info
│ ├── research.py # search_nutrition_research (PubMed)
│ └── biometrics.py # wearable aggregation, recovery/strain/HRV, behavior journal
├── integrations/
│ ├── oura.py # Oura Ring API v2
│ ├── polar.py # Polar Accesslink API v3
│ ├── withings.py # Withings Health API
│ ├── fitbit.py # Fitbit Web API
│ ├── garmin.py # Garmin Connect (via garminconnect lib)
│ └── ble_gatt.py # Direct BLE Heart Rate Service (via bleak)
├── lib/
│ ├── cache.py # Shared TTL cache (1hr, 512 entries)
│ ├── http_client.py # Retry/timeout HTTP client
│ ├── normalization.py # Unified NutritionFact schema
│ ├── disclaimers.py # Structural disclaimer wrapper
│ └── safety_filters.py # Hardcoded emergency redirect
├── tests/
│ ├── test_daily_needs.py # BMR/TDEE formula correctness
│ ├── test_normalization.py # Cross-source schema consistency
│ ├── test_disclaimer_wrapper.py # Disclaimer always present
│ ├── test_safety_filters.py # Emergency patterns 100% blocked
│ ├── test_biometrics.py # Wearable aggregation, recovery/strain/HRV, journal
│ └── test_integrations.py # Per-device auth/parsing + degradation paths
├── config/
│ └── claude_desktop_config.example.json
├── demo/
│ └── run_example.py # Key-free walkthrough of the local-logic tool chain
├── .env.example
└── requirements.txt
```
## Data Sources
All free-tier. No paid infrastructure required to run locally.
| Source | What | Key required? |
|--------|------|---------------|
| USDA FoodData Central | Whole food nutrition | No (optional for higher rate limits) |
| Open Food Facts | Branded/packaged foods | No |
| Edamam | Recipes | Yes (free tier) |
| Wger | Exercise database | No |
| ExerciseDB | Exercise GIFs | Yes (free tier via RapidAPI) |
| MedlinePlus (NLM) | Health topic summaries | No |
| openFDA | Drug/supplement labels | No |
| ODPHP MyHealthfinder | Preventive care guidelines | No |
| PubMed | Nutrition research | No |
| Oura / Polar / Withings / Fitbit / Garmin | Wearable biometrics | Yes, per-platform (see [Wearable Integrations](#wearable-integrations)) |
| Direct BLE hardware | Live heart rate / HRV | No (local Bluetooth only) |
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues