Health Vault

Health Vault

Self-hosted MCP server that syncs Xiaomi fitness data to SQLite and provides authenticated tools to query health metrics (steps, sleep, HR, etc.) for AI assistants like Grok.

Category
访问服务器

README

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

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

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选