Health apps show you charts of what they decided to show. SQL lets you ask the question you actually have — resting heart rate on the mornings after a late night, step count on days you logged a run — and DuckDB is fast enough to make that interactive. The design consequence to weigh is stated plainly in the README: every tool can reach the full configured history, so only start this from a client you would trust with all of it, and remember that query results travel to whichever model your client uses.
A local MCP server that loads Apple Health CSV exports into an in-memory DuckDB and lets an assistant query them with SQL. It makes no network requests and does not upload the export — though whatever a query returns does go to your client's model provider, which is the part worth thinking about.
- health_schema — table names, columns, units and sample rows; start here, because which tables exist depends on what your export contained
- health_query — a read-only SELECT, returned as JSON, CSV or a summary
- health_report — a weekly, monthly or custom summary rather than raw rows
- Export files become lowercase DuckDB tables — heart rate, step count, sleep analysis and workouts each land in their own table
- Every row carries sourceName for the device or app that recorded it, so you can tell apart two watches logging the same walk
- Quantity measurements sit in value with a unit; category measurements such as sleep stages keep their label in valueText
- The first query touching a table loads that table's whole history — there is no date window, so a question can reach as far back as the export goes
Node.js 22 or newer, and an export made with the Simple Health Export CSV app — Apple's own export.xml is not supported. Unzip it and point HEALTH_DATA_DIR at the directory; the server reads the files in place. MAX_MEMORY_MB caps DuckDB's memory and defaults to 2048, which the project says covers roughly a two-year multi-table export with headroom; nothing spills to disk, so an export that does not fit fails with an explicit error rather than degrading. CACHE_SIZE bounds how many query results are kept. The database is rebuilt on each launch, so every start reloads from CSV.
One command — npx -y @neiltron/apple-health-mcp
