MCP Server Reference

MCP Tools Reference

Once you install the iOS app and sync your HealthKit data, these are the 11 MCP tools your AI can call. The server is open source — clone the repo, drop in your Supabase credentials, and add one config block to your AI client.

Setup

Full verified checklist (~15 min): /setup. Detail: docs/SETUP.md. Also listed on the Glama MCP registry. An npx one-liner is not published yet — clone + Python is the supported path.

1
Clone the MCP server
git clone https://github.com/jefflitt1/health4ai
cd health4ai/mcp-server
pip install -r requirements.txt
2
Configure .env
cp .env.example .env
# DATABASE_URL + HEALTHKIT_USER_ID
3
Add to your AI client
{
  "mcpServers": {
    "health4ai": {
      "command": "python",
      "args": ["/path/to/health4ai/mcp-server/main.py"],
      "env": {
        "DATABASE_URL": "postgresql://...",
        "HEALTHKIT_USER_ID": "<your auth UID>"
      }
    }
  }
}

Works with Claude Desktop, Cursor, Continue, and any MCP-compatible client. See /setup.

11 Tools

get_health_summaryOverview · key metrics

get_health_summary(days: int = 7) → {period_days, steps, hrv_sdnn_ms, resting_heart_rate_bpm, sleep, workouts, data_as_of}

Overview of key metrics across a date range. Nested objects for steps/HRV/RHR; sleep and workouts stay raw-only.

Example prompt
"What's my health summary for the last 7 days?"
Return shape
{
  "period_days": 7,
  "steps": {"total": 59024, "daily_avg": 8432, "days_with_data": 7, "unit": "count"},
  "hrv_sdnn_ms": {"avg": 52.1, "latest": 54.2, "readings": 14},
  "resting_heart_rate_bpm": {"avg": 58.0, "latest": 57.0},
  "sleep": {"total_records": 42, "stage_records": 28},
  "workouts": {"count": 4, "types": ["Running", "TraditionalStrengthTraining"]},
  "data_as_of": "2026-09-16T23:00:00+00:00"
}
get_sleepSleep stages · per night

get_sleep(days: int = 7) → {period_days, avg_sleep_hours, nights: [{date, source, stages, total_minutes, segments}]}

Per-night sleep stage breakdown (core/deep/rem minutes). One source per night by priority.

Example prompt
"How was my sleep last week?"
Return shape
{
  "period_days": 7,
  "avg_sleep_hours": 7.5,
  "nights": [{
    "date": "2026-06-17",
    "source": "Apple Watch",
    "stages": {"core": 252.0, "deep": 66.0, "rem": 108.0},
    "total_minutes": 426.0,
    "segments": [{"stage": "deep", "duration_minutes": 22.0, "...": "..."}]
  }]
}
get_hrv_trendHRV · trend delta

get_hrv_trend(days: int = 30) → {avg_hrv_ms, latest_hrv_ms, trend_vs_prior_week, daily_averages}

Daily HRV (SDNN) averages with 7-day vs prior-week delta and direction.

Example prompt
"Is my HRV improving?"
Return shape
{
  "period_days": 30,
  "days_with_data": 28,
  "avg_hrv_ms": 52.1,
  "latest_hrv_ms": 54.2,
  "trend_vs_prior_week": {"delta_ms": 3.2, "direction": "improving"},
  "unit": "ms",
  "daily_averages": [
    {"date": "2026-06-17", "avg_hrv_ms": 54.2, "source": "raw"},
    {"date": "2026-06-16", "avg_hrv_ms": 49.8, "source": "raw"}
  ]
}
get_daily_snapshotAll metrics · single date

get_daily_snapshot(date: str = "") → {date, highlights, workouts, sleep_records, all_metrics, …}

Everything recorded for a specific date (YYYY-MM-DD). Defaults to today. Highlights fall back to daily summaries past 30 days.

