This repo is the unofficial Google Health MCP connector for local agent workflows.
- Install:
npm ci - Typecheck:
npm run typecheck - Build:
npm run build - Fast smoke:
npm run smoke - HTTP smoke:
npm run smoke:http - Full gate:
npm test - Charts:
npm run charts -- [startYYYY-MM-DD] [endYYYY-MM-DD]→ writes~/.google-health-mcp/charts/health-charts.html(needs build + a saved token; no personal data is committed)
- Never commit OAuth client secrets, access tokens, refresh tokens, personal Google Health data, or local config.
- Keep read-only behavior and privacy-safe summaries as the default.
- Preserve agent-ready surfaces: manifest, connection status, privacy audit, CLI UX, Hermes agent manifest, and metadata checks.
- Keep error messages actionable without exposing credentials or raw private payloads.
- Analytics services live in
src/services/<name>.tsand export an asyncbuild<Name>(client, params)returning a plain object, paired with aformat<Name>Markdown(result). Pure derivation helpers stay inline in the module (seesummary.ts,sleep.ts). - Raw → clean parsing is isolated in a
*-normalize.tsservice (nutrition-normalize.ts,sleep-normalize.ts). v4 payloads are loosely typed; extract with defensive multi-candidate key lookups (pickNumber/pickString/findNestedNumber), never assume a single field name. - Output envelope for analytic results:
{ kind, generated_at, source: "google_health", window, beta: true, data_quality: {...}, <payload>, safety: { medical_advice: false, ... } }. Output JSON keys aresnake_case; internal TypeScript identifiers arecamelCase. - Resilience: wrap each upstream call so partial data never throws; surface a
data_quality.confidenceand what was missing. - Tools register in
src/tools/google-health-tools.tsviaserver.registerTool( "google_health_<x>", { title, description, inputSchema: Schema.shape, outputSchema, annotations: { readOnlyHint: true, destructiveHint: false, idempotentHint: true, openWorldHint: true } }, handler). Handlerstry { … return makeResponse(result, params.response_format, format…Markdown(result)); } catch { return makeError(…) }, take aresponse_format(json|markdown), and apply the privacy layer for raw passthrough. - Schemas are zod, defined in
src/schemas/common.ts. - Naming is neutral and descriptive (
daily_summary,sleep_minutes) — no editorializing adjectives in tool or field names. - Tests are
node:assertfixtures underscripts/*.mjs, import from../dist/..., use afakeClient, and signal failure with a non-zero exit (an uncaught assert orprocess.exit(1)).npm testauto-discovers and runs everyscripts/*.mjsviascripts/run-tests.mjs— dropping a new file in is all that's needed, nothing to wire by hand. Adding a tool also requires adding it to theexpectedToolslist inscripts/smoke-tools.mjs.