Google Health MCP

Google Health MCP — Google Health MCP for AI agents

Read user-authorized Google Health API v4 data — Fitbit, Pixel Watch and partners — locally via OAuth. Beta.
Local-first MCP server — tokens never leave your machine.

npm version GitHub release npm downloads CI License MIT Site

GitHub stars Built for MCP Verified release index Hermes one-command setup Google Health

> ⚡ **One-command install** with [Delx Wellness for Hermes](https://github.com/davidmosiah/delx-wellness-hermes): > `npx -y delx-wellness-hermes setup` — preconfigures this connector and the other 8 in a dedicated Hermes profile. > > Or wire it standalone into Claude Desktop / Cursor / ChatGPT Desktop — see the install section below. > **What's new in 0.7.3 (2026-08-03):** headless OAuth (`auth --manual`) for SSH / > containers / WSL · real-account rollup/filter fixes from external testers · > opt-in `clinical` scopes for ECG/IRN · pins live in Hermes/living-body. > Full notes in [CHANGELOG.md](CHANGELOG.md). ## Highest-leverage contribution — real-account coverage If you have Fitbit, Pixel Watch, Android health data or Google Health API v4 access, the most useful help is a redacted coverage report: ```bash npx -y google-health-mcp-unofficial coverage --live --json ``` Review the output, remove anything you do not want public, then post the report on [issue #2](https://github.com/davidmosiah/google-health-mcp/issues/2) (or a new issue). The timed proof loop on [#21](https://github.com/davidmosiah/google-health-mcp/issues/21) closed **1/2** — see [docs/proof-loop-status.md](docs/proof-loop-status.md). The command is read-only and is designed to omit OAuth secrets, local paths and raw health measurements. A static preflight is available before OAuth with `coverage --json`. ### Other ways to help (no account required) | Action | Link | | --- | --- | | Star if the project earned it | [stargazers](https://github.com/davidmosiah/google-health-mcp/stargazers) | | Docs GFI — headless auth walkthrough | [#22](https://github.com/davidmosiah/google-health-mcp/issues/22) | | Compose with other wearables | [`delx-living-body`](https://github.com/davidmosiah/delx-living-body) | | One-command Hermes pack | [`delx-wellness-hermes`](https://github.com/davidmosiah/delx-wellness-hermes) | | Full registry | [`delx-wellness`](https://github.com/davidmosiah/delx-wellness) | --- ## HTTP (v2 stateless) Default is **stdio**. Optional Streamable HTTP — no session id, JSON responses, loopback only: ```bash npx -y google-health-mcp-unofficial --http # GET http://127.0.0.1:3000/health # POST http://127.0.0.1:3000/mcp (sessionless) ``` Env: `GOOGLE_HEALTH_MCP_HOST`, `GOOGLE_HEALTH_MCP_PORT`, `GOOGLE_HEALTH_MCP_TRANSPORT=http`. # Google Health MCP **Local-first MCP server that gives your AI agent user-authorized Google Health API v4 data — Fitbit, Pixel Watch and partners — over OAuth.** - **Install one connector** — `npx -y google-health-mcp-unofficial setup` - **Run it in** Claude · Cursor · ChatGPT · Hermes · OpenClaw — see the [client examples](https://github.com/davidmosiah/delx-wellness/tree/main/examples). - **Local-first** — your tokens never leave your machine ([privacy](#privacy--what-runs-offline)). - **Which connector should I use?** — see the [front-door guide](https://github.com/davidmosiah/delx-wellness#which-connector-should-i-use). > **Beta status:** Google Health API v4 is live for builders but still evolving. Google's release notes show scope and data-type changes continuing after launch, so this connector stays in early beta and points testers to safe read-only validation paths before public production use. > **Unofficial project.** Not affiliated with, endorsed by or supported by Google, Fitbit or Alphabet. Not a medical device. Not medical advice. ## Why this exists Google Health API is the successor to Fitbit Web API: new OAuth, new base URL, v4 endpoint schema, standardized data types, reconciled streams and rollups. This MCP gives agents a clean way to discover the API, check setup, authenticate locally and query data without pasting tokens into prompts or agent configs. ## Quickstart in 60 seconds Create a Google Cloud OAuth client, enable the Google Health API, and add the redirect `http://127.0.0.1:3000/callback`. Then: ```bash npx -y google-health-mcp-unofficial setup --scope-preset full # writes local config npx -y google-health-mcp-unofficial auth # OAuth, tokens saved locally npx -y google-health-mcp-unofficial doctor # verifies you're ready ``` `doctor --live` calls safe Google Health identity/profile/settings endpoints after auth to prove the API is reachable — the connection proof for this beta. That does **not** prove Claude Desktop can invoke tools: Desktop validates `outputSchema` as JSON Schema 2020-12. Use `google-health-mcp-unofficial@0.7.6+` (see [#23](https://github.com/davidmosiah/google-health-mcp/issues/23)). Full install details (scope presets, MFA, recovery) are in the [Install section](#install) below. ## Try it with your agent Three things to ask first, based on tools this connector actually ships: ```text Use google_health_connection_status to check setup, then run google_health_data_inventory. Tell me which Google Health domains and scopes I have authorized. ``` ```text Call google_health_daily_summary for today, then google_health_weekly_summary. Separate observed data from suggestions and stay non-medical. ``` ```text Run google_health_privacy_audit, then summarize exactly what is stored locally and what would be sent to Google on the next call. ``` ## Tools Start here: - `google_health_connection_status` — local config, token, scope and client readiness - `google_health_data_inventory` — supported domains, scopes, data type naming and agent flow - `google_health_data_type_coverage` — static coverage plan, or explicit live read-only validation for issue #21 - `google_health_daily_summary` — daily beta summary from rollups and reconciled streams - `google_health_weekly_summary` — weekly beta review - `google_health_privacy_audit` — what is stored locally and what is sent to Google The full tool catalog — Google Health API methods, agent manifest, diagnostics and data-type naming notes (kebab-case endpoints, snake_case filters, source families) — lives in [docs/tools.md](docs/tools.md). ## Privacy & what runs offline - OAuth tokens are stored locally at `~/.google-health-mcp/tokens.json` with `0600` permissions. - Secrets can live in `~/.google-health-mcp/config.json` or `GOOGLE_HEALTH_*` environment variables. - Tools never return access tokens, refresh tokens or client secrets. - `GOOGLE_HEALTH_PRIVACY_MODE=structured` is the default; `raw` mode is explicit and should be used only for debugging or deep analysis. An agent asking for `privacy_mode=raw` is refused unless it passes `explicit_user_intent=true`; setting `GOOGLE_HEALTH_PRIVACY_MODE=raw` yourself is your own call and needs no per-call intent. - Structured mode preserves complete upstream physiological fields and future v4 additions while removing identity, location and secret-bearing values. - "Location redaction" means a concrete key list, not a slogan. Coordinate-bearing **leaf keys**, always dropped in `structured` and `summary` (matched ignoring case, `_` and `-`, so `latitude_e7` and `latitudeE7` are the same key): `startLatitude`, `startLongitude`, `start_latlng`, `endLatitude`, `endLongitude`, `end_latlng`, `latitude`, `longitude`, `lat`, `lon`, `lng`, `latlng`, `coordinates`, `coordinate`, `gps`, `gpx`, `geoPolylineDTO`, `map`, `polyline`, `summary_polyline`, `activities-tracker-gps`, `latitudeE7`, `longitudeE7`, `latE7`, `lngE7`, `lonE7`, `startLatitudeE7`, `startLongitudeE7`, `endLatitudeE7`, `endLongitudeE7`, `lat_deg`, `lng_deg`, `lon_deg`, `latitudeDegrees`, `longitudeDegrees` Location **container keys**, dropped as a whole object — with their `address`/`city`/`placeId` siblings and any coordinate spelling this list never anticipated — whenever they hold a place record (an object, or an array containing objects). A container holding only scalars is a label, not a place, and survives: `location: ["gym", "home"]` stays, `location: { latitudeE7: … }` does not. `location`, `locations`, `geoLocation`, `geoLocations`, `geo`, `geoJson`, `route`, `routes`, `position`, `positions`, `waypoint`, `waypoints`, `trackPoint`, `trackPoints`, `placeVisit` `google_health_privacy_audit` returns both live lists in `gps_redacted_keys` and `gps_redacted_container_keys`, and `gps_redaction_default` is measured at call time by pushing a synthetic record through both non-raw modes and scanning the output by key **and by coordinate value** — it is not a hardcoded `true`. `npm run test:redaction-docs` fails the build if these two blocks stop matching the code, so the published promise cannot drift from the enforcement list again. Google Health API v4 does not currently document a location/route data type, so this is a forward-compatible guard rather than a patch for an observed leak. - Limits of that promise, stated instead of implied. Every line below is proved by a behavioural test (`npm run test:declared-limits`) that fails if the behaviour changes; a line marked **NOT VERIFIED** is a statement no test backs, labelled instead of left to read as a guarantee. A limit written here without a test fails the build: - `default_mode_is_structured` — with no `privacy_mode` argument and no `GOOGLE_HEALTH_PRIVACY_MODE`, every read runs in `structured`. - `raw_requires_explicit_user_intent` — an agent asking for `privacy_mode=raw` is refused with `USER_ACTION_REQUIRED` unless it also passes `explicit_user_intent=true`. - `local_raw_default_needs_no_per_call_intent` — `GOOGLE_HEALTH_PRIVACY_MODE=raw` in your own config or environment is honoured on every call with no per-call intent; the gate is about agent escalation, not about the machine owner. - `raw_is_an_unfiltered_passthrough` — `raw` returns the upstream payload unchanged; redaction is a property of `structured` and `summary`, never of `raw`. - `structured_drops_identity_and_secret_keys` — tokens, `authorization`, e-mail, names and avatars are dropped at any depth in `structured`, while physiology and provenance survive. - `summary_is_never_less_restrictive_than_structured` — `summary` strips first and summarizes after, so nothing `structured` drops can reappear in `summary`. - `summary_flattens_numeric_leaves_to_depth_2` — `summary` promotes numeric leaves down to depth 2 of the data-type payload into `value`; anything deeper is not reported at all. - `summary_promotes_unlisted_coordinate_keys` — a coordinate key outside the lists above is promoted by `summary`, not hidden. The key list is the boundary, not the mode. - `altitude_and_elevation_are_not_location` — `altitude` is an official v4 data type (`activity_and_fitness`) and survives redaction, as does `elevation`; an altitude alone does not localize a user. - `altitude_inside_a_place_container_is_dropped` — the same altitude inside a redacted location container dies with the container. - `location_guard_never_observed_upstream` — NOT VERIFIED: Google Health API v4 documents no location/route data type, so no test here has ever seen a real Google payload carrying coordinates. The key list is a forward-compatible guard derived from Google's own encodings, not a measured fix for an observed leak. - Daily rollups use validated civil `YYYY-MM-DD` ranges; general rollups preserve exact timezone-aware ISO date-times. Invalid or reversed ranges fail before HTTP. - `support --redacted` prints a copy-paste support bundle for GitHub issues without tokens, secrets, local paths or health measurements. - `support --feedback --json` prints an anonymous setup-feedback bundle for beta testers and MCP client reports. - `coverage --live --json` prints only redacted data-type status and point-count buckets; it never includes raw Google Health payloads. ## Authorization model & trust boundary Google OAuth controls which Google account and health scopes this connector can access. It does **not** authorize individual MCP callers or tools. The intended deployment is one local user running one trusted MCP host; callers that can reach the same process share its tool catalog and local OAuth grant. There is currently no per-user, per-agent, API-key or per-tool RBAC layer. The optional HTTP transport binds to `127.0.0.1` by default and must not be exposed publicly without standards-compliant MCP authentication, isolated per-user Google credentials and an explicit authorization policy. See the full [authorization model](docs/authorization.md). ## See the full agent demo → Want to see an agent actually reason over this connector alongside the rest of the stack? The shared, reproducible demo answers the anchor question **"Should I train hard today?"**: ```bash npx -y delx-living-body demo ``` `delx-living-body` composes whatever connectors it detects locally with rule-based (offline) synthesis — readiness-first and non-medical. For this connector specifically, `npx -y google-health-mcp-unofficial doctor --live` is the local proof that your Google Health auth is wired correctly. ## Beta Testers Wanted The highest-leverage contribution right now is real setup feedback from Fitbit, Pixel Watch, Android and Google Health API v4 users. If you can test with a real account: - Run `npx -y google-health-mcp-unofficial doctor` and confirm the OAuth flow is clear. - Run `npx -y google-health-mcp-unofficial support --feedback --json` and paste the anonymous bundle into issue #4. - Run `npx -y google-health-mcp-unofficial coverage --json` for the static coverage plan. - After OAuth, run `npx -y google-health-mcp-unofficial coverage --live --json` and paste the reviewed, redacted report into [issue #2](https://github.com/davidmosiah/google-health-mcp/issues/2). - Try `google_health_connection_status`, `google_health_data_inventory` and `google_health_daily_summary` from your MCP client. - Open an issue for missing data types, confusing setup steps, client-specific friction or privacy concerns. - Do **not** paste OAuth tokens, client secrets, local paths or personal health measurements into public issues. Useful links: - [Beta testers wanted](https://github.com/davidmosiah/google-health-mcp/issues/2) - [Proof loop status (honest 1/2)](docs/proof-loop-status.md) - [Beta testers / new coverage](https://github.com/davidmosiah/google-health-mcp/issues/2) - [MCP client setup feedback](https://github.com/davidmosiah/google-health-mcp/issues/4) - [Beta feedback guide](docs/beta-feedback.md) - [Data coverage harness](docs/data-coverage.md) - [Anonymous setup feedback](docs/setup-feedback.md) - [Demo](docs/demo.md) - [Discovery kit](docs/discovery.md) ## Install Create a Google Cloud OAuth client, enable the Google Health API, and add the local redirect: ```text http://127.0.0.1:3000/callback ``` Then run: ```bash npx -y google-health-mcp-unofficial setup --scope-preset full npx -y google-health-mcp-unofficial auth npx -y google-health-mcp-unofficial doctor ``` ### Headless hosts (servers, SSH, containers, WSL) `auth` normally opens a browser and catches the redirect on `127.0.0.1`. On a host with no browser that cannot work. When it detects a headless host — SSH, or no `DISPLAY` / `WAYLAND_DISPLAY` — it switches to pasting the redirect back in: ```bash npx -y google-health-mcp-unofficial auth --manual ``` Non-interactive provisioning: ```bash npx -y google-health-mcp-unofficial auth --print-url npx -y google-health-mcp-unofficial auth --code "http://127.0.0.1:3000/callback?code=..." ``` See [docs/oauth.md](docs/oauth.md) for `--local-callback`, SSH tunnel notes, and `GOOGLE_HEALTH_HEADLESS`. Scope presets keep OAuth consent easier to reason about — `basic`, `activity`, `sleep` and `full`. The full preset list, the exact read-only scope URLs and the OAuth endpoints live in [docs/oauth.md](docs/oauth.md). If setup gets stuck: ```bash npx -y google-health-mcp-unofficial doctor --fix # repairs local config/token permissions (chmod 600 where supported) npx -y google-health-mcp-unofficial doctor --live # calls safe identity/profile/settings endpoints to prove the API is reachable npx -y google-health-mcp-unofficial coverage --live --json # redacted read-only data-type coverage for issue #21 npx -y google-health-mcp-unofficial support --redacted # copy-paste support bundle, no tokens/secrets/measurements npx -y google-health-mcp-unofficial support --feedback --json # anonymous setup feedback for issue #4 ``` Standalone MCP config: ```json { "mcpServers": { "google_health": { "command": "npx", "args": ["-y", "google-health-mcp-unofficial"] } } } ``` ## Hermes ```bash npx -y google-health-mcp-unofficial setup --client hermes --no-auth npx -y google-health-mcp-unofficial auth npx -y google-health-mcp-unofficial doctor --client hermes --fix npx -y google-health-mcp-unofficial doctor --client hermes --live hermes mcp test google_health ``` After config changes, use `/reload-mcp` or `hermes mcp test google_health`. Do not restart the gateway for normal data access. ## Development ```bash git clone https://github.com/davidmosiah/google-health-mcp.git cd google-health-mcp npm install npm test ``` ## Links - [Changelog](CHANGELOG.md) · [Contributing](CONTRIBUTING.md) · [Security](SECURITY.md) · [Authorization model](docs/authorization.md) - Google Health API: https://developers.google.com/health - Release notes: https://developers.google.com/health/release-notes - REST reference: https://developers.google.com/health/reference/rest - Scopes: https://developers.google.com/health/scopes - Data types: https://developers.google.com/health/data-types - Migration guide: https://developers.google.com/health/migration - Delx Wellness registry: https://github.com/davidmosiah/delx-wellness ## See also The full [Delx Wellness](https://wellness.delx.ai) connector library: | Provider | Package | Repo | |---|---|---| | WHOOP | [`whoop-mcp-unofficial`](https://www.npmjs.com/package/whoop-mcp-unofficial) | [whoop-mcp](https://github.com/davidmosiah/whoop-mcp) | | Oura | [`oura-mcp-unofficial`](https://www.npmjs.com/package/oura-mcp-unofficial) | [ouramcp](https://github.com/davidmosiah/ouramcp) | | Garmin | [`garmin-mcp-unofficial`](https://www.npmjs.com/package/garmin-mcp-unofficial) | [garmin-mcp](https://github.com/davidmosiah/garmin-mcp) | | Strava | [`strava-mcp-unofficial`](https://www.npmjs.com/package/strava-mcp-unofficial) | [strava-mcp](https://github.com/davidmosiah/strava-mcp) | | Fitbit | [`fitbit-mcp-unofficial`](https://www.npmjs.com/package/fitbit-mcp-unofficial) | [fitbitmcp](https://github.com/davidmosiah/fitbitmcp) | | Withings | [`withings-mcp-unofficial`](https://www.npmjs.com/package/withings-mcp-unofficial) | [withingsmcp](https://github.com/davidmosiah/withingsmcp) | | Apple Health | [`apple-health-mcp-unofficial`](https://www.npmjs.com/package/apple-health-mcp-unofficial) | [apple-health-mcp](https://github.com/davidmosiah/apple-health-mcp) | | Polar | [`polar-mcp-unofficial`](https://www.npmjs.com/package/polar-mcp-unofficial) | [polarmcp](https://github.com/davidmosiah/polarmcp) | | Nourish (nutrition) | [`wellness-nourish`](https://www.npmjs.com/package/wellness-nourish) | [wellness-nourish](https://github.com/davidmosiah/wellness-nourish) | **One-command setup for Hermes** — preconfigures every connector above plus wellness skills + onboarding: [`delx-wellness-hermes`](https://github.com/davidmosiah/delx-wellness-hermes). ## 📧 Contact & Support - 📨 **support@delx.ai** — general questions, integration help, partnerships - 🐛 **Bug reports / feature requests** — [GitHub Issues](https://github.com/davidmosiah/google-health-mcp/issues) - 🐦 **Updates** — [@delx369](https://x.com/delx369) on X - 🌐 **Site** — [wellness.delx.ai](https://wellness.delx.ai) ## License MIT - see [LICENSE](LICENSE). [Code of Conduct](CODE_OF_CONDUCT.md). > Agent-ready yardstick: [mcp-scorecard](https://github.com/davidmosiah/mcp-scorecard) — aim ≥90 on CI. ## Skill or MCP Same package, two doors. MCP registers tools on stdio/HTTP. The [skill](skill/SKILL.md) can drive the **same** tools through the CLI when the client has no MCP: ```bash npx -y google-health-mcp-unofficial call google_health_connection_status --json '{}' ``` Copy `skill/SKILL.md` into your agent skills dir.