③ Answers
Built-in Tools
The four MCP tools the engine ships — terminology, health records and genetics — plus what DeepAgent gets from its harness.
Every tool below is an ordinary Python method that runtime discovery picked up. Nothing here is special-cased by the engine, and nothing here is compiled in: the same rules that find these would find yours.
The MCP surface is small on purpose. Four tools ship, and the authoritative list is whatever your own server reports — ask it:
curl -X POST http://localhost:18080/mcp \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'The four tools come in three groups: terminology resolution (resolve_indicator, normalize_unit), health-record reads (query_health_indicators) and genetic-data reads (get_genetic_data). Two of the four need nothing — no account, no network, no key — and two are bound to the caller’s own records:
| Tool | What it does | Needs |
|---|---|---|
resolve_indicator | any-language indicator name → canonical LOINC | nothing — offline, no user data |
normalize_unit | free-text unit → canonical UCUM + comparability family | nothing — offline, no user data |
query_health_indicators | the caller’s own records: search, read and aggregate in one call | the account |
get_genetic_data | the caller’s variants by rsID | the account |
Terminology — the ② Standardize surface
Section titled “Terminology — the ② Standardize surface”These two tools give the model a way to put a name on the same footing as a code. “LDL cholesterol”, “低密度脂蛋白胆固醇” and “LDL-C” are three strings for one measurement; both tools turn any of them into the same canonical identity. Neither reads user data, so they work for an anonymous caller and disclose nothing.
Resolution runs against the bundles shipped inside the package. A client can be air-gapped and these still answer, which is exactly the property health data deserves.
resolve_indicator
Section titled “resolve_indicator” names string[] required
Names exactly as printed. Pass the whole batch in one call.
Returns one result per input, in order: name unchanged, resolved, loinc (e.g. 718-7, empty when unresolved), canonical (the LOINC long common name) and candidates — how many corpus rows matched. A large candidates count means genuine ambiguity, and one sensible default was chosen; surface that when precision matters.
Three properties the model is told about explicitly, because they change how an answer should be written:
- Unresolved is an honest “no”. Report the name as unmatched; never invent a code.
- Panel names deliberately do not resolve.
blood pressureand血圧name a panel, not an observation — the right response is to ask which measurement (systolic or diastolic). - The same code from two names means the same test. That, not string equality, decides whether two readings are comparable.
normalize_unit
Section titled “normalize_unit” units string[] required
Unit strings as printed, e.g. ["mg/dL", "毫摩尔每升", "次/分"]. Up to 200 per call.
Returns unit unchanged, ucum (canonical form; empty means unrecognized) and family — the LOINC PROPERTY, e.g. SCnc.
- "MG/DL"
- ucum "mg/dL" · family "MCnc"
- "毫摩尔每升"
- ucum "mmol/L" · family "SCnc"
The family is the point: units in the same family are convertible, and converting across families is a category error, not arithmetic.
Health records
Section titled “Health records”query_health_indicators
Section titled “query_health_indicators”This single tool combines search, read and aggregate in one call, and every result carries its canonical identity.
keywords string[]
Fuzzy terms, any language. For shorthand, include both forms — ["MCHC", "Mean Corpuscular Hemoglobin Concentration"].
indicators string[]
Exact names from a previous call. Use instead of keywords, not alongside guesses.
start_time string
Inclusive start date, YYYY-MM-DD.
end_time string
Inclusive end date, YYYY-MM-DD.
aggregate string default: none
One of none, stats, day, week, month — declared as an enum in the schema, so an invalid value is rejected before any engine code runs. stats returns count/min/max/avg/first/last/change per indicator; a bucket returns one point per bucket. Trend questions should use one of those rather than pulling raw readings.
limit integer default: 50
Maximum readings per indicator when aggregate is none. Bounded at 500 in the schema itself.
The response is shaped so the model can keep going without guessing:
| Field | What it is |
|---|---|
indicators | Per match: indicator (the exact name, reusable as indicators), system / code (the canonical identity — same code means the same test, whatever the names), count, and rows as a pipe-delimited table. A leading (constants: k=v) line carries columns identical on every row, typically the unit. |
catalog | Returned instead of indicators when no filter was given, and also when nothing matched — it lists what this user actually has, so the model picks from reality rather than re-guessing keywords. |
truncated | Indicator → total available, when a series was cut by limit. The fix is a narrower window or an aggregate, not a bigger limit. |
Genetics
Section titled “Genetics”get_genetic_data
Section titled “get_genetic_data” rsid string | string[] required
dbSNP identifiers — "rs4988235" or ["rs1801133", "rs429358"]. A comma-separated string also works.
limit integer default: 100
Maximum variants returned.
include_nearby boolean default: true
Also return variants within nearby_range of each hit, capped at 20 per hit. Set false for exact lookups only.
nearby_range integer default: 1000000
Half-window in base pairs.
This reads the user’s own uploaded genotype file, not a reference database. Consumer arrays type a small fraction of the genome, so absent ≠ negative: an rsID missing from the result was not typed, and says nothing about the allele.
Additional tools from the DeepAgent harness
Section titled “Additional tools from the DeepAgent harness”Two tools on the list above are not the whole story for DeepAgent: its deepagents harness contributes more, and those extras are not MCP tools — an outside MCP client does not see them.
| From the harness | What it is |
|---|---|
ls · read_file · write_file · edit_file · glob · grep | The native file tools, operating on the PostgreSQL-backed virtual filesystem. read_file on an uploaded PDF hands the model the original document, multimodally, instead of a lossy extraction. |
eval | A persistent, in-process JavaScript REPL from langchain-quickjs — how the model does real computation over data it fetched. |
| Agent Skills | Not tools: SKILL.md procedures injected as frontmatter and read in full only when a task calls for it. See Agent Skills. |
delete is excluded by name because the PostgreSQL filesystem backend does not implement it. There is no task subagent and no write_todos.
Next steps
Section titled “Next steps”Your own tool is one .py file — including the identity-injection rule
Which agent sees which tools, and who runs the loop
Reaching these tools from Claude Desktop, Cursor or your own client
What “canonical identity” means, and how the resolver is scored