@pipeworx/ema-medicines
MCP serverEverything elseEMA Medicines MCP, the European Medicines Agency's public medicines register.
Available today. Use it from your connected AI after setup.
No other account needed.
Connect ahel once, and every AI you use reads what you have installed.
Then ask your AI: use @pipeworx/ema-medicines
From the project's README
As published by pipeworx-io/mcp-ema-medicines in README.md.
European Medicines Agency medicines register — every medicine authorised for the EU market through the centralised procedure, plus the committee opinions still awaiting a European Commission decision — the EMA's herbal-medicine inventory (plant/botanical substances the Committee on Herbal Medicinal Products (HMPC) has assessed, with links to each herb's EU herbal monograph and assessment-report PDFs) — and seven sibling XLSX reports from the same download-medicine-data page: shortages, direct healthcare professional communications (DHPC), referrals, periodic safety update single assessments (PSUSA), orphan designations, paediatric investigation plans, and post-authorisation procedures.
Part of Pipeworx — an MCP gateway connecting AI agents to 1576+ live data sources.
Tools
ema_recent_approvals(from?, to?, month?, category?, limit?)— new EU marketing authorisations in a date window. Answers "which drugs did the EMA approve in July 2026".ema_chmp_opinions(opinion_status?, since?, category?, include_decided?, limit?)— medicines the CHMP (human) or CVMP (veterinary) has recommended for or against approval and the Commission has not yet decided. Answers "what did the CHMP recommend this month".ema_medicine_search(query, status?, category?, orphan_only?, limit?)— search by brand name, INN / active substance, therapeutic area, indication text, ATC code or authorisation holder.ema_medicine(name)— the full published record for one medicine, by brand name or EMA product number.ema_recent_updates(since?, status?, category?, limit?)— register entries that changed most recently, including withdrawals and suspensions.herb_search(name?, latin?, botanical?, therapeutic_area?, status?, limit?)— search the EMA herbal-medicines inventory (plant/herb substances) by common name, Latin/botanical name, therapeutic area, or HMPC assessment status. Answers "which herbs has the EMA assessed for sleep disorders", "is there an EU herbal monograph for chamomile".herb(latin_name?, common_name?)— the full inventory record for one herb, plusmonograph_urlandassessment_report_urlscraped (link extraction only) from the herb's EMA page. Answers "what is the EMA monograph link for valerian root".herb_monograph_status(latin)— HMPC assessment status, code/label, and the outcome of the European assessment for one herb by Latin name; explains why well-established-use vs traditional-use is NOT a field the register carries (see below).ema_shortages(query?, status?, since?, limit?)— EU medicine shortages: status (ongoing/resolved/discontinued), forms/strengths affected, alternatives availability, start-of-shortage date. The EU counterpart of the FDA shortages tool.ema_dhpc(query?, dhpc_type?, since?, category?, limit?)— Direct Healthcare Professional Communications: urgent EU-wide safety alerts to prescribers (adverse events, quality defects, shortages, safety signals).ema_referrals(query?, status?, safety_only?, category?, since?, limit?)— EU referral procedures (Article 31/20/107i and related) — safety and scientific reviews of a medicine or substance class.ema_psusa(query?, outcome?, since?, limit?)— Periodic Safety Update Report Single Assessments: the EU-wide joint pharmacovigilance review per active substance.ema_orphan_designations(query?, status?, since?, limit?)— EU orphan medicinal product designations for rare-disease treatments (Positive/Withdrawn/Expired/Negative).ema_pip(query?, decision_type?, since?, limit?)— Paediatric Investigation Plans: the agreed/waived plan for studying a medicine in children.ema_post_authorisation(query?, status?, category?, since?, limit?)— post-marketing variations and label-change activity for centrally authorised medicines.
Auth
Keyless.
Data sources
- https://www.ema.europa.eu/en/documents/report/medicines-output-medicines-report_en.xlsx — the whole register as one XLSX, regenerated daily around 18:00 CET. Listed at https://www.ema.europa.eu/en/medicines/download-medicine-data alongside ten sibling reports (orphan designations, shortages, referrals, post-authorisation, DHPC, herbal, PSUSA, paediatric plans, MRLs).
- https://www.ema.europa.eu/en/documents/report/medicines-output-herbal_medicines-report_en.xlsx — the herbal-medicines inventory, same file family, regenerated daily. 251 data rows collapse to 204 distinct herbs (a handful of rows repeat identically 2-4x in the sheet;
herb_search/herbdedup on the per-herb page URL). Each row carries a per-herb page URL (https://www.ema.europa.eu/en/medicines/herbal/<latin-name-slug>) whose "Documents" section links the monograph and assessment-report PDFs thatherbscrapes. - Seven sibling reports, same file family and daily regeneration, listed on the same download page:
medicines-output-shortages-report_en.xlsx(ema_shortages)medicines-output-dhpc-report_en.xlsx(ema_dhpc)medicines-output-referrals-report_en.xlsx(ema_referrals)medicines-output-periodic_safety_update_report_single_assessments-report_en.xlsx(ema_psusa) — note the filename is NOTmedicines-output-psusa-report_en.xlsx; that guess 404s.medicines-output-orphan_designations-report_en.xlsx(ema_orphan_designations)medicines-output-paediatric_investigation_plans-report_en.xlsx(ema_pip)medicines-output-post_authorisation-report_en.xlsx(ema_post_authorisation)- Deliberately not built:
medicines-output-maximum_residue_limits-report_en.xlsx(veterinary residue limits, out of scope for this pack) andmedicines-output-opinions_outside_eu-report_en.xlsx(niche Article 58 scientific opinions on non-EU products).
Things worth knowing before you touch this
- Sheet layout is not row 1. Sheet
Medicine: row 1 is a provenance banner, rows 2–8 are blank, row 9 is the header (39 columns), rows 10+ are records. The header row uses inline strings, not shared strings — a parser that only resolves shared strings reads the header as blank. - Self-closing cells are a trap.
<c r="E10" s="1"/>is an empty cell. A greedy attribute match in the cell regex swallows the/and runs on to the next cell's</c>, silently shifting every value in the row by one column.src/xlsx.tsuses a lazy match for exactly this reason. - Use
Marketing authorisation datefor "new approvals", notEuropean Commission decision date. The Commission decision date also moves on post-authorisation variations — 80–141 rows a month — while genuine initial authorisations run 4–12 a month. Filtering on the wrong one answers a different question without looking wrong. - The committees meet monthly, so "what did the CHMP recommend this month" lands on an empty window most of the time. When
sincefilters everything out,ema_chmp_opinionsreturns the outstanding opinions and states inwindow_notethat none were adopted in the window asked for — the question is about the pipeline, not the calendar. Opinion statusalone does not mean "pending". Authorised and withdrawn products keep their historical opinion fields. Pending meansMedicine statusstarts withOpinion;ema_chmp_opinionsapplies that by default and exposesinclude_decidedto widen it.- EMA rate-limits bursts and answers a 429 with ~40 KB of HTML rather than JSON — reproduced at five sequential requests. A per-call download is not viable, so the pack holds one parsed copy for six hours and the Cloudflare edge cache absorbs repeats on top of that. If a refresh fails while an earlier copy is in hand, the earlier copy is served rather than an error.
- Dates are
DD/MM/YYYYupstream and are converted to ISO on the way out. data.europa.euis not a route to this data. The EMA datasets are still listed there but frozen atmodified: 2019-01-09, and every distribution URL 404s against the pre-redesign/sites/default/files/Medicines_output_*.xlsxpath.- The register covers the EU centralised procedure only — nationally authorised products are not in it.
The 7 sibling reports — things worth knowing
- The PSUSA filename does not match its tool/report name. It is
medicines-output-periodic_safety_update_report_single_assessments-report_en.xlsx, notmedicines-output-psusa-report_en.xlsx— the latter guess 404s. Verified by fetchingen/medicines/download-medicine-dataand grepping the actual<a href>list rather than guessing the pattern from the other reports' names. post_authorisation's URL column isAA, out of alphabetical order with the rest of the header row (A, AA, B, C, ...Z). The generic loader reads whatever column letter the sheet XML actually uses per header cell, so this is harmless — but do not "fix" it by assuming A..Z order if you ever hand-edit the field map.orphan_designationshas noCategorycolumn at all (the register is human-only) — unlikedhpc,referralsandpost_authorisation, which are a Human/Veterinary mix and take acategoryfilter.- A rare EMA source-data artifact, not a parser bug: PSUSA's own export occasionally splits one comma-containing active-substance string into two adjacent shared-string cells with a stray embedded
"(~0.2% of rows, e.g.dienogest/ethinylestradiol (prolonged-release tablet)"as two separate cells) — those rows still parse, just with a slightly garbledcategory/substances_in_scopevalue. Not worth a special case for a handful of rows. - Each report gets its own
ReportSpec(URL, column-header → field map, date fields) fed through one genericloadReport()/reportDataset()pair — same row-9-is-the-header parsing and same one-download-per-six-hours cache as the main register and the herbal inventory, just parameterised instead of copy-pasted seven times. - All seven probed live 2026-09-13 with real current rows (e.g. shortages: Eskazole/Zentel ongoing since 2026; DHPC: a Jentadueto quality-defect notice dated 2026-08-20; orphan designations: a satralizumab positive designation dated 2026-06-22).
Herbal tools — things worth knowing
- Same sheet layout, different columns. Row 1 banner, row 9 is the header, rows 10+ records. Columns: Latin name, Combination, English common name, Botanical name, Therapeutic area, Status, Outcome of European assessment, Additional information, three date columns, and
Herbal medicine URL(the per-herb page). - The sheet repeats some herbs' rows identically. Fragariae folium appears 4 times with byte-identical values across every column;
loadHerbal()dedups on the per-herb page URL (204 distinct herbs from 251 data rows, verified 2026-09-07). - The per-herb page URL slug is the LATIN name, not the common name (
valerianae-radix, notvalerian-root) — a couple of herbs get a-0suffix (taraxaci-officinalis-radix-0) for reasons EMA doesn't document. herbscrapes links, not prose. A herb's EMA page lists every revision's documents as plain relativehrefs under/en/documents/<category>/<filename>_en.pdf. The path category tells you the document type (herbal-monograph= the monograph,herbal-report= the assessment report — the only two categoriesherbreads); the filename prefix tells you its currency (final-beatsdraft-beats anything startingsuperseded).herbpicks the best-ranked link per category. It does not read the page's prose sections — the FAQ-style "well-established use" / "traditional use" explainer text lives there but scraping it is out of scope for this pack.- The register does not carry a well-established-use vs traditional-use field, at all. Checked every distinct value of
Outcome of European assessmentacross the full 2026-09-07 sheet:European Union herbal monograph,European Union herbal monograph;European Union list entry,European Union list entry,Public statement— none of the four say which use category applies. That classification is set per-indication inside the monograph document itself (Article 10a "well-established use" vs Article 16a "traditional use"), and a single herb can carry both for different indications — valerian root's monograph, for instance, is well-established use for mild nervous tension and sleep, and traditional use for mild mental stress.herb_monograph_statusreturnsuse_classification: nullwith a note explaining this, rather than guessing from prose. - A herb without a finalised assessment can still have a final monograph. Assessment
status(F/P/C/D/R) tracks the periodic-review cycle, not first publication —Taraxaci officinalis radixcarriesR: Rapporteur assigned(an ongoing review) but its page already has afinal-monograph and assessment report from years earlier. Rank on the filename prefix, never on the register'sstatusfield. - An early-stage herb may have no assessment report yet.
Cannabis flos(D: Draft under discussion) has only adraft-public-statement-*.pdfunderherbal-monographand nothing at all underherbal-report—herbreturnsassessment_report_url: nullrather than erroring.
Quick Start
Add to your MCP client (Claude Desktop, Cursor, Windsurf, etc.):
{
"mcpServers": {
"ema-medicines": {
"url": "https://gateway.pipeworx.io/ema-medicines/mcp"
}
}
}
What this endpoint actually serves
tools/list at https://gateway.pipeworx.io/ema-medicines/mcp returns the tools in the table
above plus the shared Pipeworx meta-tools — ask_pipeworx,
discover_tools, search_within, remember/recall and the rest of the
gateway-wide set. So the tool count you see is larger than this table: a
single-pack endpoint currently lists roughly 30 shared tools alongside the
pack's own. The connection's initialize response states its exact scope, and
is the authoritative answer for a given day.
This is deliberate, not multiplexing by accident. The meta-tools are what let a
scoped connection answer a question this pack does not cover — via
ask_pipeworx, which routes across the whole catalog — without you adding a
second MCP server. There is currently no way to mount a pack endpoint without
them; if the extra schemas cost you more context than the routing is worth,
connect to the full gateway once rather than to several pack endpoints.
Or connect to the full Pipeworx gateway to get every pack's tools listed directly, instead of just this one's:
{
"mcpServers": {
"pipeworx": {
"url": "https://gateway.pipeworx.io/mcp"
}
}
}
Both URLs reach the same gateway and the same 1576+ data sources. The
only difference is which pack's tools are listed directly; ask_pipeworx
reaches all of them from either one.
Standalone (no gateway account)
This package also runs as a local stdio MCP server — no Pipeworx account, no gateway round-trip:
{
"mcpServers": {
"ema-medicines": {
"command": "npx",
"args": ["-y", "@pipeworx/mcp-ema-medicines"]
}
}
}
Or run it directly to confirm it starts:
npx -y @pipeworx/mcp-ema-medicines
It speaks MCP over stdin/stdout and answers initialize/tools/list/tools/call
for only this pack's tools — none of the shared meta-tools the gateway
connection above adds. Same source, same tools, no ask_pipeworx routing.
Using with ask_pipeworx
Instead of calling tools directly, you can ask questions in plain English — this works on the pack endpoint above as well as on the full gateway:
ask_pipeworx({ question: "your question about Ema Medicines data" })
The gateway picks the right tool and fills the arguments automatically.
More
License
MIT
Advanced
- Delivery
- ema-medicines MCP server → your ahel gateway (mcp.ahel.ai) → every connected AI client.
- Catalog kind
- mcp-server
- Gateway key
io-github-pipeworx-io-ema-medicines- Source
- github.com/pipeworx-io/mcp-ema-medicines
- Hosted endpoint
https://gateway.pipeworx.io/ema-medicines/mcp