Skip to main content
Glama
ilyanehay
by ilyanehay

Health Vault

Self-hosted Xiaomi Fitness / Smart Band → SQLite → authenticated MCP for Grok (CLI and grok.com Custom Connector).

Mi Band  →  Mi Fitness (phone)  →  Xiaomi cloud
                                      ↓
                              health sync (this project)
                                      ↓
                                   SQLite
                                      ↓
                         MCP tools (OAuth or API key)
                                      ↓
                              Grok answers with real data

Not affiliated with Xiaomi or xAI. Uses an unofficial reverse-engineered Health API. Personal / research use. Wearable data is wellness only, not medical advice.


Requirements

Need

Notes

Python 3.12+

Required (requires-python >= 3.12)

Xiaomi Smart Band + Mi Fitness app

Band must sync to the phone app first

Xiaomi account

QR login from this tool

Optional: cloudflared or ngrok

For grok.com (public HTTPS)

Optional: Grok CLI / Grok Build

Local MCP with Bearer API key


Related MCP server: Garmin MCP

Quick install

git clone <this-repo> health-vault && cd health-vault

# Option A: uv
uv venv --python 3.12 .venv
uv pip install --python .venv/bin/python -e .

# Option B: plain venv
python3.12 -m venv .venv
source .venv/bin/activate   # Windows: .venv\Scripts\activate
pip install -U pip
pip install -e .

CLI entrypoint: .venv/bin/health (or health after activate).

Runtime data goes to ./data/ (gitignored): Xiaomi token, SQLite DB, OAuth state.


Scenario A — Local data + Grok CLI

Best for development and private use on one machine.

1. Pull data from Xiaomi

  1. On the phone, open Mi Fitness and sync the band.

  2. On the computer:

.venv/bin/health login    # QR → scan with Xiaomi Account app
# QR is also saved as data/qr_login.png if you cannot see the terminal
.venv/bin/health sync --days 7
.venv/bin/health status   # expect sync_health: ok
.venv/bin/health show --days 14

2. API key + MCP server

.venv/bin/health key create --name grok   # prints Bearer token ONCE — save it
.venv/bin/health serve --host 127.0.0.1 --port 8787

3. Point Grok CLI / Grok Build at the server

~/.grok/config.toml (or your agent’s MCP config):

[mcp_servers.health]
url = "http://127.0.0.1:8787/mcp"
headers = { Authorization = "Bearer hlt_PASTE_YOUR_TOKEN" }

Restart the CLI/agent so it reloads MCP. Ask something concrete, e.g. “How did I sleep in the last 7 days?”

Smoke checks (A)

curl -sS http://127.0.0.1:8787/healthz
# → ok

curl -sS -o /dev/null -w '%{http_code}\n' -X POST http://127.0.0.1:8787/mcp \
  -H 'Content-Type: application/json' -H 'Accept: application/json' -d '{}'
# → 401  (auth required)

.venv/bin/health tool health_status
.venv/bin/health tool health_context --hint sleep --days 7

Scenario B — grok.com Custom Connector (tunnel)

Grok’s cloud must call a public HTTPS MCP URL. Easiest path: local server + Cloudflare quick tunnel or ngrok. See also xAI tunneling notes.

1. Data + owner password

.venv/bin/health login
.venv/bin/health sync --days 7
.venv/bin/health oauth set-password    # password for the browser login page

2. Serve with a public URL

One-shot (integrated tunnel):

# brew install cloudflared   # if needed
.venv/bin/health serve --host 127.0.0.1 --port 8787 --tunnel

Copy the printed URL, e.g. https://xxxx.trycloudflare.com.

More reliable (two terminals):

# Terminal 1
.venv/bin/health serve --host 127.0.0.1 --port 8787 --public-url https://PLACEHOLDER

# Terminal 2 — after Uvicorn is up
cloudflared tunnel --url http://127.0.0.1:8787
# copy https://xxxx.trycloudflare.com

# Restart terminal 1 with the real public URL (OAuth issuer must match HTTPS host):
.venv/bin/health serve --host 127.0.0.1 --port 8787 \
  --public-url https://xxxx.trycloudflare.com

Free tunnel URLs often change on restart — update the Grok connector when they do.
If the public URL returns 530 / Error 1033, wait a few seconds or use the two-terminal flow.

3. Connect in Grok

  1. Open grok.com/connectorsNew ConnectorCustom.

  2. Server URL: https://xxxx.trycloudflare.com/mcp (must include /mcp).

  3. If Grok shows an OAuth form: use PKCE; authorization/token endpoints from
    https://xxxx.trycloudflare.com/.well-known/oauth-authorization-server;
    scope health:read (Client Secret usually empty for public + PKCE).

  4. Browser opens Health Vault login → enter the password from health oauth set-password.

  5. Chat with a real question (not only “list tools”).

More detail: docs/GROK_CONNECT.md.

Smoke checks (B)