Example prompt
"What does my health data look like for June 15?"
Return shape
{
  "date": "2026-06-15",
  "total_records": 186,
  "truncated": false,
  "metrics_present": ["HKQuantityTypeIdentifierStepCount", "..."],
  "highlights": {
    "steps": 9241,
    "active_energy_cal": 612,
    "resting_hr_bpm": 57,
    "hrv_sdnn_ms": 51.4,
    "weight_kg": 78.2
  },
  "highlights_source": "raw",
  "workouts": [{"type": "Running", "duration_minutes": 42.0, "calories": 487}],
  "sleep_records": 12,
  "all_metrics": {"HKQuantityTypeIdentifierStepCount": [{"value": 120, "unit": "count", "at": "..."}]}
}
get_workoutsWorkout log · type & intensity

get_workouts(days: int = 30, limit: int = 20) → {total_workouts, by_type, workouts: [{date, workout_type, duration_minutes, …}]}

Workout log with type, duration, distance, and calories.

Example prompt
"How many workouts did I do this month?"
Return shape
{
  "period_days": 30,
  "total_workouts": 12,
  "total_duration_hours": 8.4,
  "by_type": {"Running": 7, "TraditionalStrengthTraining": 5},
  "workouts": [{
    "date": "2026-06-17",
    "started_at": "2026-06-17T06:30:00+00:00",
    "workout_type": "Running",
    "duration_minutes": 42.0,
    "distance_km": 6.8,
    "calories_burned": 487,
    "source": "Apple Watch"
  }]
}
query_metricRaw time series · any HKQuantityType

query_metric(metric_type: str, days: int = 7, limit: int = 200) → {granularity, count, avg, samples|daily, …}

Time series for any HKQuantityType. ≤30 days returns raw samples; longer windows return daily aggregates. Empty results may include data_status.

Example prompt
"Show me my VO2 max readings for the last 90 days"
Return shape (raw, ≤30d)
{
  "metric_type": "HKQuantityTypeIdentifierVO2Max",
  "period_days": 7,
  "granularity": "raw",
  "count": 2,
  "avg": 48.3,
  "min": 47.9,
  "max": 48.7,
  "samples": [{
    "value": 48.3,
    "unit": "mL/kg·min",
    "started_at": "2026-06-17T07:14:22+00:00",
    "ended_at": null,
    "source": "Apple Watch",
    "metadata": null
  }]
}
get_long_term_trendMonthly aggregates · multi-year

get_long_term_trend(metric_type: str, months: int = 24) → {overall_avg, monthly_trend, daily_data, …}

Multi-year monthly aggregates. Merges recent raw with historical daily summaries so the trend has no recency gap.

Example prompt
"What's my HRV trend for the last 2 years?"
Return shape
{
  "metric_type": "HKQuantityTypeIdentifierHeartRateVariabilitySDNN",
  "months_requested": 24,
  "days_with_data": 612,
  "overall_avg": 51.8,
  "overall_min": 28.4,
  "overall_max": 78.1,
  "unit": "ms",
  "monthly_trend": [{
    "month": "2026-06",
    "avg": 51.8,
    "days_with_data": 17,
    "sources": ["raw", "summary"]
  }],
  "daily_data": [{"date": "2026-06-17", "avg": 54.2, "min": 48.1, "max": 61.0, "count": 3, "source": "raw"}]
}
get_coaching_briefStructured context · AI agents

get_coaching_brief() → {data_status, recovery, sleep, training_load_30d, activity_7d, fitness_markers}

Structured coaching context for AI agents. Includes freshness status — do not cite numbers when data_status is stale/none.

Example prompt
"Give me a training readiness brief"
Return shape
{
  "generated_at": "2026-09-16T23:00:00+00:00",
  "data_status": {"status": "fresh", "hours_since_newest_sample": 3.2, "guidance": "..."},
  "recovery": {
    "hrv_latest_ms": 54.2,
    "hrv_7d_avg_ms": 52.1,
    "hrv_trend": "stable",
    "hrv_delta_vs_prior_week_ms": 1.1,
    "resting_hr_latest_bpm": 57,
    "coaching_note": "Recovery stable"
  },
  "sleep": {"avg_hours_last_7_nights": 7.3, "nights_tracked": 7, "quality_flag": "borderline"},
  "training_load_30d": {"total_workouts": 12, "total_hours": 8.4, "weekly_avg_workouts": 2.8, "by_type": {"Running": 7}},
  "activity_7d": {"avg_daily_steps": 8432, "avg_active_energy_cal": 520},
  "fitness_markers": {"vo2max_latest": 48.3, "weight_kg_latest": 78.2}
}
search_recordsThreshold filtering · worst/best days

