A remote MCP server that exposes your Apple Watch / Apple Health data to every Claude surface — claude.ai web, Claude Desktop, the Claude mobile app, and Claude Code — with near-fresh data.
Built in public. MIT licensed. Your health data and secrets never live in this repo — only code does.
Apple Watch → iPhone HealthKit
→ Health Auto Export (iOS app) POSTs to /api/ingest every ~hour
→ Neon Postgres
→ /api/mcp (remote MCP server, this repo)
→ Claude (web · desktop · mobile · Claude Code)
HealthKit is iOS-only, so the data is pushed from your iPhone by the Health Auto Export app. Local MCP servers can't reach claude.ai web/mobile, so this one is remote.
| Tool | What it does |
|---|---|
list_metrics |
Discover available metrics (units, counts, date ranges) |
query_metric |
Query a metric over a range (raw / hourly / daily / avg / sum / min / max) |
list_workouts |
Workouts in a range, optionally by type |
query_events |
ECG, State of Mind, symptoms, medications, cycle tracking, HR notifications |
latest_snapshot |
Most recent value for every metric |
health_sql |
Read-only SELECT over metric_samples, workouts, health_events |
- Database — provision Neon (Vercel Marketplace → Neon) and copy the connection string.
- Deploy — deploy this repo to Vercel. Set env vars:
DATABASE_URL— your Neon stringMCP_SECRET—openssl rand -hex 32
- Migrate —
DATABASE_URL=... npm run db:migrate. - iOS push — in Health Auto Export: Automations → REST API
- URL:
https://<your-app>.vercel.app/api/ingest - Header:
Authorization: Bearer <MCP_SECRET> - Format: JSON, all data types, schedule hourly.
- URL:
- Connect Claude — same URL everywhere:
https://<your-app>.vercel.app/api/mcp- Web / mobile / desktop (claude.ai): add a Custom Connector with that URL.
claude.ai requires OAuth, which this server implements: when prompted to sign
in, an Authorize page opens — enter your
MCP_SECRETas the access secret. That issues a 90-day token; no per-request URL secret. - Claude Code:
claude mcp add --transport http apple-health https://<your-app>.vercel.app/api/mcp --header "Authorization: Bearer <MCP_SECRET>"
- Web / mobile / desktop (claude.ai): add a Custom Connector with that URL.
claude.ai requires OAuth, which this server implements: when prompted to sign
in, an Authorize page opens — enter your
- Claude Code / ingest use the static
MCP_SECRETas a bearer (or?key=). - claude.ai web/mobile/desktop require OAuth, so the server ships a minimal,
stateless OAuth 2.1 layer (discovery, dynamic client registration, PKCE). The
/authorizestep is gated byMCP_SECRET(entered as a password), so only the secret-holder can mint a token. Codes and tokens are HMAC-signed — no DB, no deps.
- Treat
MCP_SECRETlike a password: it's the ingest bearer and the OAuth login. - For extra
health_sqlsafety, pointDATABASE_URLat a Postgres role granted onlySELECT, or keep a separate read-only role for production. - Custom Connectors require a paid Claude plan (Pro/Max/Team/Enterprise).
- iOS background limits make sync periodic (≈ hourly), not real-time.
- Data is a push from the phone; if the phone is offline, ingestion pauses.
npm install
npm test # Vitest (uses in-memory PGlite, no DB needed)
npm run dev