Google Health MCP — Remote
by Shreyamkmr
README.md
# Google Health MCP — Remote
**Connect Claude (or any MCP client) to your Fitbit / Pixel Watch data from anywhere.**
A remote, multi-user [Model Context Protocol](https://modelcontextprotocol.io) server for the
[Google Health API v4](https://developers.google.com/health), with built-in OAuth 2.0 sign-in,
ready to deploy to Google Cloud Run — and tuned to run inside the free tier.
[](https://github.com/Shreyamkmr/google-health-mcp-remote/actions/workflows/ci.yml)
[](https://github.com/Shreyamkmr/google-health-mcp-remote/releases/latest)
[](LICENSE)
> Fork of [davidmosiah/google-health-mcp](https://github.com/davidmosiah/google-health-mcp)
> (`google-health-mcp-unofficial`), which runs locally over stdio. This fork adds a remote
> transport so the server can live on the internet and be used from Claude on the web,
> desktop and mobile. Unofficial — not affiliated with Google or Fitbit.
---
## What you get
- **Paste one URL into Claude** — `https://<your-service>.run.app/mcp`. Claude discovers the
login itself, sends you to Google's consent screen, and you're connected.
- **Your data, your server** — it runs in *your* Google Cloud project with *your* OAuth client.
Nothing goes through a third party.
- **Stateless and free to idle** — no database; tokens are encrypted blobs only the server can
open. Scales to zero, so a personal setup typically costs £0/month.
- **Read-only by default** — sleep, steps, distance, heart rate, HRV, Active Zone Minutes,
workouts, weight, nutrition and more, plus daily/weekly summaries.
- **Locked down** — only the Google accounts you allow (`MCP_ALLOWED_EMAILS`) can sign in.
## How it works
```mermaid
sequenceDiagram
participant C as Claude (MCP client)
participant S as This server (Cloud Run)
participant G as Google sign-in
participant H as Google Health API
C->>S: POST /mcp (no token)
S-->>C: 401 + where to log in
C->>S: /register, /authorize
S->>G: redirect to consent (your OAuth client)
G-->>S: /oauth/callback with code
S-->>C: code → /token → encrypted access + refresh tokens
C->>S: POST /mcp (Bearer token)
S->>H: request with *your* Google token
H-->>S: health data
S-->>C: tool result
```
The server is both the MCP resource server and an OAuth 2.1 authorization server (MCP
authorization spec 2025-06-18: protected-resource metadata, authorization-server metadata,
dynamic client registration, PKCE S256, refresh tokens). Login itself is delegated to Google.
Client registrations, codes and tokens are sealed with AES-256-GCM, so there is no database and
any instance can serve any request.
## Deploy (about 15 minutes)
You need a Google account, a Google Cloud project with billing enabled (the free tier covers
personal use), and Cloud Shell or the `gcloud` CLI.
1. **Google Cloud Console** (same project you'll deploy to):
- Enable the **Google Health API**.
- **Google Auth Platform → Get started**: External, add yourself under **Audience → Test users**.
- **Clients → Create client → Web application**. Leave both URI lists empty for now; copy the
Client ID and secret.
2. **Deploy** from Cloud Shell:
```bash
git clone https://github.com/Shreyamkmr/google-health-mcp-remote.git
cd google-health-mcp-remote
export PROJECT_ID="your-project-id"
export GOOGLE_HEALTH_CLIENT_ID="xxxx.apps.googleusercontent.com"
export GOOGLE_HEALTH_CLIENT_SECRET="GOCSPX-xxxx"
export MCP_ALLOWED_EMAILS="you@gmail.com"
./deploy-cloudrun.sh
```
3. Add the printed **`…/oauth/callback`** URL to your OAuth client's *Authorized redirect URIs*.
4. In Claude: **Settings → Connectors → Add custom connector** → paste the printed **`…/mcp`** URL → Connect.
Step-by-step guide, configuration reference, free-tier details and troubleshooting:
**[DEPLOY-CLOUD-RUN.md](DEPLOY-CLOUD-RUN.md)**.
Other clients:
- **Claude Code**: `claude mcp add --transport http google-health https://<service>/mcp`
- **MCP Inspector**: Streamable HTTP → URL → *Quick OAuth Flow*
### Common gotchas
| Symptom | Fix |
|---|---|
| Build fails with `artifactregistry.repositories.uploadArtifacts denied` | New projects don't grant build permissions by default. The script now grants `roles/run.builder`; on older copies run it by hand (see the deploy guide). |
| `redirect_uri_mismatch` at sign-in | The callback URL on your OAuth client must match exactly (`https`, no trailing slash). |
| "Google hasn't verified this app" | Expected for a personal app — click **Continue**. |
| Logged out every 7 days | Apps in *Testing* get 7-day refresh tokens. Fill in Branding (the server serves `/`, `/privacy`, `/terms`) and **Publish** the app, then reconnect once. |
| Free-trial billing account | Upgrade to a paid account before the trial ends, or Cloud Run is stopped. Always-free allowances still apply. |
## Tools (remote mode)
| Area | Tools |
|---|---|
| Health data | `google_health_list_data_points`, `google_health_reconcile_data_points`, `google_health_daily_rollup`, `google_health_rollup` |
| Summaries | `google_health_daily_summary`, `google_health_weekly_summary`, `google_health_wellness_context` |
| Account | `google_health_get_profile`, `google_health_get_settings`, `google_health_get_identity`, `google_health_revoke_access` |
| Discovery | `google_health_list_data_types`, `google_health_data_inventory`, `google_health_data_type_coverage`, `google_health_capabilities`, `google_health_quickstart`, `google_health_agent_manifest`, `google_health_demo` |
Tools that only make sense for one local user (manual auth URL/code exchange, token-file
status, local disk audits, local wellness-profile file) are hidden in remote mode. Resources and
prompts from the original project are still served.
Try asking: *"How did I sleep last night?"*, *"Summarise my last run and whether I've recovered"*,
*"How many Active Zone Minutes have I got this week?"*
## Security model
- Google access/refresh tokens are only ever held encrypted inside tokens issued to your MCP
client; the server stores nothing. Health data is not stored.
- `MCP_TOKEN_SECRET` (in Secret Manager) encrypts everything. Rotate with `new,old`; drop `old`
to sign everyone out.
- `MCP_ALLOWED_EMAILS` is checked at sign-in, on every request and on every refresh.
- Dynamic registration accepts `https` redirect URIs (and `http` only on localhost); PKCE is required;
authorization codes are single-use and expire in 5 minutes.
- `google_health_revoke_access` revokes the caller's Google grant.
- Report vulnerabilities via [SECURITY.md](SECURITY.md) / a private GitHub advisory.
## Running locally
All original modes still work:
```bash
npm ci && npm run build
node dist/index.js # stdio, single user (original behaviour)
node dist/index.js --http # local HTTP, single user, no auth
npm run start:remote # remote mode on :8080 (needs the env vars above + MCP_TOKEN_SECRET)
```
For local remote mode, add `http://localhost:8080/oauth/callback` to your OAuth client and set
`MCP_PUBLIC_URL=http://localhost:8080`.
The original single-user documentation is kept in [docs/UPSTREAM-README.md](docs/UPSTREAM-README.md).
## Development
```bash
npm ci
npm run typecheck
npm run build
npm run smoke # stdio tools/resources/prompts smoke test
npm run test:remote # 25-check OAuth + MCP end-to-end test against a mock Google
npm run ci # all of the above
```
Remote-mode code lives in [`src/remote/`](src/remote): `oauth.ts` (authorization server and bearer
middleware), `sealed.ts` (AES-256-GCM token sealing), `server.ts` (Express app) and
`request-context.ts` (per-request Google token).
## Credits and licence
Built on [google-health-mcp](https://github.com/davidmosiah/google-health-mcp) by
**David Mosiah**, which provides the Google Health client, tools, summaries and privacy modes.
Remote transport, OAuth layer and Cloud Run deployment by [@Shreyamkmr](https://github.com/Shreyamkmr).
MIT — see [LICENSE](LICENSE). Not medical advice; Google Health data is wellness context only.
This server cannot be deployed
Maintenance
ActivityActive
ResponsivenessNo issues