apple-health-semantic-mcp
This MCP server lets you query and analyze your Apple Health export and optional CPAP therapy data using natural language and SQL, with a semantic layer to avoid common data traps.
Explore the schema (
health_schema): View all available health tables and metric metadata—meanings, valid aggregates, units, known pitfalls (like blood oxygen as fractions, sleep crossing midnight, duplicate sources)—always call before writing queries.Run SQL queries (
health_query): Execute read-only DuckDB SELECT statements against your health and optional CPAP tables (e.g., heart rate, sleep, workouts), returning up to 5,000 labeled rows; errors show actual columns.Generate health reports (
health_report): Get a summary of heart rate, HRV, sleep, SpO2, activity, workouts, and CPAP over flexible windows (e.g., last week, month, or explicit dates), with the exact window declared.Correlate CPAP therapy: If OSCAR CPAP data is imported, join nightly metrics (AHI, leak, pressure) with wearable data in queries.
Avoid data pitfalls: Semantic layer enforces correct aggregation (no averaging step counts), night grouping (
nightOffrom noon to noon), and deduplication, preventing silent errors.Convert health exports: Import your Apple Health ZIP or XML into an efficient, queryable local database.
Ensure privacy: All processing is local; no data ever leaves your machine.
Integrate with LLM clients: Works over MCP and can be configured with Claude Desktop, VS Code, Copilot CLI, Codex, and more for natural language querying.
Provides tools for querying and analyzing Apple Health export data, including metrics like heart rate, sleep, blood oxygen, and workouts, with a semantic layer to avoid common data misinterpretations.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@apple-health-semantic-mcpWhat's my sleep been like over the last month, and is it trending?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
apple-health-semantic-mcp
Query your Apple Health export with an LLM, over the Model Context Protocol.
The hard part of this is not moving the data. It is that Apple Health data is
full of traps that produce confidently wrong answers: percentages stored as
fractions, sleep that changes date at midnight, three apps recording the same
steps, device names containing an invisible character that makes LIKE filters
match nothing. A model that reads the raw tables will answer fluently and
incorrectly, and you will have no way to tell.
So this server ships a semantic layer: for every metric it states what the value means, which aggregate function is valid, and what is known to go wrong — and injects that into the model's context before it writes any SQL.
It optionally imports CPAP therapy data, so a single query can correlate machine data with wearable data.
SELECT o.nightOf, o.ahi, ROUND(AVG(h.value), 1) AS sdnn_ms
FROM oscar_daily o
JOIN hkquantitytypeidentifierheartratevariabilitysdnn h USING (nightOf)
GROUP BY 1, 2 ORDER BY 1;Quick start
git clone https://github.com/Barbaroso/apple-health-semantic-mcp
cd apple-health-semantic-mcp
npm installOn your iPhone: Health → your profile picture → Export All Health Data. Get
the resulting export.zip onto this machine — AirDrop, iCloud Drive, a cable,
whatever suits. Do not unzip it; point the tool at the archive as it is.
node bin/cli.js setup /path/to/export.zip --write-configThat one command reads the archive, converts it, imports CPAP data if it finds any, verifies the result, and registers the server with Claude Desktop (keeping a backup of your previous config, and leaving every other server alone). Restart the client and you are done.
For VS Code, Visual Studio, GitHub Copilot or Codex, add --client — see
Connecting a client.
Drop --write-config if you would rather paste the configuration yourself — it
gets printed either way, in that client's own format, with absolute paths already
filled in.
Reading straight from the archive is not just less typing. A real 83 MB
export.zip holding a 1.4 GB export.xml converts in 16 seconds, faster
than converting the extracted file, because the disk only has to deliver 83 MB.
It also saves you 1.4 GB. Memory stays flat regardless of export size: the XML is
streamed through a decompressor, never held.
export.xml and the extracted apple_health_export/ folder are accepted too, if
you have already unpacked one.
Restart the client and ask something. Good first questions:
"What's my sleep been like over the last month, and is it trending?"
"Show me nights where my blood oxygen dropped below 90%."
"Does my resting heart rate go up after short nights?"
setup is a wrapper. The individual commands remain, and are what you want when
re-converting a newer export into an existing directory:
node bin/cli.js convert --in /path/to/export.zip --out ~/health-data
node bin/cli.js sync-oscar --out ~/health-data # optional, CPAP
node bin/cli.js doctor --dir ~/health-dataThe configuration block, if you are writing it by hand, is in Connecting a client — one per client, since they disagree on the format.
Related MCP server: apple-health-mcp
Connecting a client
setup --write-config targets Claude Desktop unless told otherwise. Each client
below has been checked against a running server:
node bin/cli.js setup /path/to/export.zip --client vscode --write-config
| Application | Configuration file |
| Claude Desktop |
|
| VS Code (GitHub Copilot Chat) |
|
| Visual Studio |
|
| GitHub Copilot CLI and desktop app |
|
| Codex CLI and the ChatGPT desktop app |
|
Without --write-config the block is printed in that client's own format for you
to paste. Nothing is ever rewritten blind: the previous file is copied to a
timestamped sibling first, and every other server and unrelated setting is kept.
Three differences matter, because each one produces a client that starts cleanly and then lists no tools at all:
VS Code and Visual Studio read
servers, notmcpServers, and expect an explicit"type": "stdio".Codex uses TOML, as
[mcp_servers.<name>]with the environment in its own[mcp_servers.<name>.env]table. That file is edited by section rather than parsed and reserialised, so comments and hand-written ordering survive.The GitHub Copilot CLI reads its configuration when a session starts. A session that was already open when you added the server keeps its original list; start a new one.
Claude Desktop and the GitHub Copilot CLI:
{
"mcpServers": {
"apple-health": {
"command": "node",
"args": ["/absolute/path/to/apple-health-semantic-mcp/bin/cli.js", "serve"],
"env": { "HEALTH_DATA_DIR": "/absolute/path/to/health-data" }
}
}
}VS Code and Visual Studio:
{
"servers": {
"apple-health": {
"type": "stdio",
"command": "node",
"args": ["/absolute/path/to/apple-health-semantic-mcp/bin/cli.js", "serve"],
"env": { "HEALTH_DATA_DIR": "/absolute/path/to/health-data" }
}
}
}Codex:
[mcp_servers.apple-health]
command = "node"
args = ["/absolute/path/to/apple-health-semantic-mcp/bin/cli.js", "serve"]
[mcp_servers.apple-health.env]
HEALTH_DATA_DIR = "/absolute/path/to/health-data"On Windows, write the absolute path to node.exe rather than node, and escape
the backslashes (C:\\Program Files\\nodejs\\node.exe). setup does this for you.
Why a semantic layer
These are real defects in real exports, all of which produce a plausible wrong answer rather than an error.
Trap | What the data looks like | The wrong answer it produces |
Blood oxygen stored as a fraction |
| "your oxygen saturation is 0.95%" |
Heart rate is a discrete sample | 475,000 rows |
|
Step count is an interval total | one row per partial interval |
|
| both cover the same hours | "you slept 13 hours" |
Sleep crosses midnight | a session starts at 01:15 |
|
Several apps record the same metric | watch + phone + third-party app | step counts inflated by 80–90% |
| one row spanning 30 days, value | "a 30-day apnoeic episode" |
Source names contain U+00A0 |
|
|
The last one deserves emphasis, because it is invisible in every tool that displays it. Apple writes device and source names with a NO-BREAK SPACE. A query that looks correct returns zero rows, and the natural conclusion — "this device has no data" — is wrong. The converter normalises it. See docs/DATA-TRAPS.md for the full catalogue.
Tools
health_schema
Lists every table and returns the semantic layer: measurement class, correct aggregate function, units, observed value ranges, recording sources, date coverage, and per-metric caveats. Call this first. Everything else depends on the model having read it.
health_query
Read-only DuckDB SQL. Writes are rejected with an explanation, not a generic failure. Tables load on demand. Rows come back as labelled objects rather than positional arrays, because column misalignment is exactly the class of silent error this project exists to prevent.
If a query names a column that doesn't exist, the error lists the columns that do:
Binder Error: Referenced column "measurementClass" not found ...
Columns that actually exist -> hkquantitytypeidentifierheartrate: type,
sourceName, sourceVersion, unit, startDate, endDate, value, valueText, device,
productType, nightOf. Note that measurementClass, aggregation and caveats are
metadata returned by health_schema, not columns in any table.health_report
A summary across heart rate, resting heart rate, HRV, sleep, respiratory rate, blood oxygen, activity, workouts and CPAP therapy.
Every section declares how it was computed:
## Sleep [per night (noon to noon), source: Apple Watch]
Average 7.81 h across 14 nights (6.65-8.53)
! 2 sources recorded this metric. Restricted to 'Apple Watch' (14 days,
140 readings); combining them would count the same activity more than once.Three rules are enforced throughout, because breaking any of them yields a number that looks reasonable and is wrong:
Nocturnal metrics group by
nightOf, never by calendar day. Otherwise a night that crosses midnight is split in two and a fictitious short night drags the average down.Per-day and per-night values are computed first, then averaged. Averaging raw samples weights each day by how often the device happened to sample it.
Where several apps recorded the same metric, one source is used and the rest are named in
sourcesExcluded.
Choosing the window
Explicit dates take effect on their own — period does not have to be set to
custom, and one endpoint is enough:
{ "start_date": "2026-07-22", "end_date": "2026-07-30" } // exactly those 9 days
{ "start_date": "2026-07-22" } // that date to today
{ "period": "week", "end_date": "2026-06-15" } // the 7 days ending then
{ "period": "quarter" } // 90 days ending todayNamed periods are inclusive of both endpoints, so a week is seven days, and they are dated in local time rather than UTC — the same wall-clock the data uses.
Every reply reports the window it actually used, and why:
"period": {
"start": "2026-07-22", "end": "2026-07-30", "days": 9,
"basis": "the requested start_date and end_date, inclusive"
}That field exists because of a shipped defect: dates were honoured only when
period was custom, so a caller passing dates the obvious way silently got the
default window, correctly computed and confidently labelled. A report on the
wrong period is worse than an error — nothing about it looks wrong. An
unrecognised parameter is now refused rather than dropped, for the same reason.
Data model
One table per HealthKit type, named after the identifier in lower case
(HKQuantityTypeIdentifierHeartRate → hkquantitytypeidentifierheartrate).
Every table has exactly these columns:
Column | Type | Notes |
| VARCHAR | HealthKit identifier, or the activity for workouts |
| VARCHAR | App or device that wrote the record |
| VARCHAR | |
| VARCHAR | Check it before comparing or summing |
| TIMESTAMP | Local wall-clock time |
| TIMESTAMP | Local wall-clock time |
| DOUBLE | NULL for category types |
| VARCHAR | The label — use this for sleep stages |
| VARCHAR | |
| VARCHAR | Hardware model |
| DATE | The night this record belongs to |
nightOf
CAST(DATE_TRUNC('day', startDate - INTERVAL 12 HOUR) AS DATE)A night runs noon to noon and is labelled with the day it began. Sleep starting
at 23:40 on the 22nd and sleep starting at 01:10 on the 23rd both belong to
nightOf = 2024-01-22.
Measured on a real six-year export: 87% of asleep records are assigned to the
wrong night by DATE(startDate). This is not an edge case.
Timestamps are local wall-clock time. The CSV keeps the original UTC offset and the loader truncates it at load, so "last night" means what the wearer would mean by it, in whatever timezone they were in.
CPAP correlation (optional)
If you use a CPAP or BiPAP machine and review your therapy in OSCAR, you can pull the nightly summaries into the same database:
node bin/cli.js sync-oscar --out ~/health-dataThis reads the oscar.db that OSCAR 2.x writes in its own data folder — there is
no export step, and OSCAR can stay open. The database is copied together with its
write-ahead log before being read, so nothing is locked. OSCAR 1.x used a
different on-disk layout and is not supported.
This adds an oscar_daily table: one row per night, with AHI, RDI, event counts
by class, pressure and leak statistics, usage hours and compliance.
The join needs no date adjustment — OSCAR and this pipeline both define a night
as noon-to-noon, so nightOf matches directly.
SELECT o.nightOf,
o.ahi,
o.leakTotal95th,
ROUND(MIN(s.value), 1) AS lowest_spo2
FROM oscar_daily o
JOIN hkquantitytypeidentifieroxygensaturation s USING (nightOf)
WHERE o.maskOnHours >= 4
GROUP BY 1, 2, 3
ORDER BY o.ahi DESC;Two things worth knowing:
OSCAR stores "not recorded" as
0for SpO2 and pulse. If no oximeter was attached, every value is a placeholder. The importer exports these as NULL so the model cannot report a saturation of 0%.Apple's "breathing disturbances" metric is not an AHI and the two are not comparable. It is a relative index from a wrist accelerometer; AHI is a count of scored respiratory events per hour from a flow sensor.
This bridge is deliberately narrow: one row per night, enough to correlate therapy with wearable data in a single SQL statement. To interrogate CPAP data on its own — session detail, event clustering through the night, pressure and setting changes — use oscar-mcp, a separate read-only MCP server for exactly that. The two run side by side.
More examples in examples/queries.md.
Configuration
Variable | Default | Purpose |
| (required) | Directory produced by |
|
| DuckDB memory ceiling, MB |
|
| Load only the last N days. |
|
| Hour separating one night from the next |
| auto-discovered | Folder containing |
CLI
apple-health-semantic-mcp setup <export.zip|export.xml|dir> [--out <dir>]
[--client <name>] [--write-config] [--config <path>]
[--memory <mb>] [--no-oscar] [--limit n]
apple-health-semantic-mcp convert --in <export.zip|export.xml|dir> --out <dir> [--limit n] [--dry]
apple-health-semantic-mcp sync-oscar --out <dir> [--db <oscar.db>] [--dry]
apple-health-semantic-mcp doctor [--dir <dir>]
apple-health-semantic-mcp servesetup is the whole pipeline in one call and is what a first install should use.
--client picks which application to configure (claude, vscode,
visual-studio, copilot-cli, codex — see
Connecting a client); --config overrides the file it
would otherwise find for that client. --write-config merges the server in,
keeping a timestamped backup and every other server you have; without it the
block is printed for you to paste. A configuration file that cannot be parsed is
refused rather than overwritten.
doctor is the one to run when something looks wrong. It validates the data
directory, loads a table, and checks for un-normalised non-breaking spaces.
Privacy
Everything runs locally. The server reads files on your disk and speaks MCP over stdio; it opens no network connection and sends nothing anywhere. Your data goes to whichever model you have connected, and nowhere else.
.gitignore excludes *.csv, export.xml, semantics.json and *.db, so
health data cannot be committed by accident. The test suite generates its own
synthetic data — there is no real health data in this repository, and none should
ever be added.
This is not a medical device. Consumer wearable data supports trend and correlation analysis, not diagnosis. Wrist reflectance oximetry in particular is not comparable to a pulse oximeter, and Apple's own documentation says so. Take clinical decisions with a clinician.
Development
npm test75 end-to-end tests. They generate a synthetic export containing every trap listed above, pack it into real ZIP archives (including a ZIP64 one, which is what a multi-gigabyte export produces), convert it, build a synthetic CPAP database, and drive the real server over stdio. Nothing is mocked, so a failure means a client would see the same failure.
test/period.test.js is deliberately exhaustive about report windows. That is
where the worst defect in this project's history lived, and it survived a green
suite because every test had pinned period: 'custom' — encoding the
implementation rather than the requirement. Tests should ask for things the way a
caller would.
Requires Node 22.5 or newer (for the built-in node:sqlite).
bin/cli.js setup | convert | sync-oscar | doctor | serve
src/ontology.js the semantic layer: every metric's meaning, aggregation, caveats
src/convert.js streaming export.xml -> CSV + semantics.json
src/zip.js streaming reader for the archive the phone produces
src/setup.js one-shot install: convert, verify, configure the client
src/oscar.js CPAP bridge
src/doctor.js data directory health checks
src/db.js DuckDB storage, catalogue, on-demand loading
src/tools.js the three MCP tools
src/server.js stdio wiringThe ontology is where contributions are most valuable. If Apple adds a metric, or
you find a trap that isn't documented, add it to src/ontology.js and the model
will be told about it everywhere.
Related
oscar-mcp — a read-only MCP server for
CPAP therapy data, reading OSCAR's own oscar.db directly. Where this project
pulls one summary row per night for correlation, that one exposes the therapy
data properly: per-session detail, when events clustered during the night,
pressure and setting changes. The two run side by side, and an assistant with
both can reason across them.
Acknowledgements
The idea of exposing an Apple Health export over MCP comes from @neiltron/apple-health-mcp. This is an independent implementation; several bugs found along the way were reported back upstream.
License
MIT
Available Tools
3 toolshealth_queryA
Run a read-only DuckDB SQL query against the health tables. Call health_schema first so you know the columns and the correct aggregate function for each metric.
| Name | Required | Description | Default |
|---|---|---|---|
| limit | No | Maximum rows to return (default 1000, maximum 5000). | |
| query | Yes | A single SELECT or WITH statement. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations provided, the description carries full responsibility for behavioral disclosure. It adds the critical read-only guarantee and hints at needing the schema, but it omits details like error handling, result formatting, or any potential side effects. This is adequate but not rich.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two concise sentences with the core purpose front-loaded in the first sentence and a useful prerequisite in the second. Every word earns its place, with no redundancy or filler.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a tool with two parameters and no output schema, the description is adequately complete. It tells the user the essential prerequisite (call health_schema first) and the read-only nature. It could be more explicit about when to use this instead of health_report, but that is a minor gap given the clarity of the query intent.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
The input schema already documents both parameters (query as a single SELECT/WITH statement, limit with max rows) with 100% coverage. The description adds no additional parameter-specific semantics, so it neither compensates for nor improves upon the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool runs a read-only DuckDB SQL query against health tables, identifying the verb, resource, and scope. It is distinguishable from siblings by emphasizing arbitrary SQL queries, though it does not explicitly name alternatives or contrast with health_report or health_schema.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
Provides clear context: use for read-only SQL queries on health data, and explicitly instructs to call health_schema first as a prerequisite. It does not specify when not to use or mention alternative tools, but the guidance is actionable and sufficient for most cases.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
health_reportA
Generate a summary across heart rate, sleep, activity, blood oxygen, workouts and CPAP therapy for a period. The window is either a named relative period or explicit dates; the reply states which window was used and why, so check period.start and period.end against what you asked for. Use health_query for anything more specific.
| Name | Required | Description | Default |
|---|---|---|---|
| period | No | Relative window ending today, inclusive of both endpoints: week = 7 days, month = 30, quarter = 90, year = 365. Ignored when start_date and end_date are both given. Defaults to month. | |
| end_date | No | YYYY-MM-DD, inclusive. Takes effect on its own; period does not need to be set to custom. Given without start_date, the window is the named period's length ending on this date. | |
| start_date | No | YYYY-MM-DD. Takes effect on its own; period does not need to be set to custom. Given without end_date, the window runs from this date to today. |
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses a key behavioral trait: the reply states which window was used and why, prompting verification against the requested range. It also clarifies window semantics (inclusive endpoints, relative length), though detailed parameter logic is covered in the schema. It does not mention permissions, rate limits, or error handling, but for a read-only summary tool this is reasonable.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
The description is compact (two sentences) and front-loaded with the core purpose. Every sentence earns its place: the first identifies the tool's function and scope, the second explains window behavior and directs to the alternative tool. No fluff or repetition of schema details.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
Given the moderate complexity (3 optional attributes, full schema documentation, no output schema), the description is complete enough. It states what the tool does, how the window works, what to verify in the response, and when to use a sibling tool. It conveys essential information for correct selection and invocation without needing to list return fields explicitly.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
Schema description coverage is 100%, so the schema already documents all parameters thoroughly. The description adds only minimal extra meaning by framing the window as 'named relative period or explicit dates' and noting that the reply includes the window actually used. This is useful context but does not significantly enhance the parameter semantics beyond the schema.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly states the tool generates a summary across multiple health metric domains (heart rate, sleep, activity, blood oxygen, workouts, CPAP therapy), identifying a specific verb and resource. It distinguishes itself from sibling health_query by scope, noting it handles broad summaries while health_query is for anything more specific.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The description explicitly names health_query as the alternative for more specific needs, providing a clear when-to-use boundary. It also explains the window selection logic (named relative period or explicit dates) and instructs the agent to verify period.start and period.end in the reply, giving actionable guidance.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
health_schemaA
List every available health table and return the curated semantic layer: what each metric measures, which aggregate function is valid for it, and the known traps in the data. Call this before writing any query.
| Name | Required | Description | Default |
|---|---|---|---|
No parameters | |||
TDQS
Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?
With no annotations, the description carries the full burden. It discloses the tool's informational nature and enumerates what it returns (tables, semantic layer, metrics, aggregations, traps). It could be more transparent about potential access limitations or output size, but the core behavior is clearly conveyed.
Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.
Is the description appropriately sized, front-loaded, and free of redundancy?
Two sentences, with the main action front-loaded in the first sentence and a clear directive in the second. No redundant words or filler; every clause earns its place.
Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.
Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?
For a zero-parameter metadata listing tool, the description fully covers what it does, what it returns, and when to use it. The lack of output schema is not an issue because the description itself enumerates the semantic content, and the sibling tools are clearly distinct.
Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.
Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?
There are zero parameters, and the schema description coverage is 100% (trivially). The description adds contextual meaning about the tool's purpose and return value, satisfying the baseline for parameter-less tools.
Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.
Does the description clearly state what the tool does and how it differs from similar tools?
The description clearly identifies the tool as listing every health table and returning a curated semantic layer, including metric definitions, valid aggregate functions, and known data traps. This specific verb-resource pairing distinguishes it from the sibling tools health_report and health_query.
Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.
Does the description explain when to use this tool, when not to, or what alternatives exist?
The explicit instruction 'Call this before writing any query' provides clear when-to-use guidance, implying it is a prerequisite for data querying and reporting. This effectively differentiates it from health_query and health_report, which are for actual data retrieval.
Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
3 tool updates
v1.0.0- First observed
health_query - First observed
health_report - First observed
health_schema
TDQS
Scored across 3 tools
Each tool has a distinct role: health_schema provides metadata, health_query executes arbitrary SQL, and health_report generates a curated summary. The cross-references between them clarify when to use which, leaving no ambiguity.
All tools follow the consistent health_<noun> pattern: health_schema, health_query, health_report. This uniform convention makes the toolset predictable and easy to navigate.
With only three tools, the set is tightly scoped for a semantic layer: schema discovery, query execution, and report generation. Each tool is essential and the count is appropriate for the purpose.
The domain is read-only exploration of Apple Health data, and the three tools cover the full workflow: understanding the schema, running specific queries, and generating high-level summaries. There are no obvious gaps or dead ends.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
- SomviaOAuthapp.somvia
Private Apple Health metrics and workout detail for ChatGPT, Claude, and any MCP client.
- freddyOAuthcoach.freddy
Connect your wearables, rings and training apps, then ask your AI about your own health data.
Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.
Track, curate, and analyze data about your health, habits, and goals.
Related MCP Servers
- AlicenseBqualityCmaintenanceEnables users to query Apple Health metrics, workouts, and trends from CSV files exported via the Health Auto Export app. It allows MCP clients to analyze health data such as heart rate, sleep stages, and activity levels directly from local iCloud Drive storage.3211MIT
- AlicenseNot gradedqualityCmaintenanceLoads Apple Health export data into a local SQLite database and exposes tools to query health metrics and workout records via natural language.3MIT
- FlicenseBqualityDmaintenanceEnables Claude to answer natural language questions about your Apple Health data by analyzing local CSV exports, supporting metrics like steps, heart rate, sleep, and more.62-
- AlicenseAqualityAmaintenanceAn MCP server that enables AI agents to query Apple Health data (190+ metrics) in natural language, including trends, comparisons, and structured exports.141963MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Barbaroso/apple-health-semantic-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server