Akari Health MCP
Provides tools for retrieving health data stored in a SQLite database, such as the latest heart rate, SpO2, stress, and sleep records from a vivo watch.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Akari Health MCPwhat's my latest heart rate and SpO2?"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Akari Pulse
English | 中文
Akari Pulse is a self-hosted bridge that takes the health data your own vivo phone and watch already collect, puts it in a database you control, and serves it to your own AI assistant over MCP.
You run every part of it. Your phone reads its own health providers, your relay buffers the upload, your server stores it, and your MCP endpoint answers queries from ChatGPT, Claude, or any other MCP client you point at it. There is no Akari Pulse cloud in the middle, because no such service exists.
The reason people usually want this: an AI assistant — or an AI companion — that can actually see how you slept and how your body is doing today, instead of asking you to type it in every morning. That is one natural use of a personal health MCP, not the only one; the same endpoint is just as useful for a self-tracking dashboard or your own analysis scripts.
What it can read today
Source | Data |
vivo phone | daily steps · distance · calories · last night's full sleep summary with stages, wake-ups and score · latest heart rate · latest SpO2 · latest stress |
vivo watch ( | heart rate · resting heart rate · SpO2 · stress · the watch-side diagnostics already supported by the collector |
Sleep and the three latest vitals come from vivo's private health providers, which a sideloaded app cannot reach until you grant it access yourself over ADB — see the owner ADB bootstrap below. Steps, distance and calories need no such step.
Related MCP server: Mi Fitness MCP
Rules the project holds to
Phone and watch stay separate. Both sources are returned side by side. Neither is merged into the other and neither is given precedence.
No silent fallback. A failed read never becomes a cached value, a stale value, a UI scrape, or an invented zero.
Missing data stays missing, visibly. Every observation is
PASS,NO_DATA,DENIED,UNSUPPORTED,API_MISSING, orERROR. A real measured zero is stillPASS; an absent measurement never becomes one.No shared cloud, no telemetry, no analytics. Nothing phones home. You deploy the relay, the database, the backend and the MCP endpoint yourself.
Your AI client only ever sees the answer to the query you asked, not the database.
This project handles sensitive personal health data, and sleep data in particular is a detailed record of when you are home and unconscious. Read PRIVACY.md and SECURITY.md before you expose any endpoint beyond loopback.
Verified environment
Compatibility here is per model and per firmware. A successful build proves nothing about a device that has not been tested.
Device | State |
vivo X200 Pro ( | Verified on the ROM installed at test time, 2026-08-14. Daily activity, private sleep and latest vitals all read successfully and matched the vivo Health UI. |
vivo WATCH GT, first-gen Bluetooth | Verified 2026-08-12 for the watch health chain end to end. |
Any other vivo or iQOO phone, watch, ROM or firmware | Unverified. The private-provider route may be refused outright, in which case Akari Pulse reports |
vivo's official Health Kit remains the supported, ADB-free third-party route. Akari Pulse is an owner-controlled path for the owner's own device, not a distribution mechanism.
Status: reference / research. Published as-is with no maintenance or support promise. Not
affiliated with, endorsed by, or sponsored by vivo. Every endpoint in this repository is a
placeholder — pulse.example.com, pulse-mcp.example.com, REPLACE_WITH_* — and there
are no real tokens, credentials, or signing keys in the tree.
The RPK sideloading path relies on the OrbitV community's work; without it the watch could not receive an unsigned developer build at all.
How the pieces fit together
vivo phone vivo WATCH GT (WA2456C)
step provider -> daily summaries BlueOS health + sensor APIs
private sleep -> sleep summary durable on-watch queue
private care -> latest HR / SpO2 / stress HTTPS via the paired phone
| |
+--> Android bridge: Room + immutable outbox <-----+
|
v
Cloudflare Worker relay (D1 buffer) you deploy this
|
v
Akari Health service (Node.js + SQLite) you deploy this
|
v
Akari Health MCP (stdio / Streamable HTTP)
|
v
ChatGPT / Claude / any MCP clientThree data shapes travel that path, deliberately kept distinct:
Daily activity is a natural-day cumulative summary — one current row per
(source, metric, source_day), replaced by later reads of the same day.Sleep is a bounded interval with stages, not a day counter, so it gets its own contract — one current row per
(source, source_day).Latest vitals are single timestamped observations, each carrying the provider's own measurement time. They are never republished as a daily minimum, maximum, average, or resting value.
Every upload batch is immutable, and every receiver acknowledges only after durable storage. The relay deletes a row only after the backend confirms that exact batch, so no layer drops data it has not handed off.
Full detail is in ARCHITECTURE.md; the reverse-engineering evidence is in RESEARCH.md.
Repository
Every component has its own README; start with the one for the layer you are touching.
Path | What it is |
BlueOS health collection, durable queue, HTTPS/RPC adapters, diagnostics UI | |
phone-local daily summaries, vivo private sleep/vitals, fallback watch receiver | |
Cloudflare Worker ingest buffer and D1 schema | |
Node.js 24 HTTP service and SQLite persistence | |
independent MCP (stdio + Streamable HTTP) using the official TypeScript SDK | |
systemd units and runbook for an always-on store + remote MCP | |
strict shared event and batch schemas | |
architecture, research, diagnostics, testing, and real-device evidence | |
deliverable policy and SHA-256 manifest (no binaries are published) | |
| install, start, smoke, relay-drain, ADB bootstrap, and tailnet-bind scripts |
SPEC.md states the product and data-model requirements the implementation is held to.
Prerequisites
Windows PowerShell 7 or Windows PowerShell 5.1.
Node.js 24 or newer for the service and MCP.
JDK 17 and Android SDK API 35 for rebuilding the Android app.
Android platform-tools (
adb) onPATHfor the private-provider bootstrap.BlueOS Studio 2.x, including its bundled Node.js and
blueos-pack, for rebuilding the RPK.Optional: Tailscale for phone-to-Windows private-network access.
Optional, for vivo's official RPC at runtime: a vivo developer
appid, an intelligent-terminal SDK key (encryStr), vivo Health on the phone, and a package/signing-fingerprint pair the watch accepts.
Install and verify the service/MCP
From the repository root:
.\scripts\install.ps1
.\scripts\verify-service.ps1Start the loopback service:
.\scripts\start-server.ps1To bind only the machine's current Tailscale IPv4, first provide a strong bearer token:
$env:AKARI_HEALTH_TOKEN = '<strong-random-token>'
.\scripts\start-server-tailnet.ps1The tailnet script reads the exact IPv4 from tailscale ip -4. It does not run
tailscale up, alter grants, change Windows Firewall, or modify an existing Serve/Funnel
configuration.
Start the independent MCP in another terminal:
$env:AKARI_HEALTH_URL = 'http://127.0.0.1:8787'
$env:AKARI_HEALTH_TOKEN = '<same-token-if-configured>'
.\scripts\start-mcp.ps1Ready-to-edit client examples are codex.example.toml and claude-desktop.example.json; adjust the paths for your host. Keep the bearer token in the local environment/config only; do not commit it.
For an always-on deployment — so queries still work with your PC off — the systemd units and runbook are in deploy/tokyo. Treat the resulting MCP URL as a password: the unguessable path is the credential.
Build and configure Android
The official public AAR is vendored at android/app/libs/device-rpc-1.0.0.17.aar with its
SHA-256 sidecar. To rebuild, put only local machine values in the ignored
android/local.properties:
sdk.dir=C\:\\Users\\<you>\\AppData\\Local\\Android\\Sdk
VIVO_RPC_APP_ID=<numeric-vivo-appid>If no app ID is available, omit the second line; the APK still builds and the UI truthfully
reports official RPC as API_MISSING. Build and validate:
Set-Location .\android
.\gradlew.bat testDebugUnitTest assembleDebug lintDebug --no-daemon --max-workers=1
.\scripts\verify-device-rpc.ps1Install the resulting debug APK with Android Studio or:
adb install -r .\app\build\outputs\apk\debug\app-debug.apkIn the app, configure the Akari Health base URL and the phone-specific upload credential in
server bearer token; Android Keystore encrypts it at rest. read today activity persists
the three phone daily-summary metrics transactionally and queues
/v1/health/daily-summaries through WorkManager. Keep this credential separate from the
watch relay's INGEST_TOKEN.
The debug-only HTTP receiver permits cleartext for a controlled loopback/tailnet probe. A non-loopback listener requires a separate bridge token of at least 16 characters. Release builds reject cleartext service URLs.
The owner ADB bootstrap
Sleep and the three latest vitals live behind com.vivo.health.widget.permission, which
vivo declares signature|privileged. An installed third-party APK never receives it,
no matter what its manifest asks for. Until it is granted, Akari Pulse reports
NOT_GRANTED and returns null values.
This is not a way around vivo's permission system, and nothing about vivo Health is modified. It is the device owner using ADB — the same tool Android ships for exactly this purpose — to say: this app, on my phone, may read my own health providers. You can undo it at any time.
Grant it once per install:
pwsh -File .\scripts\bootstrap-vivo-private-health.ps1The script does not trust the grant command. pm grant can exit 0 on a ROM that quietly
refuses to change anything, so the verdict is read back from dumpsys package and
printed as PASS or FAIL. It also refuses to act at all when adb is missing, no
authorized device is attached, several devices are attached without -Serial, the package
is not installed, or the provider authorities do not exist on the device.
Revoke it the same way, verified the same way:
pwsh -File .\scripts\bootstrap-vivo-private-health.ps1 -RevokeAfter a successful grant, use read sleep and vitals in the app and confirm its capability
card:
Capability state | Meaning | What to do |
| the permission is held and both providers are readable | nothing — reads will work |
| the providers exist, but this build does not hold the permission | run the bootstrap script |
| the provider authorities do not exist on this device | this route is unavailable on this phone |
| the probe itself failed; the raw reason is kept | read the reported reason |
Things to expect, all of them demonstrated on the verified device rather than assumed:
Reinstalling the APK clears the grant. Re-run the script after every install.
A system update, factory reset, or new phone may clear or refuse it. Re-verify; do not assume the previous result still holds.
A ROM is allowed to say no. The script then reports
FAILand the app reportsNOT_GRANTED. Neither is worked around, and neither falls back to stale data.This is not a general Android or vivo guarantee. It is one verified phone, one ROM, at one point in time.
Build and configure the watch
The watch app calls the current official modules directly:
@blueos.health.healthwithwatch.permission.READ_HEALTH_DATA;@blueos.hardware.sensor.sensorwithwatch.permission.STEP_COUNTER;@blueos.bluexlink.connectionManagerfor the production RPC candidate;@blueos.network.fetchfor the explicit HTTP probe.
Before a paired RPC build, set watch/src/config.js phonePackage to
dev.akari.pulse.bridge and phoneSha256 to the SHA-256 signer fingerprint of the exact
APK being installed. Rebuilding the APK with a different debug/developer certificate
changes that fingerprint and requires rebuilding the RPK.
Use the build command documented in watch/README.md, then install the RPK through the current OrbitV sideload flow. The checked-in project never carries a watch signing private key. BlueOS Studio's debug builder may generate a local debug signature; a release RPK requires the operator's own developer certificate and key.
Since 0.1.3 the watch adapter defaults to http against your relay's
/v1/health/batches endpoint with your ingest token compiled in via watch/src/config.js
(placeholders pulse.example.com / REPLACE_WITH_YOUR_INGEST_TOKEN in this repository).
Because the token is compiled into the package, never publish a built RPK — rotating it
requires wrangler secret put INGEST_TOKEN (or the REST equivalent) plus a watch rebuild.
Pointing the adapter at the Android LAN listener instead is a fallback: set an address the
physical watch can actually reach and the Android bridge token; 127.0.0.1:23102 is
deliberately not claimed to map to the phone on a real watch.
vivo's official BlueXlink/device RPC pair was the original watch-to-phone candidate and
remains closed on this hardware: the real WA2456C fails at interconnect connection
time with code=1001 interconnectfeature error, the official support table lists only vivo
WATCH 3, and the required vivo appid/encryStr are not obtainable for this project. The
Android watch receiver remains buildable as a fallback. OrbitV is used for RPK sideloading
only and is not treated as a generic bridge API.
Data and failure semantics
Every watch observation is one immutable event containing the producer timestamp, metric,
source device, status, and optional real value/sample timestamp/callback delta/session/
error. A phone natural-day summary is instead a versioned current row backed by immutable
upload batches; it is never disguised as a watch event. A phone sleep night is a third
shape: one current row per source day, also backed by immutable batches. PASS requires a
real value, including a legitimate numeric zero. Missing or failed measurements remain
NO_DATA, DENIED, UNSUPPORTED, API_MISSING, or ERROR; no layer substitutes a stale
value.
Failures are attributed to watch_module_api, permission, sample_acquisition,
watch_transport, phone_receive, phone_persistence, uplink, vivo_private_health,
backend_ingest, database, or mcp_query. Follow DIAGNOSTICS.md
from the first non-PASS layer.
Raw health records have no update/delete HTTP or MCP route. Session summaries may calculate baseline, peak, delta, latency-to-rise, and time-to-peak from real samples and timestamped events, but they state that temporal association does not establish causality.
The MCP exposes 14 narrow tools; each read tool is annotated readOnlyHint. The full list
and their semantics are in mcp/README.md.
Current delivery status
Layer | Host result | Real-device result |
BlueOS watch app |
|
|
Watch health chain | one-test-per-launch harness |
|
Official BlueXlink RPC | public watch API and official Android AAR integrated | closed: |
Cloudflare relay | strict watch-event, phone-daily-summary, and phone-sleep-summary ingest routes; replay/conflict/auth tests (5/5) |
|
Akari Health service | authenticated watch-event plus idempotent daily-summary and sleep-summary routes tested against temporary databases (21/21) |
|
Akari Health MCP | official SDK client lists and invokes all 14 tools (3/3 e2e) |
|
Always-on VPS + remote MCP | deployed on a Tokyo VPS (systemd: service, 2-min drain timer, Streamable-HTTP MCP, Cloudflare Tunnel) |
|
Android app | debug APK built, 35 unit tests, linted, Room 1 -> 2 and 2 -> 3 migration-tested |
|
vivo private health providers | reader unit-tested against synthetic cursors and payloads only |
|
Exact evidence and the adaptive one-test-per-launch sequence are in REAL_DEVICE_RESULTS.md and DIAGNOSTICS.md.
Tests and artifacts
The complete reproducible verification record is TESTING.md. Run the repository-wide suite with:
npm testNo binaries are distributed here — see artifacts/README.md for
why. SHA256SUMS.txt is kept as the historical record of what was privately built and
device-verified:
Artifact | Bytes | SHA-256 |
| 31,164,014 |
|
| 89,461 |
|
| 84,899 |
|
| 75,466 |
|
| 69,649 |
|
| 15,674 |
|
| 8,757 |
|
The machine-readable list, APK signer certificate digest, and vendored AAR digest are in SHA256SUMS.txt.
Do not interpret an RPK/APK build, an RPC send callback, a simulator request, or
/healthz as a physical-device end-to-end pass. Only update
REAL_DEVICE_RESULTS.md after real-device verification, and
keep public evidence free of personal health values, tokens, SDK keys, serial numbers, MAC
addresses, cookies, private endpoint URLs, and account identifiers. See
CONTRIBUTING.md.
License
Copyright (c) 2026 Yoru. Licensed under the GNU Affero General Public License v3.0.
AGPL-3.0 is deliberate for this kind of project: if you modify Akari Pulse and offer it to other people over a network, those users are entitled to your modified source. Running your own private instance for yourself imposes no obligation at all.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
MCP server for Withings health data — sleep, activity, heart, and body metrics.
Multi-tenant hosted MCP server for Oura Ring — 21 read-only tools, OAuth per user.
Private Apple Health metrics and workout detail for ChatGPT, Claude, and any MCP client.
Remote MCP server for training, nutrition, wellness, and performance data with OAuth 2.0.
Related MCP Servers
- AlicenseBqualityBmaintenanceMCP 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.109MIT
- AlicenseCqualityCmaintenanceMCP server for Mi Fitness cloud data. Provides a local SQLite-backed server to sync and query daily activity, heart rate, and body measurements.124MIT
- AlicenseNot gradedqualityDmaintenanceMCP server that exposes Garmin Connect health and activity data (steps, sleep, stress, activities, etc.) via tools for querying, analysis, and visualization.Apache 2.0
- AlicenseAqualityBmaintenanceUnofficial MCP server bridging Garmin Connect to MCP clients and ChatGPT, providing tools to access health data, activities, and trends via a self-hosted API.11MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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/yoruuuchan/akari-pulse'
If you have feedback or need assistance with the MCP directory API, please join our Discord server