curl -sS https://xxxx.trycloudflare.com/healthz
curl -sS https://xxxx.trycloudflare.com/.well-known/oauth-authorization-server | head
curl -sS -o /dev/null -w '%{http_code}\n' -X POST https://xxxx.trycloudflare.com/mcp \
  -H 'Content-Type: application/json' -d '{}'
# → 401 without token

Scenario C — VPS / home server (generic production)

Pattern: app listens on HTTP on a private port; TLS and domain are terminated by a reverse proxy (Caddy, nginx, Traefik, etc.) in front. Do not put secrets in git.

Example names below are placeholders — choose your own domain and port.

1. Install on the host

sudo mkdir -p /opt/health-vault/data
sudo chown "$USER:$USER" /opt/health-vault /opt/health-vault/data
chmod 700 /opt/health-vault/data

# copy or git clone the project into /opt/health-vault
cd /opt/health-vault
python3.12 -m venv .venv
.venv/bin/pip install -U pip
.venv/bin/pip install -e .

2. Environment file (secrets, not in git)

sudo tee /etc/health-vault.env >/dev/null <<'EOF'
HEALTH_ROOT=/opt/health-vault
HEALTH_DATA_DIR=/opt/health-vault/data
PUBLIC_BASE_URL=https://health.example.com
HOST=0.0.0.0
PORT=8002
# Optional: bootstrap owner password once if DB has none yet
OAUTH_LOGIN_PASSWORD=change-me-to-a-long-random-string
EOF
sudo chmod 640 /etc/health-vault.env
# owner should be root + the service user (e.g. root:deploy)

PUBLIC_BASE_URL must be the public HTTPS origin users and Grok hit (no path).

3. systemd unit

Example unit (also see deploy/health-mcp.service as a template — rename paths):

[Unit]
Description=Health Vault MCP server
After=network-online.target
Wants=network-online.target

[Service]
Type=simple
User=YOUR_USER
Group=YOUR_GROUP
WorkingDirectory=/opt/health-vault
EnvironmentFile=/etc/health-vault.env
ExecStart=/opt/health-vault/.venv/bin/python -m health_mcp
Restart=on-failure
RestartSec=5
NoNewPrivileges=true
PrivateTmp=true
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/opt/health-vault/data

[Install]
WantedBy=multi-user.target
sudo systemctl daemon-reload
sudo systemctl enable --now health-vault.service
systemctl is-active health-vault
curl -sS http://127.0.0.1:8002/healthz

4. Reverse proxy (TLS)

Terminate HTTPS on the proxy and reverse-proxy to 127.0.0.1:8002 (or the app host). Preserve Host and X-Forwarded-Proto.

Caddy example:

health.example.com {
    reverse_proxy 127.0.0.1:8002
}

nginx sketch:

server {
    listen 443 ssl;
    server_name health.example.com;
    # ssl_certificate ...;
    location / {
        proxy_pass http://127.0.0.1:8002;
        proxy_set_header Host $host;
        proxy_set_header X-Forwarded-Proto $scheme;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    }
}

Point DNS A/AAAA for health.example.com at your server (or your edge).

5. Data + Grok

cd /opt/health-vault
# if OAUTH_LOGIN_PASSWORD was not used:
HEALTH_ROOT=/opt/health-vault .venv/bin/health oauth set-password

HEALTH_ROOT=/opt/health-vault .venv/bin/health login
HEALTH_ROOT=/opt/health-vault .venv/bin/health sync --days 7

Optional cron (every 30 minutes):

*/30 * * * * cd /opt/health-vault && HEALTH_ROOT=/opt/health-vault .venv/bin/health sync --days 3 >>/var/log/health-sync.log 2>&1

Connect Grok Custom Connector to:

https://health.example.com/mcp

Smoke checks (C)

curl -sS -o /dev/null -w '%{http_code}\n' https://health.example.com/          # 200
curl -sS -o /dev/null -w '%{http_code}\n' https://health.example.com/healthz   # 200
curl -sS https://health.example.com/.well-known/oauth-authorization-server | head
curl -sS -o /dev/null -w '%{http_code}\n' -X POST https://health.example.com/mcp \
  -H 'Content-Type: application/json' -d '{}'                                  # 401

Auth model

Method

Use case

Bearer API key (health key create)

Grok CLI / local agents

OAuth 2.1 + PKCE + owner password

grok.com Custom Connector

Xiaomi QR token

Ingest only — never sent to Grok

  • API keys are stored as SHA-256 hashes; plaintext shown once.

  • OAuth access/refresh tokens hashed in SQLite under data/.

  • Unauthenticated /mcp401.


MCP tools

All tools return sync_health, attention_required, and a wellness disclaimer.

Tool

Purpose

health_status

Last sync, coverage, token presence

health_get_daily

Daily rows (steps, sleep, HR, SpO2, stress, …), max 90 days

health_context

