google-health-mcp
# Google Health Daily Pulse
A self-hosted health service for Google Health API v4. It synchronizes Fitbit,
Pixel Watch, and compatible health data, preserves timestamped records locally,
calculates reproducible 7-day and 28-day comparisons, and exposes both summaries and
full-fidelity data to Hermes Agent through a read-only MCP server.
You can do anything you want with this repo. **Codex was used to code it.** Use at your own risk.
For Mac users, there should not be much of a difference. I will test it on a Mac later
and update the repository if there are any issues.
## Architecture
```text
Google Health API
→ OAuth 2.0 + encrypted tokens
→ FastAPI / healthctl
→ SQLCipher-encrypted database + encrypted sensitive payloads
→ deterministic baselines
→ local read-only MCP server
→ Hermes (optional)
→ Discord
```
The health core works without Hermes. If Hermes, the subscription, or a rate limit is
unavailable, the service can produce a deterministic English template message.
## Quick start
Requirement: Python 3.11 or newer.
```powershell
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -e ".[dev]"
Copy-Item .env.example .env
healthctl seed-demo
healthctl daily-pulse --no-hermes
```
Alternatively, `healthctl setup` creates `.env` interactively without displaying the
client secret. OAuth client credentials are stored in `data/credentials.enc`, not
`.env`.
Existing installations should run this once after upgrading:
```powershell
healthctl migrate-security
```
This converts an existing plaintext SQLite database to SQLCipher, moves Google OAuth
client credentials out of `.env`, protects the master key with Windows DPAPI, and
restricts local file permissions.
For real data:
1. [Configure Google Cloud](docs/google-cloud-setup.md).
2. Run `healthctl serve`.
3. In a second terminal, run `healthctl authorize`.
4. Run `healthctl sync`.
5. Run `healthctl daily-pulse --no-hermes`.
See [docs/windows-setup.md](docs/windows-setup.md) for the complete Windows, Hermes,
Codex, Discord, MCP, and scheduler setup.
## What needs to stay running?
`healthctl serve` and the MCP server are separate:
- `healthctl serve` starts the local FastAPI service on `127.0.0.1:8765`. It is needed
for the Google OAuth callback and only if you want to use the REST endpoints.
- The local MCP server uses stdio. Hermes starts `google-health-mcp` automatically when
it loads the configured `google-health` MCP connection.
- You do not need to keep `healthctl serve` running for MCP access, synchronization
through the CLI, or daily-pulse generation.
- To use health tools from Discord continuously, the Hermes gateway must be running.
- To refresh the local database, run `healthctl sync` manually or schedule
`healthctl run-daily`.
## REST API
The service binds only to `127.0.0.1:8765` by default.
```powershell
healthctl serve
```
| Method | Path | Purpose |
|---|---|---|
| `GET` | `/healthz` | Configuration and sync status without secrets |
| `GET` | `/oauth/google/start` | Start Google OAuth |
| `GET` | `/oauth/google/callback` | Receive the OAuth callback |
| `DELETE` | `/oauth/google` | Revoke Google access |
| `POST` | `/v1/sync` | Synchronize a date range |
| `POST` | `/v1/daily-pulse` | Generate facts and a message |
Examples:
```powershell
Invoke-RestMethod -Method Post `
-Uri http://localhost:8765/v1/sync `
-ContentType application/json `
-Body '{"start_date":"2026-05-15","end_date":"2026-06-20"}'
Invoke-RestMethod -Method Post `
-Uri http://localhost:8765/v1/daily-pulse `
-ContentType application/json `
-Body '{"use_hermes":true,"send":false}'
```
Uvicorn access logs are disabled by the CLI server so OAuth codes do not appear in
query-string logs.
## Data model
The database stores two complementary layers.
Normalized daily values:
- Sleep duration, sleep period, awake time, awakenings, and efficiency
- Light, deep, and REM sleep when available
- Steps
- Light, moderate, and vigorous activity minutes
- Exercise count, duration, and types
- Daily resting heart rate
- Daily HRV/RMSSD
Full-fidelity records preserve the complete structured Google payload and timestamps
for every supported stream under the configured activity, health-metrics, and sleep
scopes. This includes:
- Complete sleep sessions, stage segments, and out-of-bed segments
- Intraday heart rate, HRV, oxygen saturation, and respiratory measurements
- Heart-rate zones, activity intervals, sedentary periods, and exercise details
- Energy, distance, floors, VO2 max, body measurements, and temperature records
- Daily rollups for total calories and calories in heart-rate zones
The complete SQLite database, including normalized metrics, timestamps, indexes,
OAuth states, and tokens, is encrypted with SQLCipher. Sensitive payloads and OAuth
tokens retain an additional Fernet encryption layer. Google OAuth client credentials
are stored in an encrypted credential file rather than `.env`.
On Windows, the local master key at `data/token.key` is wrapped with DPAPI for the
current Windows account. The data directory, database, key, credential store, and
`.env` use ACLs restricted to that account and SYSTEM. Secrets must be decrypted in
application memory while in use; no application can protect them from malware already
running as the same signed-in user.
The default daily sync uses 35 days for compact baseline metrics and two recent days
for full-resolution records. This avoids re-downloading hundreds of thousands of
one-second heart-rate samples every morning. Detailed records accumulate locally as
the scheduled sync advances. Configure `HEALTH_DETAILED_SYNC_LOOKBACK_DAYS` from 1 to
90 for a larger initial backfill.
## CLI
```text
healthctl setup
healthctl migrate-security
healthctl serve
healthctl authorize
healthctl sync
healthctl facts [--date YYYY-MM-DD]
healthctl daily-pulse [--send] [--no-hermes]
healthctl run-daily [--send]
healthctl seed-demo
healthctl doctor
```
## Local MCP server
The project includes a read-only stdio MCP server for Hermes and other local MCP
clients:
```powershell
google-health-mcp --project-dir C:\path\to\Google-Health
```
It exposes:
- Calculated daily facts and 7-day/28-day baselines
- The deterministic English daily pulse
- Selected normalized history for up to 90 days
- A catalog of all detailed data types and their local coverage
- Full-fidelity records for a date range with bounded pagination
- Exact timestamp-window queries for calendar and workout correlation
- Authorization, sync, and local data-coverage status
It does not expose OAuth tokens, Google credentials, synchronization, revocation, or
database-write operations. Detailed health payloads are intentionally available to
the local agent, but each call is date bounded, limited to at most 500 records, and
pageable.
Hermes normally starts this executable automatically. You should not run it manually
unless you are testing an MCP client.
## Hermes skill
The repository includes [skills/google-health/SKILL.md](skills/google-health/SKILL.md).
It teaches Hermes how to choose the correct health tool, correlate exact windows with
calendar events, handle timezones and personal baselines, and use memory without
copying raw health data into it.
Install it into the active Hermes profile:
```powershell
$SkillsRoot = if (Test-Path "$env:LOCALAPPDATA\hermes\skills") {
"$env:LOCALAPPDATA\hermes\skills"
} else {
"$HOME\.hermes\skills"
}
$Target = Join-Path $SkillsRoot "personal\google-health"
New-Item -ItemType Directory -Force $Target | Out-Null
Copy-Item .\skills\google-health\SKILL.md $Target\SKILL.md -Force
```
Start a new Hermes session after installing or changing the skill.
## Security and product boundaries
- Never put secrets in issues, chat messages, or Git.
- Only read-only Google Health scopes are requested.
- The complete health database is encrypted at rest with SQLCipher.
- OAuth client credentials are encrypted outside `.env`; tokens are encrypted inside
the SQLCipher database with an additional Fernet layer.
- Hermes Discord access is restricted through `DISCORD_ALLOWED_USERS`.
- The FastAPI service binds to localhost by default and provides no public multi-user
authentication.
- Health guidance describes trends; it does not provide diagnoses or treatment.
- A centrally hosted service requires a different security architecture, privacy
review, Google OAuth verification, and recurring restricted-scope security review.
## Tests
```powershell
pytest
ruff check .
```
## Official references
- [Google Health API Setup](https://developers.google.com/health/setup)
- [Google Health API Scopes](https://developers.google.com/health/scopes)
- [Google Health API App Verification](https://developers.google.com/health/app-verification)
- [Google Health API REST v4](https://developers.google.com/health/reference/rest)
- [OpenAI Codex Authentication](https://developers.openai.com/codex/auth)
- [Hermes MCP](https://hermes-agent.nousresearch.com/docs/user-guide/features/mcp)
- [Hermes Discord Setup](https://hermes-agent.nousresearch.com/docs/user-guide/messaging/discord)
TDQS
Scored across 7 tools
Tools have distinct purposes but some overlap exists: get_daily_health_facts and get_daily_health_pulse both return daily summaries (one factual, one narrative), and get_health_history vs get_health_records both provide data at different granularities. Descriptions help differentiate, but minor ambiguity remains.
All tool names follow the verb_noun pattern with snake_case, consistently using 'get_' prefix. The naming is uniform and predictable (e.g., get_daily_health_facts, get_health_data_catalog).
With 7 tools, the set is well-scoped for a health data server. Each tool serves a distinct purpose (daily summary, history, records, catalog, status, time window) without unnecessary bloat or deficiency.
The tool set provides thorough read-only coverage: daily facts, narrative summaries, historical trends, full-fidelity records, time-window queries, and metadata. Missing write operations (create/update/delete) are reasonable if the server is query-only. Minor gaps like direct metric extraction are mitigated by history and records tools.