Google Health Broker

Google Health Broker

Self-hosted multi-user Google Health OAuth broker and read-only Agent API with remote MCP support. Enables users to connect their Google account and grant agents secure access to activity, sleep, heart, HRV, SpO2, and other health metrics via revocable per-token authentication.

Category
Visit Server

README

Google Health Broker

Self-hosted, multi-user Google Health OAuth broker and read-only Agent API. Each person connects their own Google account and receives a separate, revocable gha_ Agent Token. Generic Agents can discover the API through OpenAPI; MCP clients with static-header support can use the optional remote MCP endpoint.

The broker runs locally on Node.js or on Cloudflare Workers with D1. It encrypts Google OAuth credentials at rest, stores only hashes of Agent Tokens, refreshes Google access automatically, and does not persist health API responses.

This project uses Google Health API v4, not the legacy Fitbit Web API. It is not a medical device and must not be used for diagnosis or emergencies.

What is included

  • Self-service Google OAuth for multiple users
  • Separate, revocable Agent Tokens instead of exposing Google refresh tokens
  • Fixed read-only routes for activity, steps, distance, floors, calories, active minutes, sleep, heart, HRV, SpO2, respiratory rate, VO2 max, temperature, profile, and devices
  • OpenAPI 3.1 and /.well-known/agent.json discovery
  • Sessionless remote MCP adapter with read-only tools
  • Local encrypted JSON storage or Cloudflare D1
  • Token rotation, Google revocation, per-token rate limits, no-store responses, and OAuth CSRF protection

Quick start: local Node.js

Requires Node.js 22 or later.

npm install
cp .env.example .env
npm run keygen

Put the generated key and your Google OAuth client values in .env, then run:

npm start

Open http://localhost:8787/connect. After authorization, save the connection bundle shown once. Never commit .env, data/, or an Agent Token.

Docker is also supported:

docker compose up --build -d

The bundled JSON store supports one service process. Use the D1 deployment for a hosted, concurrent service.

Configure Google Cloud

Follow Google's Google Health setup guide:

  1. Enable Google Health API.
  2. Configure the OAuth consent screen. While the app is in Testing, add each allowed account as a test user.
  3. Request the least-privilege scopes in .env.example.
  4. Create a Web application OAuth client.
  5. Add the exact redirect URI:
http://localhost:8787/oauth/google-health/callback

For production, use your public HTTPS origin. /v1/profile also requires the optional googlehealth.profile.readonly scope.

Google OAuth projects in Testing commonly issue refresh tokens that expire after seven days. Before offering a public service, move the app to Production and complete all verification or security assessment Google requires for your scopes and audience.

Deploy to Cloudflare Workers

The committed Worker configuration is a template. Your real wrangler.toml is ignored so account and database identifiers remain local.

cp wrangler.toml.example wrangler.toml
npx wrangler d1 create google-health-broker-db

Put the returned D1 database ID in wrangler.toml, then apply the schema:

npm run worker:migrate

Upload secrets interactively. Do not put their values in wrangler.toml, shell scripts, issues, or chat:

npx wrangler secret put GOOGLE_CLIENT_ID
npx wrangler secret put GOOGLE_CLIENT_SECRET
npx wrangler secret put TOKEN_ENCRYPTION_KEY

Deploy and verify:

npm test
npm run worker:deploy
curl -fsS https://YOUR-WORKER.workers.dev/healthz

Add this exact callback URL to the Google OAuth client:

https://YOUR-WORKER.workers.dev/oauth/google-health/callback

For production, configure CONTACT_EMAIL, operator-specific privacy/terms text, a custom domain, monitoring, backups, incident response, and the required Google verification.

Connect an Agent

The one-time connection bundle contains:

{
  "type": "google-health-connection",
  "service_url": "https://health.example.com",
  "discovery_url": "https://health.example.com/.well-known/agent.json",
  "openapi_url": "https://health.example.com/openapi.json",
  "mcp_url": "https://health.example.com/mcp",
  "authorization": "Bearer gha_REDACTED"
}

An HTTP-capable Agent should fetch openapi_url, then call only documented routes with the authorization header. Each person must authorize separately and keep their own token private.

Remote MCP

POST /mcp exposes the same read-only capabilities as MCP tools. Configure the complete Authorization: Bearer gha_... header in a client that supports static MCP headers.

This adapter is intentionally described as pre-provisioned Bearer mode: it does not implement MCP OAuth 2.1 discovery or an automatic browser login flow. See docs/MCP.md.

REST API

Every /v1/* request requires:

Authorization: Bearer gha_...

Read routes:

GET /v1/connection
GET /v1/profile
GET /v1/devices
GET /v1/activity?date=YYYY-MM-DD
GET /v1/steps?start=YYYY-MM-DD&end=YYYY-MM-DD
GET /v1/distance?start=YYYY-MM-DD&end=YYYY-MM-DD
GET /v1/floors?start=YYYY-MM-DD&end=YYYY-MM-DD
GET /v1/calories?start=YYYY-MM-DD&end=YYYY-MM-DD
GET /v1/active-minutes?start=YYYY-MM-DD&end=YYYY-MM-DD
GET /v1/heart?start=YYYY-MM-DD&end=YYYY-MM-DD
GET /v1/sleep?start=YYYY-MM-DD&end=YYYY-MM-DD
GET /v1/hrv?start=YYYY-MM-DD&end=YYYY-MM-DD
GET /v1/spo2?start=YYYY-MM-DD&end=YYYY-MM-DD
GET /v1/breathing?start=YYYY-MM-DD&end=YYYY-MM-DD
GET /v1/cardio?start=YYYY-MM-DD&end=YYYY-MM-DD
GET /v1/temperature?start=YYYY-MM-DD&end=YYYY-MM-DD

Dates are Google Health civil dates. The operator maximum is at most 90 days. Google limits total-calorie and active-minute daily rollups to 14 days. Empty data can mean the connected account, permission, or device did not supply that measurement.

Credential management remains REST-only and is intentionally omitted from Agent discovery documents:

POST   /v1/token/rotate
DELETE /v1/connection

Rotation invalidates the old Agent Token immediately. Deletion removes the stored connection and attempts to revoke Google authorization.

Security and privacy

  • Google access and refresh tokens use AES-256-GCM authenticated encryption.
  • Random Agent Tokens are stored only as SHA-256 lookup hashes.
  • OAuth state is signed, expires, and is bound to an HttpOnly SameSite cookie.
  • Agent routes and upstream Google Health data types are allowlisted.
  • MCP tools are read-only and reject mismatched browser Origin headers.
  • Responses use Cache-Control: no-store and are not persisted by this application.

Read SECURITY.md and docs/THREAT_MODEL.md before operating this for other people. Encryption at rest does not make the operator or Agent client untrusted; both can observe data while processing it.

Project documents

License

MIT

Recommended Servers

playwright-mcp

playwright-mcp

A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.

Official
Featured
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.

Official
Featured
Local
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.

Official
Featured
Local
TypeScript
VeyraX MCP

VeyraX MCP

Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.

Official
Featured
Local
graphlit-mcp-server

graphlit-mcp-server

The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.

Official
Featured
TypeScript
Kagi MCP Server

Kagi MCP Server

An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.

Official
Featured
Python
E2B

E2B

Using MCP to run code via e2b.

Official
Featured
Neon Database

Neon Database

MCP server for interacting with Neon Management API and databases

Official
Featured
Exa Search

Exa Search

A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.

Official
Featured
Qdrant Server

Qdrant Server

This repository is an example of how to create a MCP server for Qdrant, a vector search engine.

Official
Featured