health-mcp
by AnshRajput
README.md
# any-health-mcp
Read-only access to your own health records, over the Model Context Protocol, so
Claude or any other MCP client can answer questions about them.
It reads **Android Health Connect** (or Apple HealthKit) rather than any vendor's
cloud. Those are the shared on-device stores that fitness apps write into, so one
integration reaches whatever your phone already holds — no per-vendor code here,
and none planned.
Runs two ways from one codebase: **locally**, reading your phone over USB and
storing nothing, or **self-hosted** on a Cloudflare Worker that keeps history.
---
## What is paid and what is not
Stated up front so you can judge the rest of this page.
- **This server is MIT-licensed and free.** Run it locally or deploy your own
copy without paying anyone. You may still pay your own infrastructure costs.
- **Cairn, the phone app, is a separate paid product** made by the same author.
It is free for one destination, manual sync and a 48-hour window; a one-time
purchase unlocks background sync, backfill and multiple destinations. **It is
not released yet.**
- **A managed hosted service is planned and charged separately.** It is **not
open to sign-ups today** — `/login` on the reference deployment returns 503.
**None of that is required to use this server.** It speaks a documented wire
format ([docs/CONTRACT.md](docs/CONTRACT.md)); anything that can POST JSON can
feed it, and the local path needs no app store and no account at all.
## Which path is yours
| | **Local** | **Self-hosted** | **Managed** |
|---|---|---|---|
| Where it runs | your Mac | your Cloudflare account | ours |
| Stores records | no | yes, in your D1 | yes, in ours |
| History | 30 days (the store's own limit) | as far back as you keep | as far back as you keep |
| Needs an account | no | a Cloudflare + Google account | sign-in |
| Phone must be | plugged in | anywhere | anywhere |
| Cost | free | free tier is usually enough | paid |
| Available now | **yes** | **yes** | **not yet** |
If you just want to try this, use **Local**. It is the only path with no signup,
no deploy and no cost, and it is the fastest way to find out whether your phone
actually holds the data you are hoping for.
## Status and limits
Honest about what has and has not been exercised, because this reads medical-grade
data and you should be able to judge it.
- **Verified end to end on real hardware** — a Galaxy Watch 6 Classic paired to a
Galaxy S24 Ultra, 14,855 real records over 30 days, through to answers in
Claude. That run used the third-party HC Webhook bridge.
- **Not yet verified with Cairn's own payload on a real device.** Cairn's record
shaping is covered by unit tests only. Treat it as unproven until this line
changes.
- **Only Samsung Health has been exercised as a source.** Fitbit, Garmin, Oura,
Whoop and others write to Health Connect and should work unchanged, but nobody
has confirmed it. What any vendor writes is that vendor's choice, and several
withhold their most interesting derived metrics — see
[docs/DATA.md](docs/DATA.md).
- **Aggregation happens in memory**, capped at 20,000 rows per tool call. A raw
month of continuous heart rate exceeds that and will be truncated, with the
limit reported in the result.
- Full list: **[docs/LIMITATIONS.md](docs/LIMITATIONS.md)**.
## Local: the five-minute path
You need Node 22+, a phone with Health Connect, and a bridge app on it that can
POST the documented payload or serve it over HTTP.
**1.** Make sure your fitness app is actually sharing with Health Connect. In
Samsung Health that is Settings → Health Connect; Fitbit, Garmin Connect and
Google Fit each have an equivalent. **This is the step people miss**, and it
leaves Health Connect empty while everything else looks fine.
**2.** Connect the phone over USB. In Developer options turn on *USB debugging*,
then map a port straight to it:
```bash
adb forward tcp:8787 tcp:8787
node bin/probe.ts http://localhost:8787
```
`probe.ts` prints what the bridge is serving and what this server makes of it.
Run it first whenever anything looks wrong.
**3.** Register it with your client:
```bash
claude mcp add health-local --env HEALTH_PHONE_URL=http://localhost:8787 \
-- node /path/to/any-health-mcp/src/local.ts
```
Set `HEALTH_TZ_OFFSET_MINUTES` if you are not on IST (default 330). It decides
where your local day begins, and getting it wrong silently misattributes sleep.
Then ask your agent: **"What does `get_sync_status` say?"** — it is the only tool
that answers usefully with no data, and it tells you what actually arrived.
No phone handy? `node bin/fake-phone.ts 8787` serves a plausible payload.
## Self-hosted: your own Worker
```bash
npx wrangler login
node cloud/setup.ts # bindings, schema, deploy — prints your URL
```
Then create a Google OAuth web client whose redirect URI is `<your URL>/auth/callback`,
run `node cloud/setup.ts --secrets`, and open the URL.
**The ordering is forced and is the usual stumble**: the Google client needs a
redirect URI, that URI contains your Worker's origin, and the origin does not
exist until the Worker has been deployed once. Deploy first, then create the
client. Full walkthrough in [docs/CLOUD.md](docs/CLOUD.md).
## The tools
All read-only. Identical on every path, because they take a row source and
nothing else.
| Tool | Answers |
|---|---|
| `get_sync_status` | where data came from, how fresh it is, what is held per type |
| `get_daily_summary` | one local day: steps, distance, energy, HR, sleep, workouts |
| `get_sleep` | sessions with per-stage durations |
| `get_workouts` | exercise sessions with type, duration, distance |
| `get_timeseries` | any of 29 numeric metrics, raw or bucketed |
| `query_records` | raw records of any type, for what the shaped tools miss |
Connecting this to Claude Code, Claude Desktop, Codex, Cursor, Gemini, VS Code or
Zed: **[docs/CLIENTS.md](docs/CLIENTS.md)**.
## Where your data goes
The question worth asking of any health tool, so here is the direct answer.
```
wearable --BT--> vendor's app --> Health Connect --> a bridge app on your phone
|
┌─────────────────────┴──────────────────┐
USB to your Mac HTTPS to a server
(nothing stored) (records stored)
└─────────────────────┬──────────────────┘
|
this MCP server
|
your AI client
```
- **Local mode stores nothing.** No database, no file. A tool call reaches
through to the phone, shapes an answer in memory and forgets it.
- **Self-hosted mode stores records, and has to** — Health Connect discards data
after 30 days, so keeping history means keeping records. What makes that safe
is not an absence of storage but *whose* storage: your Cloudflare account, your
database, deployed by you.
- **Records returned to an AI client go wherever that client sends them**, under
its own terms. The tools are the boundary; what your agent does with an answer
is between you and its provider.
- **Nothing here can write to your health store.** No write permission is ever
requested, on either platform. The worst a confused model can do is ask a bad
question.
Threat model, asset inventory and the known gaps: **[docs/SECURITY.md](docs/SECURITY.md)**.
## Feeding it
This server needs something on the phone to push data to it, because Health
Connect has no cloud API and nothing can read it remotely.
- **Write your own.** [docs/CONTRACT.md](docs/CONTRACT.md) is the authoritative
wire format and is a specification, not notes.
- **[HC Webhook](https://github.com/mcnaveen/health-connect-webhook)** — a
third-party open-source Android app. This is what the verification above used.
- **Cairn** — the author's own app for Android and iOS, paid, not yet released.
It is one option and never a requirement.
## Documentation
| Question | Doc |
|---|---|
| How does it fit together? | [ARCHITECTURE.md](docs/ARCHITECTURE.md) |
| What JSON goes on the wire? | [CONTRACT.md](docs/CONTRACT.md) |
| What can I actually get from my watch? | [DATA.md](docs/DATA.md) |
| Health Connect / HealthKit gotchas | [DOMAIN.md](docs/DOMAIN.md) |
| Running, deploying, troubleshooting | [OPERATIONS.md](docs/OPERATIONS.md) |
| Connecting any MCP client | [CLIENTS.md](docs/CLIENTS.md) |
| Is my data safe? | [SECURITY.md](docs/SECURITY.md) |
| What doesn't work yet? | [LIMITATIONS.md](docs/LIMITATIONS.md) |
## Contributing and security
Issues and pull requests are welcome, particularly **confirmed reports of what a
given wearable does or does not write into Health Connect** — that is the most
useful thing anyone can add, and the hardest for one person to gather.
Found a security problem? Please open a private security advisory on this
repository rather than a public issue.
MIT licensed. Built by [Ansh Singh Rajput](https://anshgandharva.in).
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues