@pipeworx/herb-tcm
Connect: https://gateway.pipeworx.io/herb-tcm/mcp · Install: one-click buttons
Tools: 7
HERB 2.0’s Traditional Chinese Medicine knowledge base — herbs, ingredients,
gene targets, diseases, PubMed-cited papers and GEO transcriptomic
experiments — proxied live from herb.ac.cn, with every relationship row
tagged an evidence_tier so a statistical prediction is never mistaken for
proof of efficacy.
Tools
herb_search(keyword, category?)— resolve a name to an id. Accepts Chinese characters, pinyin, English/Latin names, gene names/aliases, disease names, or a HERB id itself.categoryis one ofherb/ingredient/target/disease(defaultherb).herb_browse(category, page?, page_size?)— page through the full herb/ingredient/target/disease list (7,263 / 49,258 / 12,933 / 28,212 rows respectively).herb_detail(id, category)— the full record for one id: composition, traditional-use summary, and every predicted or literature-backed target/disease relationship, each carrying itsevidence_tier.herb_papers(drug_type?, experiment_type?, sort_by?, limit?, offset?)— list PubMed-cited references, each taggedhuman_clinicalorlaboratory.herb_paper_detail(paper_id)— one reference’s bibliographic record plus the specific targets/diseases it reports.herb_experiments(drug_type?, species?, experiment_type?, limit?, offset?)— list GEO-deposited herb/ingredient-vs-control transcriptomic experiments.herb_experiment_detail(experiment_id)— differential-expression results for one experiment: top up/down genes, enriched GO/KEGG terms, connectivity-map hit counts. Alwaysevidence_tier: computational_prediction.
Evidence tiers
Every relationship row carries one of:
| Tier | Meaning |
|---|---|
traditional_use | From the herb’s Pharmacopoeia-style summary (Function/Indication/Meridians). Historical use, not a trial. |
human_clinical | A PubMed-cited paper whose HERB-assigned “Experiment type” includes “Clinical Experiment” — it studied humans. |
laboratory | A PubMed-cited paper studying cells or animals only. |
computational_prediction | A statistical enrichment or database cross-reference with no clinical or experimental confirmation. This is a hypothesis, not evidence the herb/ingredient treats anything. |
compositional_fact | ”This ingredient occurs in this herb” — a composition fact, not an efficacy claim at all. |
herb_target / herb_disease (statistical enrichment, p-value + FDR_BH
columns), ingredient_target / ingredient_disease / target_disease
(curated cross-references with no clinical backing) and every
herb_experiment_detail row are computational_prediction.
drug_paper_target / drug_paper_disease (PubMed-cited) are split into
human_clinical or laboratory by resolving each cited paper’s own
“Experiment type” — see Data sources below for how.
Auth
Keyless. herb.ac.cn requires no account, token or payment — it is public data served to anyone.
Data sources
http://herb.ac.cn/chedi/api/— herb.ac.cn is a umi single-page app with no REST surface (every path returns the same ~900-byte shell). The real API is this one POST endpoint, dispatching on afunc_namebody field, found in the site’s own JS bundle (http://herb.ac.cn/static/umi.js). Seven verbs, confirmed live 2026-09-08:search_api,detail_api,browse_api,paper_api,paper_detail_api,experiment_api,experiment_detail_api.
Notes for the next person:
- http only, and Chinese-hosted — measured 200ms-1.5s per call from this
session but expect latency and occasional unreachability; several
.cnsources are known-flaky from our vantage. This is a known class, not a bug — report it rather than retrying hard. - Every response is served as
text/html, including successful ones — do not branch onContent-Type. The only reliable signal for “no such id” is the HTTP status: a badkey_id/label/paper_key_id/drug_GSE_idreturns HTTP 500 with an HTML “Internal Server Error” page; an unknownfunc_namereturns HTTP 200 with the literal bodynull.parseJson/httpErrorfrom@pipeworx/sharedhandle both shapes. - Cells in every table are either a plain value or
{link, title}/{style, title}— even header cells in the differential-expression tables come this way ({filterable, sortable, title}).tableToRowsinsrc/index.tsunwraps every shape to a plain string/number. detail_apineeds three params, not just the id:key_id,label(must match the id’s category —HERB…ids needlabel: "Herb", etc.) andv(the site’s own UI passes the id again under this name; omitting it was not tested and isn’t worth risking).drug_paper_target/drug_paper_diseaserows (insideherb_detail) carry a Paper id but not that paper’s own experiment type, and a cited herb can reference 20-100+ papers. Rather than firing onepaper_detail_apicall per paper (impolite fan-out against a slow host),herb_detailmakes ONE extra call topaper_apiunfiltered — which returns HERB’s entire ~2,000-row reference index including “Experiment type” per id — and resolves the tier from that in-memory lookup. Nothing from it is cached across tool calls; it is refetched live every timeherb_detailneeds it.Ingredient_alias(inside an ingredient’sdetail_apiresponse) is not a table — it’s a one-element array holding one semicolon-joined string of synonyms. Treating it as a table throws (table[0].map is not a function); split on;instead.experiment_detail_api’sExperiment_detailfield nests everything one level deeper than expected: it’s an object with exactly one key, named “HBEXP000001 Data Detail” (the experiment id plus a fixed suffix), whose value is{ data: {...} }. The differential-expression/GO/KEGG/CMAP tables live under that single value’sdatafield —src/index.tsgrabs it withObject.values(...)[0]?.datarather than building the key string, since the exact suffix isn’t documented anywhere.paper_apiandexperiment_apihave no server-side pagination — each call returns the FULL filtered list (~2,000 papers / ~1,000 experiments unfiltered) in one response.herb_papers/herb_experimentsslice client-side withlimit/offset; a tighterdrug_type/experiment_typefilter reduces what herb.ac.cn itself has to compute and send.- Licensing: settled by Bruce, fleet #1389 (2026-09-08) — a live per-request proxy call is a client, not a publisher, so it needs no explicit reuse grant the way bulk-copying the dataset would. This pack must stay a proxy: no bulk download, no full local mirror, no cached complete copy of herb.ac.cn’s data.
Tools
- herb_search — Search HERB 2.0 for a herb, ingredient, gene target or disease by Chinese name, pinyin, English name,
- herb_browse — Page through HERB 2.0’s full herb, ingredient, target or disease list (7,263 herbs / 49,258 ingredients /
- herb_detail — Full record for one HERB id: herb (composition + traditional-use summary + predicted and literature
- herb_papers — List PubMed-cited papers in HERB’s reference index — the literature backing herb/ingredient-target and
- herb_paper_detail — One reference’s bibliographic record (journal, PubMed id, experiment type, phenotype) plus the specific
- herb_experiments — List HERB’s transcriptomic experiments (herb/ingredient treatment vs. control, GEO-deposited) — the raw
- herb_experiment_detail — Differential-expression results for one HERB transcriptomic experiment: top up/down-regulated genes and
Tools
-
herb_browse— Page through HERB 2.0's full herb, ingredient, target or disease list (7,263 herbs / 49,258 ingredients / -
herb_detail— Full record for one HERB id: herb (composition + traditional-use summary + predicted and literature -
herb_experiment_detail— Differential-expression results for one HERB transcriptomic experiment: top up/down-regulated genes and -
herb_experiments— List HERB's transcriptomic experiments (herb/ingredient treatment vs. control, GEO-deposited) — the raw -
herb_paper_detail— One reference's bibliographic record (journal, PubMed id, experiment type, phenotype) plus the specific -
herb_papers— List PubMed-cited papers in HERB's reference index — the literature backing herb/ingredient-target and -
herb_search— Search HERB 2.0 for a herb, ingredient, gene target or disease by Chinese name, pinyin, English name,