Compact brief for one question (question_hint)

health_trends

Mean / min / max / half-window delta for one metric

health_anomalies

Points outside mean ± 2σ

If attention_required is true (stale/broken sync), Grok should warn first and suggest health login / health sync.

Env thresholds: HEALTH_STALE_AFTER_HOURS (default 36), HEALTH_BROKEN_AFTER_HOURS (default 72).


CLI reference

health login                         # Xiaomi QR → data/token.json
health sync [--days N] [--uid …] [--base-url …]
health status
health show [--days N]

health key create|list|revoke
health oauth set-password|status

health serve [--host] [--port] [--public-url] [--tunnel]
health tool <name> [--days N] [--hint …] [--metric …]

Production process entry: python -m health_mcp (reads env above).


Layout

src/health_core/       SQLite schema, queries, sync_health
src/health_ingest/     Xiaomi cloud → daily_metrics
src/health_auth/       API keys, owner password, OAuth AS
src/health_mcp/        MCP server, tools, tunnel helper
src/health_cli/        `health` CLI
vendor/mi-fitness-python/   vendored SDK (GPL-3.0)
deploy/                example systemd unit (template only)
docs/GROK_CONNECT.md   Grok connection details
data/                  runtime (gitignored)

Troubleshooting

Symptom

What to try

Login QR invisible

Open data/qr_login.png; use Xiaomi Account app to scan

Token not found / TokenExpiredError

health login again

Sync OK but empty metrics

Sync the band in Mi Fitness on the phone; wait; re-run health sync

not support HlthRelativesCareClient

Expected on some accounts; own user_id path still works

Wrong region / empty cloud

Try --base-url / HEALTH_API_BASE if your account is not on default RU IDC

MCP always 401 with key

Use full Bearer hlt_… header; create a new key if revoked

grok.com cannot connect

Must be public HTTPS + path /mcp; OAuth password set; tunnel alive

Tunnel 530 / hostname fails

Restart tunnel; two-terminal setup; confirm cloudflared has network

Stale data in Grok answers

Check health status; run sync on a schedule

attention_required in every tool

Fix ingest; do not treat metrics as current until sync_health.status is ok


Security notes

  • Never commit data/, .env, tokens, or passwords (see .gitignore).

  • Prefer long random OAUTH_LOGIN_PASSWORD; rotate via health oauth set-password.

  • Expose only HTTPS to the internet; keep the app port private when possible.

  • Single-owner design: one vault password / API keys for that host.


Acknowledgements

This project stands on reverse-engineering and open-source work that made Xiaomi Fitness data reachable outside the official app.

  • alexgetmancom/miband-bot — personal self-hosted Telegram bot for Xiaomi Fitness / Mi Band (auth, cloud sync, SQLite, parsers). The approach and practical stack around Band 10 / Mi Fitness cloud were a major starting point for this vault. Thank you to the author for publishing the research and code. See also the write-up Reverse Engineering the Xiaomi Smart Band 10 (Habr).

  • MistEO/MiSDK (mi-fitness / mi_fitness) — Python SDK for Xiaomi Health / “relatives” APIs (QR login, RC4 transport, typed clients). Vendored under vendor/mi-fitness-python/ (GPL-3.0).

Neither project is affiliated with this repo; any bugs here are ours.


License

This project is free software under the GNU General Public License v3.0 or later (GPL-3.0-or-later).

You may run, study, share, and modify it. If you distribute modified versions (or a product that combines this code with the vendored SDK), you must keep them under GPL-compatible terms and preserve copyright/license notices. See LICENSE for the full text.

  • Includes vendor/mi-fitness-python (MistEO/MiSDK), also GPL-3.0 — attribution required.

  • Unofficial Xiaomi Health protocol — may break without notice when Xiaomi changes apps or servers.


Optional reading

A
license - permissive license
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • A
    license
    B
    quality
    C
    maintenance
    MCP server that provides local caching, sync, and tools for Zepp Life health data including steps, sleep, heart rate, workouts, and body measurements, supporting both file exports and cloud session access.
    Last updated
    10
    5
    MIT
  • A
    license
    B
    quality
    A
    maintenance
    Local-first MCP server that connects AI agents to your Garmin sleep, HRV, Body Battery, stress, training readiness and activities, keeping tokens on your machine.
    Last updated
    41
    239
    7
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    MCP server to read daily activity, sleep, heart rate, and body metrics from Google Health API, allowing AI assistants like Claude to access your health data. Optionally syncs health metrics to an Obsidian vault.
    Last updated
    5
    MIT

View all related MCP servers

Related MCP Connectors

  • MCP server for Withings health data — sleep, activity, heart, and body metrics.

  • Garmin data in Claude & ChatGPT via the Garmin Health API. OAuth sign-in, no password sharing.

  • Self-hosted MCP gateway: turn any API, database or MCP server into AI connectors — no code.

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ilyanehay/mi-health-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server