mirobody
Self-hosted health data engine: lab reports, wearables and genetic files in one record, and an agent that cites its sources.
Install / Use
claude mcp add thetahealth -- npx -y github:thetahealth/mirobodyIf the server publishes to npm under a different name, use that package instead — check the repo README.
MCP Server
Model Context Protocol server
Quality Score
Category
Healthcare & Life SciencesSupported Platforms
Our assessment of mirobody
mirobody scores 93/100 on our quality scale, 5th of 43 Healthcare & Life Sciences skills we index (top 12%).
Its MCP Server is 18 KB long, well organised into 10 sections with 5 code examples: a thorough specification that gives an agent plenty to work with.
With 1,347 GitHub stars, it is one of the more widely adopted skills in the catalogue.
Maintenance, license and trust
- The repository was last updated today, so mirobody is actively maintained.
- Our last check on 2026-09-28 found the source still online.
- It is released under the Apache-2.0 license, a permissive license that allows use, modification and commercial use with attribution.
- Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.
Safety scan
No issues foundOur scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful.
AI review by kimi-k2.7-code on 2026-09-24. Automated pattern scan on 2026-09-24. It catches known dangerous patterns, not every risk — read a skill before letting an agent act on it.
mirobody compared with similar skills
All 4 of these similar skills score higher than mirobody; compare them before choosing.
| Skill | Score | Stars | Updated | Format |
|---|---|---|---|---|
| mirobody (this skill)by thetahealth | 93 | 1.3k | today | MCP Server |
| Agent-Reachby Panniantong | 100 | 86.4k | 15d ago | CLAUDE.md |
| headroomby headroomlabs-ai | 100 | 74.2k | today | CLAUDE.md |
| rufloby ruvnet | 100 | 73.6k | today | CLAUDE.md |
| CowAgentby zhayujie | 100 | 47.2k | today | CLAUDE.md |
Frequently asked questions
- How do I install mirobody?
- Run
claude mcp add thetahealth -- npx -y github:thetahealth/mirobody. The install tabs above show the steps for each supported agent. - Which AI agents does mirobody work with?
- It is written for Claude Code and Claude Desktop, as a MCP Server file. Other agents that read the same format can often use it too.
- Is mirobody safe to use?
- Our scan of the whole file found no instruction hijacking, hidden characters, credential access, data exfiltration or destructive commands. An AI review of the same text found nothing harmful. It is Apache-2.0-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
- Is mirobody still maintained?
- The repository was last updated today, so mirobody is actively maintained.
Skill content
View source on GitHubMirobody
Self-hosted AI health data engine: every source, one standard, answers that cite their source.
English · 中文
📚 Documentation · ▶ Live demo — no sign-up · 🔌 API platform
</div>Last year's checkup wrote A1c, this year's panel HbA1c, the new clinic
Glycated Hemoglobin. One test, three names, nothing to compare. Mirobody takes
health information from any source, in any format, under any name, and settles
it into one language and one system, then answers over that record, every number
citing its source: traceable, comparable, chartable. How has my blood pressure
moved? Are mom's diabetes markers improving? What changed across my child's
checkups? Self-host it all, and your health record stays in your hands.
What Mirobody does
- One record for the whole family. Invite a partner, a parent, even a child who never signs in at all, and keep the household's health history in one place.
- Every source, one record. Garmin, Oura and Whoop connect directly; anything already written into Apple Health comes with it; PDFs, phone photos, spreadsheets, exports: 23 file types in all, and Mirobody reads them.
- No hallucinations, everything traceable. Every indicator lands in one settled system: either it gets a definite code, or it says it could not resolve one. It never invents one in between. Built and tested against real reports, in English, Chinese and Japanese.
- The agent reasons only over coded data. Trends by minute, hour, day, week or month, drawn as a chart; a baseline and how far a number has moved in one call; comparisons across labs, files and devices, because one standard (LOINC and UCUM) sits under all of them. It reads medications and genetic variants too.
- Runs on a laptop. Four containers, 791 MiB resident, under 5% CPU idle. No GPU, no Node.js.
- Your model, your key, your data. Model calls go to the model you chose. Everything else stays on your machine.
Try it in 60 seconds
One command, five spellings: watch which ones it recognises, and which one it
refuses. No key, no config, no network, and with uvx, no install either:
uvx mirobody resolve "LDL cholesterol" 血红蛋白 ヘモグロビン "空腹血糖(GLU)" 血脂
<p align="center">
<img src="docs/images/resolve-demo.gif"
alt="mirobody resolve: 血红蛋白 and ヘモグロビン landing on the same LOINC code, and one deliberate abstention" width="880">
</p>
血红蛋白 and ヘモグロビン: two languages, one code, 718-7. 血脂 (lipids)
names a category, not one observation, so it resolves to nothing. The
resolver would rather return nothing than guess a code, because a wrong one
puts two different tests on the same trend line.
from mirobody.engine import resolve, resolve_reading
resolve("血红蛋白").loinc # '718-7' any language, one code
resolve("total cholesterol").loinc # '2093-3' [Mass/volume]
resolve_reading("total cholesterol", "5.0", "mmol/L") # '14647-2' [Moles/volume]
resolve_reading("total cholesterol", "193", "mg/dL") # '2093-3' the unit picks the code
resolve("中性粒细胞百分比").loinc # '26511-6' Neutrophils/Leukocytes
resolve_reading("中性粒细胞", "62 %", None).loinc # '26511-6' a percentage...
resolve_reading("中性粒细胞", "4.2", "10*9/L").loinc # '26499-4' ...and a count are two codes
resolve("血脂").resolved # False a category, not an observation
Pass the value and the unit when you have them. A different unit means a different test, and LOINC folds that into the code's own identity, so one name is deliberately several codes. → Engine reference · Indicators
Collect · Translate · Agent
<p align="center"> <picture> <source media="(prefers-color-scheme: dark)" srcset="docs/images/collect-translate-agent-dark.svg"> <source media="(prefers-color-scheme: light)" srcset="docs/images/collect-translate-agent.svg"> <img src="docs/images/collect-translate-agent.svg" alt="Collect, Translate, Agent: three stages, left to right" width="920"> </picture> </p>An indicator takes three steps from arriving to being cited. Each one leaves a trace, so the answer at the end can be followed back to the page it came off:
| Stage | What it does | Where |
| --- | --- | --- |
| ① Collect | Lab reports, wearables, phone photos, genetic files, all pulled in. The source file is kept as it was, so every indicator points back to the page it was read from. | collect/ |
| ② Translate | One name to one code, one unit to UCUM, offline and deterministic. A1c, HbA1c and Glycated Hemoglobin become the same test here. | engine.py · translate/ |
| ③ Agent | Ask over the coded record. Trend a value by minute, hour, day, week or month; get count, min, max, avg or change over any window in one call; compare across labs and devices, because they share one code. It charts the result in its reply, reads medications and genetic variants too, and names the file every number came from. | agent/ |
① records how the source spelled it, ② decides what it actually is, ③ answers on that footing. Comparing a number across two labs, charting three years of it, computing a baseline: all of it rests on the code ② hands over.
The agent does not have to be ours. Every tool it uses is served at /mcp
as well, gated per user. Claude Desktop, Cursor or your own loop run the same
tools over the same record, and get back the same indicators.
Garmin, Oura and Whoop connect with your own credentials from each vendor; the setup guide walks it through. Apple Health goes another way: a client on the phone hands the data over, so any band, ring or scale reaches your record the moment it writes into Apple Health, with nothing to integrate here at all.
Privacy
Nothing leaves your machine except calls to the model you chose. Reading a
photo of a report, pulling indicators out of a PDF, answering your question:
all three call it. Which provider and which model is the one key in your .env.
② Translate stays local entirely: a name to a code, a unit to UCUM, looked up against a bundle that ships inside the package. No key, no network, no GPU, no model. Your record lives in your own Postgres, in containers you run, and nothing here reports usage anywhere.
One key, and it is the only secret you hold. Put an
OpenRouter key (OPENROUTER_API_KEY), a
Gemini key (GOOGLE_API_KEY), an
OpenAI key (OPENAI_API_KEY) or an
Anthropic key
(ANTHROPIC_API_KEY) in the .env beside compose.yaml, then
docker compose restart. DeepSeek, DashScope or any OpenAI-compatible gateway
works alone too. Which model chats, which reads report photos, which extracts
indicators and which embeds are four lines in
config.llm.yaml, and that file names the variable
(api_key: OPEN…[redacted]), never the secret. mirobody doctor prints
what each surface selected, and names the fix where one has nothing.
The quickstart ships its secrets as placeholders, and encryption at rest does not yet cover every field. Before this reaches a network you do not control, read SECURITY.md: it also lists exactly what the server calls off your machine.
🚀 See it end to end
git clone --depth 1 https://github.com/thetahealth/mirobody.git && cd mirobody
git lfs install && git lfs pull # the resolver's LOINC bundle, 13 MB; a fresh clone holds a pointer stub until you do
./deploy.sh # Postgres + pgvector, Redis, server, worker → http://localhost:18060
(--depth 1 skips the history of superseded frontend builds; drop it if you
plan to send a pull request.)
Two things deploy.sh will stop and tell you about, both with the fix in the
message: one checkout at a time, because compose.yaml pins the stack's
subnet, so a second one needs a different mirobody_network subnet; and a
Docker that refuses named volumes (rootless, hardened) needs bind mounts
instead, which is what compose.override.yaml.example is for.
Sign in as you@mirobody.ai, code 111111, no mail provider needed. An
account of your own is one request away:
curl -X POST localhost:18060/password/register -H 'Content-Type: application/json' \
-d '{"email":"me@example.com","password":"at-l…[redacted]"}'
SEED_DEMO_DATA is on by default, so two accounts are already there with
2,019 indicators between them: you, and mom@mirobody.ai, who shares her
record with you view-only. Set it to false to hold real data and neither
account is created. Settings → Add member covers someone who will never
sign in at all, a parent, a child, with a record you hold on their behalf.
Drop a file on the Data page and watch it become indicators.
demo/upload/ holds four files the seed deliberately leaves out: a
lab PDF, a phone photo of a printed report, a spreadsheet and another lab's
CSV export. Each analyte comes out with a value, a unit and a LOINC code,
linked back to the page it was read from.
Ask how the cholesterol has moved and the agent finds every file that carries
it: one lab writes Cholesterol, Total where the others write
Total Cholesterol-TC, and both are 14647-2. It charts the trend and names
the file each number came off: 4.60 → 4.45 → 4.38 mmol/L. Ask for a baseline
or a monthly average instead and the same tool aggregates over the whole
record, rather than handing back rows for the model to add up itself.
Ask the same question of the record shared with you and it is a different person's answer, from data you can only view. That sharing is a care circle: invite-only, off by default, and strictly permission-checked.
<p align="center"> <img src="docs/images/ask-circle-demo.gif" alt="The same question asked on the shared record; the agent answers from a different person's files" width="880"> </p>Each of those three words is one check, and they all live in one function.
resolve_subject is the only way an account reaches a record that is not its
own — being in a circle together grants nothing by itself.
Truncated for display — read the full file on GitHub.
Related Skills
Agent-Reach
86.4kGive your AI agent eyes to see the entire internet. Read & search Twitter, Reddit, YouTube, GitHub, Bilibili, XiaoHongShu — one CLI, zero API fees.
headroom
74.2kCompress tool outputs, logs, files, and RAG chunks before they reach the LLM. 20% fewer tokens for coding agents, 60-95% fewer tokens for JSON, same answers. Library, proxy, MCP server.
ruflo
73.6k🌊 The original agent harness. Deploy intelligent multi-player swarms, coordinate autonomous workflows, and build conversational AI systems. Features adaptive memory, self-learning intelligence, federation, vector RAG integration, and native Claude Code / Codex / Hermes and many more Integrated
CowAgent
47.2kOpen-source personal AI assistant & Agent Harness. Plans tasks, runs tools and skills, self-evolves with memory and knowledge. Multi-agent, multi-model, multi-channel. Lightweight, extensible, one-line install.
Languages
Trust signals
From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.