search_records(metric_type: str, days: int = 90, min_value: float | None = None, max_value: float | None = None, limit: int = 100) → {results: [{date, value, source}], filters, …}

Find days where a metric crossed a threshold. Cumulative metrics filter on daily total; rate metrics on daily average. Results sorted highest-to-lowest.

Example prompt
"What were my worst HRV days this year?" → max_value=40
Return shape
{
  "metric_type": "HKQuantityTypeIdentifierHeartRateVariabilitySDNN",
  "period_days": 90,
  "days_searched": 87,
  "days_matched": 2,
  "filters": {"min_value": null, "max_value": 40},
  "value_type": "daily_avg",
  "unit": "ms",
  "results": [
    {"date": "2026-03-12", "value": 28.4, "source": "raw"},
    {"date": "2026-01-08", "value": 31.2, "source": "summary"}
  ]
}
get_metric_statsPersonal baseline · percentiles

get_metric_stats(metric_type: str, days: int = 90) → {mean, std_dev, percentiles, thresholds, …}

Personal baseline and percentiles. thresholds.good_day_above = p75; poor_day_below = p25. Answers "is 42ms HRV good for me?"

Example prompt
"Is my HRV today above or below my normal range?"
Return shape
{
  "metric_type": "HKQuantityTypeIdentifierHeartRateVariabilitySDNN",
  "period_days": 90,
  "data_points": 84,
  "value_type": "daily_avg",
  "unit": "ms",
  "min": 28.4,
  "max": 78.1,
  "mean": 52.1,
  "std_dev": 9.3,
  "percentiles": {"p10": 38.2, "p25": 44.0, "p50": 51.4, "p75": 59.1, "p90": 67.8},
  "thresholds": {"good_day_above": 59.1, "poor_day_below": 44.0}
}
compare_periodsBefore/after · with verdict

compare_periods(metric_type: str, period_a_start: str, period_a_end: str, period_b_start: str, period_b_end: str, label_a: str = "Period A", label_b: str = "Period B") → {label_a, label_b, comparison}

Compare two YYYY-MM-DD ranges. Period objects are keyed by label_a / label_b. Answers "did my sleep improve after I started lifting?"

Example prompt
"Compare my sleep before and after I started taking magnesium"
Return shape
{
  "metric_type": "HKCategoryTypeIdentifierSleepAnalysis",
  "value_type": "daily_avg",
  "before": {
    "start": "2026-04-01", "end": "2026-04-14",
    "data_points": 14, "avg": 6.8, "min": 5.1, "max": 8.2, "unit": "min"
  },
  "after": {
    "start": "2026-04-15", "end": "2026-04-28",
    "data_points": 14, "avg": 7.4, "min": 6.0, "max": 8.5, "unit": "min"
  },
  "comparison": {
    "delta": 0.6,
    "pct_change": 8.8,
    "verdict": "after is higher than before"
  }
}

HKQuantityType Identifiers

Pass these strings as metric_type toquery_metric or get_long_term_trend.

IdentifierMetric
HKQuantityTypeIdentifierHeartRateVariabilitySDNNHRV
HKQuantityTypeIdentifierRestingHeartRateResting HR
HKQuantityTypeIdentifierVO2MaxVO2 max
HKQuantityTypeIdentifierStepCountSteps
HKQuantityTypeIdentifierActiveEnergyBurnedActive calories
HKQuantityTypeIdentifierBodyMassWeight
HKQuantityTypeIdentifierOxygenSaturationBlood oxygen
Early Access

Connect your Apple Health data to Claude

Invite-only TestFlight — join the waitlist and request a beta invite. No public TestFlight link.

Join the waitlist