@pharmatools/pubcrawl 2.5.1 → 2.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -13,6 +13,7 @@ _A peer-reviewed pub crawl through the literature — the label — and the tria
13
13
  [![downloads](https://img.shields.io/npm/dm/@pharmatools/pubcrawl?color=cb3837)](https://www.npmjs.com/package/@pharmatools/pubcrawl)
14
14
  [![node](https://img.shields.io/node/v/@pharmatools/pubcrawl?color=339933&logo=node.js&logoColor=white)](https://nodejs.org)
15
15
  [![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed-6E56CF)](https://registry.modelcontextprotocol.io/?q=pubcrawl)
16
+ [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.22101559.svg)](https://doi.org/10.5281/zenodo.22101559)
16
17
  [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE)
17
18
  [![PRs welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](CONTRIBUTING.md)
18
19
 
@@ -32,6 +33,8 @@ Every tool is a thin, deterministic wrapper over an official API. Nothing is inv
32
33
 
33
34
  Ask **"compare US and UK labelling for semaglutide"** and PubCrawl pulls both live labels and maps equivalent sections — US *Indications and Usage* ↔ UK *4.1 Therapeutic indications*, and so on — so the differences are visible instead of assumed:
34
35
 
36
+ ![Asking an MCP client to compare US and UK labelling for semaglutide: PubCrawl calls compare_labels, fetches the US Prescribing Information from openFDA/DailyMed and the UK SmPC from the eMC, and returns the two indication lists side by side — three US indications including cardiovascular and renal risk reduction, against one UK indication, with the cardiovascular and renal outcomes appearing only as cross-references to sections 4.4, 4.5 and 5.1.](docs/demo-compare-labels.gif)
37
+
35
38
  | | US Prescribing Information | UK SmPC |
36
39
  |---|---|---|
37
40
  | **Indications** | glycaemic control · **reduce risk of MACE** in T2D with established CVD · **reduce risk of sustained eGFR decline, ESKD and CV death** in T2D with CKD | glycaemic control only — CV and renal outcomes appear as cross-references to §4.4/4.5/5.1, *not* as indications |
@@ -45,7 +48,7 @@ A cardiovascular claim that is on-label in the US promotes an unlicensed indicat
45
48
  - 🧾 **Verifiable by design** — results link back to DailyMed, the eMC, PubMed, and ClinicalTrials.gov
46
49
  - 📰 **Preprints** via Europe PMC — surface work ahead of formal publication
47
50
  - 🆓 **No API keys required** (an optional free NCBI key raises PubMed rate limits)
48
- - 🧪 Fully **typed, tested, and CI-checked** — retrieval fidelity gated by [OpenGATE](https://github.com/nickjlamb/opengate) on every release
51
+ - 🧪 Fully **typed, tested, and CI-checked** — literature retrieval gated by [OpenGATE](https://github.com/nickjlamb/opengate), and labelling & trials by the in-repo [fidelity benchmark](benchmark/README.md), on every release
49
52
 
50
53
  Built by [PharmaTools.AI](https://pharmatools.ai).
51
54
 
@@ -102,7 +105,7 @@ That's it. → [More examples](#-examples) · [API key & other options](#-config
102
105
  | `resolve_drug_name` | Convert a brand drug name to its generic (or a generic to its US brand names), with drug class and common indications. Deterministic, via RxNorm/openFDA — no AI. |
103
106
  | `get_uspi` | Pull US Prescribing Information sections via openFDA (cited to DailyMed) — indications, dosing, warnings, contraindications, and more. |
104
107
  | `get_smpc` | Retrieve UK Summary of Product Characteristics from the eMC — the UK equivalent of US prescribing information, with numbered SmPC sections. |
105
- | `compare_labels` | Side-by-side comparison of US (USPI) and UK (SmPC) labelling for the same drug. Spot regulatory differences in indications, warnings, and dosing. |
108
+ | `compare_labels` | Side-by-side comparison of US (USPI) and UK (SmPC) labelling for the same drug, pairing equivalent sections (US Indications ↔ UK 4.1). A missing side is always explained, cut sections are flagged `truncated`, and `us_drug` / `uk_drug` pin a different name per market (Farxiga / Forxiga). |
106
109
  | `search_by_indication` | Find drugs approved for a medical condition. Searches FDA labelling via openFDA, then cross-references UK availability on the eMC. |
107
110
 
108
111
  ### 🧫 Clinical trials
@@ -226,7 +229,16 @@ npm test # Vitest unit suite
226
229
  npm run lint # ESLint
227
230
  ```
228
231
 
229
- Unit tests live in `tests/` and cover the parsing, caching, citation, and formatting logic with fixture payloads (no network calls). CI runs lint → test → build on every push and pull request. New to the codebase? Start with [`CONTRIBUTING.md`](CONTRIBUTING.md).
232
+ Unit tests live in `tests/` and cover the parsing, caching, citation, formatting and label-pairing logic with fixture payloads (no network calls). CI runs lint → test → build on every push and pull request. New to the codebase? Start with [`CONTRIBUTING.md`](CONTRIBUTING.md).
233
+
234
+ ### Measuring fidelity
235
+
236
+ ```bash
237
+ npm run bench # labelling + trials fidelity benchmark against the live sources
238
+ npm run bench -- --ci # what the release gate runs: exit 1 if a verified case fails
239
+ ```
240
+
241
+ Two gates run on every release and weekly. [OpenGATE](https://github.com/nickjlamb/opengate)'s retrieval scorer checks PubMed and Europe PMC records against hand-verified anchors. The in-repo [fidelity benchmark](benchmark/README.md) does the same for drug labelling and trials: `compare_labels` is held to a gold set of US/UK anchors (a phrase must appear on one side and must *not* on the other, so real divergences are surfaced rather than smoothed over) plus a verbatim check that refetches the raw openFDA record and eMC page and confirms every returned sentence is a substring of the source. No LLM judge anywhere in either gate.
230
242
 
231
243
  ---
232
244
 
@@ -244,9 +256,12 @@ If PubCrawl supports work you publish, please cite it — see [`CITATION.cff`](C
244
256
 
245
257
  ```bibtex
246
258
  @software{lamb_pubcrawl,
247
- author = {Lamb, Nick},
248
- title = {PubCrawl: verifiable biomedical literature, drug labelling and clinical trials for AI assistants},
249
- url = {https://github.com/nickjlamb/pubcrawl}
259
+ author = {Lamb, Nick},
260
+ title = {PubCrawl: verifiable biomedical literature, drug labelling and clinical trials for AI assistants},
261
+ year = {2026},
262
+ publisher = {Zenodo},
263
+ doi = {10.5281/zenodo.22101559},
264
+ url = {https://doi.org/10.5281/zenodo.22101559}
250
265
  }
251
266
  ```
252
267
 
@@ -5,4 +5,14 @@ export interface SectionMapping {
5
5
  }
6
6
  export declare const SECTION_MAP: SectionMapping[];
7
7
  export declare function filterSectionMap(requestedTopics?: string[]): SectionMapping[];
8
+ /**
9
+ * The shared engine caps each section's text (currently 1,400 characters) and
10
+ * appends " …" when it does. Mark those sections so callers know the text is
11
+ * verbatim but incomplete.
12
+ */
13
+ export declare function markTruncated<T extends {
14
+ content: string;
15
+ }>(sections: T[]): (T & {
16
+ truncated?: boolean;
17
+ })[];
8
18
  //# sourceMappingURL=label-mapping.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"label-mapping.d.ts","sourceRoot":"","sources":["../../src/lib/label-mapping.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,WAAW,EAAE,cAAc,EAUvC,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAc7E"}
1
+ {"version":3,"file":"label-mapping.d.ts","sourceRoot":"","sources":["../../src/lib/label-mapping.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,cAAc;IAC7B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,WAAW,EAAE,cAAc,EAUvC,CAAC;AA4BF,wBAAgB,gBAAgB,CAAC,eAAe,CAAC,EAAE,MAAM,EAAE,GAAG,cAAc,EAAE,CAG7E;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS;IAAE,OAAO,EAAE,MAAM,CAAA;CAAE,EAAE,QAAQ,EAAE,CAAC,EAAE,GAAG,CAAC,CAAC,GAAG;IAAE,SAAS,CAAC,EAAE,OAAO,CAAA;CAAE,CAAC,EAAE,CAE3G"}
@@ -9,15 +9,46 @@ export const SECTION_MAP = [
9
9
  { topic: "Overdosage", us_loinc: "34088-5", uk_code: "4.9" },
10
10
  { topic: "Clinical Pharmacology", us_loinc: "34090-1", uk_code: "5.1" },
11
11
  ];
12
+ const words = (s) => s.split(/[^a-z0-9.]+/).filter(Boolean);
13
+ /**
14
+ * Does a requested topic name refer to this mapping?
15
+ *
16
+ * Matches on the whole topic, a prefix of it ("indic" -> Indications), one of
17
+ * its words ("interactions" -> Drug Interactions), or the topic appearing as a
18
+ * whole word in a longer request ("special warnings and precautions" ->
19
+ * Warnings). Deliberately not a bare substring test: "indications" must not
20
+ * also select Contraindications.
21
+ */
22
+ function topicMatches(mapping, request) {
23
+ const topic = mapping.topic.toLowerCase();
24
+ const req = request.toLowerCase().trim();
25
+ if (!req)
26
+ return false;
27
+ if (req === mapping.us_loinc || req === mapping.uk_code)
28
+ return true;
29
+ if (topic === req || topic.startsWith(req))
30
+ return true;
31
+ const topicWords = words(topic);
32
+ const reqWords = words(req);
33
+ if (topicWords.includes(req))
34
+ return true;
35
+ if (reqWords.includes(topic))
36
+ return true;
37
+ // whole-phrase, word-bounded containment ("warnings and precautions" ⊇ "warnings")
38
+ const phrase = new RegExp(`(^|[^a-z0-9])${topic.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}([^a-z0-9]|$)`);
39
+ return phrase.test(req);
40
+ }
12
41
  export function filterSectionMap(requestedTopics) {
13
42
  if (!requestedTopics || requestedTopics.length === 0)
14
43
  return SECTION_MAP;
15
- return SECTION_MAP.filter((mapping) => requestedTopics.some((req) => {
16
- const lower = req.toLowerCase().trim();
17
- return (mapping.topic.toLowerCase().includes(lower) ||
18
- lower.includes(mapping.topic.toLowerCase()) ||
19
- mapping.us_loinc === req ||
20
- mapping.uk_code === req);
21
- }));
44
+ return SECTION_MAP.filter((mapping) => requestedTopics.some((req) => topicMatches(mapping, req)));
45
+ }
46
+ /**
47
+ * The shared engine caps each section's text (currently 1,400 characters) and
48
+ * appends " …" when it does. Mark those sections so callers know the text is
49
+ * verbatim but incomplete.
50
+ */
51
+ export function markTruncated(sections) {
52
+ return sections.map((s) => (/\u2026\s*$/.test(s.content) ? { ...s, truncated: true } : s));
22
53
  }
23
54
  //# sourceMappingURL=label-mapping.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"label-mapping.js","sourceRoot":"","sources":["../../src/lib/label-mapping.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,WAAW,GAAqB;IAC3C,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IAC7D,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IACxD,EAAE,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IACnE,EAAE,KAAK,EAAE,UAAU,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IAC1D,EAAE,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IACnE,EAAE,KAAK,EAAE,WAAW,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IAC3D,EAAE,KAAK,EAAE,mBAAmB,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IACnE,EAAE,KAAK,EAAE,YAAY,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;IAC5D,EAAE,KAAK,EAAE,uBAAuB,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,KAAK,EAAE;CACxE,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAAC,eAA0B;IACzD,IAAI,CAAC,eAAe,IAAI,eAAe,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,WAAW,CAAC;IAEzE,OAAO,WAAW,CAAC,MAAM,CAAC,CAAC,OAAO,EAAE,EAAE,CACpC,eAAe,CAAC,IAAI,CAAC,CAAC,GAAG,EAAE,EAAE;QAC3B,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QACvC,OAAO,CACL,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC;YAC3C,KAAK,CAAC,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,WAAW,EAAE,CAAC;YAC3C,OAAO,CAAC,QAAQ,KAAK,GAAG;YACxB,OAAO,CAAC,OAAO,KAAK,GAAG,CACxB,CAAC;IACJ,CAAC,CAAC,CACH,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"label-mapping.js","sourceRoot":"","sources":["../../src/lib/label-mapping.ts"],"names":[],"mappings":"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"}
@@ -1,11 +1,35 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import { CompareLabelsResult } from "../types.js";
2
+ import { CompareLabelsResult, LabelSection } from "../types.js";
3
+ /** Minimal shape of a fetched label, as the shared engine returns it. */
4
+ interface FetchedLabel {
5
+ drugName: string;
6
+ sections: LabelSection[];
7
+ }
8
+ /** The two fetchers, injectable so the pairing logic can be tested offline. */
9
+ export interface LabelFetchers {
10
+ getUsLabel: (drug: string, codes: string[]) => Promise<(FetchedLabel & {
11
+ dailymedUrl: string;
12
+ }) | null>;
13
+ getUkSmpc: (drug: string, codes: string[]) => Promise<(FetchedLabel & {
14
+ url: string;
15
+ }) | null>;
16
+ }
3
17
  /**
4
18
  * Build a CompareLabelsResult by fetching both labels from the shared engine and
5
19
  * pairing equivalent sections (US LOINC <-> UK section number). Cached for 24h.
20
+ *
21
+ * A null section is never left unexplained: the paired *_note says whether the
22
+ * whole label was unavailable or the label was retrieved but lacks that section.
6
23
  */
7
- export declare function buildCompareResult(drug: string, sections?: string[]): Promise<CompareLabelsResult | {
24
+ export interface CompareNames {
25
+ /** Name used for the US lookup; defaults to `drug`. */
26
+ us?: string;
27
+ /** Name used for the UK lookup; defaults to `drug`. */
28
+ uk?: string;
29
+ }
30
+ export declare function buildCompareResult(drug: string, sections?: string[], fetchers?: LabelFetchers, names?: CompareNames): Promise<CompareLabelsResult | {
8
31
  error: string;
9
32
  }>;
10
33
  export declare function registerCompareLabelsTool(server: McpServer): void;
34
+ export {};
11
35
  //# sourceMappingURL=compare-labels.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"compare-labels.d.ts","sourceRoot":"","sources":["../../src/tools/compare-labels.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EAAmB,mBAAmB,EAAE,MAAM,aAAa,CAAC;AAYnE;;;GAGG;AACH,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,mBAAmB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CA0ClD;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuBjE"}
1
+ {"version":3,"file":"compare-labels.d.ts","sourceRoot":"","sources":["../../src/tools/compare-labels.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EACL,mBAAmB,EAEnB,YAAY,EAEb,MAAM,aAAa,CAAC;AAoBrB,yEAAyE;AACzE,UAAU,YAAY;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,YAAY,EAAE,CAAC;CAC1B;AAED,+EAA+E;AAC/E,MAAM,WAAW,aAAa;IAC5B,UAAU,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,CAAC,YAAY,GAAG;QAAE,WAAW,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC,CAAC;IACxG,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,OAAO,CAAC,CAAC,YAAY,GAAG;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAC,GAAG,IAAI,CAAC,CAAC;CAChG;AAuBD;;;;;;GAMG;AACH,MAAM,WAAW,YAAY;IAC3B,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,uDAAuD;IACvD,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAED,wBAAsB,kBAAkB,CACtC,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,EACnB,QAAQ,GAAE,aAA+B,EACzC,KAAK,GAAE,YAAiB,GACvB,OAAO,CAAC,mBAAmB,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAuElD;AAED,wBAAgB,yBAAyB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA0BjE"}
@@ -1,59 +1,109 @@
1
1
  import { z } from "zod";
2
2
  import { getUsLabel, getUkSmpc } from "@pharmatools/drug-data";
3
3
  import { cache, TTL } from "../lib/cache.js";
4
- import { filterSectionMap } from "../lib/label-mapping.js";
4
+ import { filterSectionMap, markTruncated } from "../lib/label-mapping.js";
5
5
  const schema = {
6
6
  drug: z.string().describe("Drug name to compare across US and UK labelling"),
7
+ us_drug: z
8
+ .string()
9
+ .optional()
10
+ .describe("Name to use for the US lookup when it differs from `drug` (e.g. a US-only brand). Defaults to `drug`."),
11
+ uk_drug: z
12
+ .string()
13
+ .optional()
14
+ .describe("Name to use for the UK lookup when it differs from `drug` — brands often do (Farxiga/Forxiga, Prilosec/Losec). Defaults to `drug`."),
7
15
  sections: z
8
16
  .array(z.string())
9
17
  .optional()
10
18
  .describe("Specific topics to compare (e.g., ['indications', 'adverse reactions']). Compares all mapped sections if omitted."),
11
19
  };
12
- /**
13
- * Build a CompareLabelsResult by fetching both labels from the shared engine and
14
- * pairing equivalent sections (US LOINC <-> UK section number). Cached for 24h.
15
- */
16
- export async function buildCompareResult(drug, sections) {
20
+ const defaultFetchers = { getUsLabel, getUkSmpc };
21
+ const US_UNAVAILABLE = "US label not retrieved: no openFDA/DailyMed product matched this name, or the source was unreachable. " +
22
+ "If the name is a brand, try resolve_drug_name and retry with the generic.";
23
+ const UK_UNAVAILABLE = "UK SmPC not retrieved: no eMC product matched this name (the drug may not be licensed in the UK under it), " +
24
+ "or the source was unreachable. If the name is a brand, try resolve_drug_name and retry with the generic.";
25
+ const TRUNCATED_NOTE = (side, url) => `${side} text is verbatim but cut at the engine's per-section cap (ends with …); absence of a phrase here proves nothing — read the full section at ${url ?? "the source"}`;
26
+ const res_us_url = (us) => us?.dailymedUrl ?? null;
27
+ const res_uk_url = (uk) => uk?.url ?? null;
28
+ function sourceStatus(label, note) {
29
+ if (!label || label.sections.length === 0) {
30
+ return { status: "unavailable", product: null, sections_returned: 0, note };
31
+ }
32
+ return { status: "ok", product: label.drugName, sections_returned: label.sections.length };
33
+ }
34
+ export async function buildCompareResult(drug, sections, fetchers = defaultFetchers, names = {}) {
17
35
  const mappings = filterSectionMap(sections);
18
36
  if (mappings.length === 0) {
19
37
  return { error: "No matching section mappings found for the requested topics" };
20
38
  }
21
- const cacheKey = `compare:${drug.toLowerCase()}:${(sections ?? []).join(",").toLowerCase()}`;
39
+ const usName = names.us?.trim() || drug;
40
+ const ukName = names.uk?.trim() || drug;
41
+ const cacheKey = `compare:${usName.toLowerCase()}|${ukName.toLowerCase()}:${(sections ?? []).join(",").toLowerCase()}`;
22
42
  const cached = cache.get(cacheKey);
23
43
  if (cached)
24
44
  return cached;
25
45
  const usCodes = mappings.map((m) => m.us_loinc);
26
46
  const ukCodes = mappings.map((m) => m.uk_code);
27
- // Fetch both in parallel — allow partial results
47
+ // Fetch both in parallel — allow partial results. The engine already returns
48
+ // null on failure, so a rejection here is unexpected; treat it as unavailable.
28
49
  const [usSettled, ukSettled] = await Promise.allSettled([
29
- getUsLabel(drug, usCodes),
30
- getUkSmpc(drug, ukCodes),
50
+ fetchers.getUsLabel(usName, usCodes),
51
+ fetchers.getUkSmpc(ukName, ukCodes),
31
52
  ]);
32
53
  const us = usSettled.status === "fulfilled" ? usSettled.value : null;
33
54
  const uk = ukSettled.status === "fulfilled" ? ukSettled.value : null;
34
- if ((!us || us.sections.length === 0) && (!uk || uk.sections.length === 0)) {
35
- return { error: `No labelling found for "${drug}" in either US or UK databases` };
55
+ const usStatus = sourceStatus(us, US_UNAVAILABLE);
56
+ const ukStatus = sourceStatus(uk, UK_UNAVAILABLE);
57
+ if (usStatus.status === "unavailable" && ukStatus.status === "unavailable") {
58
+ return {
59
+ error: `No labelling retrieved for "${usName === ukName ? drug : `${usName}" (US) / "${ukName}" (UK)`}" from openFDA/DailyMed or the eMC. ` +
60
+ "Either no product is listed under that name in these sources (try resolve_drug_name for the generic name), " +
61
+ "or a source was unreachable.",
62
+ };
36
63
  }
37
- const usByCode = new Map((us?.sections ?? []).map((s) => [s.code, s]));
38
- const ukByCode = new Map((uk?.sections ?? []).map((s) => [s.code, s]));
39
- const comparisons = mappings.map((m) => ({
40
- topic: m.topic,
41
- us_section: usByCode.get(m.us_loinc) ?? null,
42
- uk_section: ukByCode.get(m.uk_code) ?? null,
43
- }));
64
+ const usByCode = new Map(markTruncated(us?.sections ?? []).map((s) => [s.code, s]));
65
+ const ukByCode = new Map(markTruncated(uk?.sections ?? []).map((s) => [s.code, s]));
66
+ const comparisons = mappings.map((m) => {
67
+ const usSection = usByCode.get(m.us_loinc) ?? null;
68
+ const ukSection = ukByCode.get(m.uk_code) ?? null;
69
+ const c = { topic: m.topic, us_section: usSection, uk_section: ukSection };
70
+ if (!usSection) {
71
+ c.us_note =
72
+ usStatus.status === "unavailable"
73
+ ? "US label unavailable (see us_label.note)"
74
+ : `US label retrieved but has no section mapped to ${m.topic} (LOINC ${m.us_loinc})`;
75
+ }
76
+ if (!ukSection) {
77
+ c.uk_note =
78
+ ukStatus.status === "unavailable"
79
+ ? "UK SmPC unavailable (see uk_label.note)"
80
+ : `UK SmPC retrieved but has no section ${m.uk_code} (${m.topic})`;
81
+ }
82
+ if (usSection?.truncated)
83
+ c.us_note = TRUNCATED_NOTE("US section", res_us_url(us));
84
+ if (ukSection?.truncated)
85
+ c.uk_note = TRUNCATED_NOTE("UK section", res_uk_url(uk));
86
+ return c;
87
+ });
44
88
  const result = {
45
89
  drug,
90
+ ...(usName !== drug || ukName !== drug ? { lookup_names: { us: usName, uk: ukName } } : {}),
46
91
  comparisons,
47
92
  us_source: us?.dailymedUrl ?? null,
48
93
  uk_source: uk?.url ?? null,
94
+ us_label: usStatus,
95
+ uk_label: ukStatus,
49
96
  };
50
97
  cache.set(cacheKey, result, TTL.LABEL);
51
98
  return result;
52
99
  }
53
100
  export function registerCompareLabelsTool(server) {
54
- server.tool("compare_labels", "Compare US FDA Prescribing Information vs UK/EU SmPC for a drug side-by-side. Maps equivalent sections (e.g., US Indications ↔ UK 4.1) and returns paired content.", schema, { readOnlyHint: true, destructiveHint: false, openWorldHint: true }, async (params) => {
101
+ server.tool("compare_labels", "Compare US FDA Prescribing Information vs UK/EU SmPC for a drug side-by-side. Maps equivalent sections (e.g., US Indications ↔ UK 4.1) and returns paired verbatim content. A missing side is always explained: us_label/uk_label say whether the label was retrieved, each comparison notes why a section is null, and sections cut at the engine's length cap are flagged truncated.", schema, { readOnlyHint: true, destructiveHint: false, openWorldHint: true }, async (params) => {
55
102
  try {
56
- const result = await buildCompareResult(params.drug, params.sections);
103
+ const result = await buildCompareResult(params.drug, params.sections, defaultFetchers, {
104
+ us: params.us_drug,
105
+ uk: params.uk_drug,
106
+ });
57
107
  const isError = "error" in result;
58
108
  return {
59
109
  content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
@@ -1 +1 @@
1
- {"version":3,"file":"compare-labels.js","sourceRoot":"","sources":["../../src/tools/compare-labels.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"compare-labels.js","sourceRoot":"","sources":["../../src/tools/compare-labels.ts"],"names":[],"mappings":"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"}
@@ -1,3 +1,12 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ import { OpenFdaDrug } from "../lib/openfda.js";
3
+ import { EmcSearchResult } from "../lib/emc.js";
4
+ import { DrugApprovalEntry } from "../types.js";
5
+ /**
6
+ * Merge openFDA hits with the eMC lookups into the final entries. Pure, so the
7
+ * pairing rule (UK-approved iff the eMC returned at least one product for the
8
+ * generic name) is unit-testable without the network.
9
+ */
10
+ export declare function mergeIndicationResults(fdaDrugs: OpenFdaDrug[], emcResults: Map<string, EmcSearchResult[]>): DrugApprovalEntry[];
2
11
  export declare function registerSearchIndicationTool(server: McpServer): void;
3
12
  //# sourceMappingURL=search-indication.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"search-indication.d.ts","sourceRoot":"","sources":["../../src/tools/search-indication.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAgCpE,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CA6DpE"}
1
+ {"version":3,"file":"search-indication.d.ts","sourceRoot":"","sources":["../../src/tools/search-indication.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AACpE,OAAO,EAAsB,WAAW,EAAE,MAAM,mBAAmB,CAAC;AACpE,OAAO,EAAa,eAAe,EAAE,MAAM,eAAe,CAAC;AAC3D,OAAO,EAAE,iBAAiB,EAA0B,MAAM,aAAa,CAAC;AAwBxE;;;;GAIG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,EAAE,WAAW,EAAE,EACvB,UAAU,EAAE,GAAG,CAAC,MAAM,EAAE,eAAe,EAAE,CAAC,GACzC,iBAAiB,EAAE,CAarB;AAOD,wBAAgB,4BAA4B,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkDpE"}
@@ -17,6 +17,25 @@ async function batchEmcLookups(drugNames) {
17
17
  }
18
18
  return results;
19
19
  }
20
+ /**
21
+ * Merge openFDA hits with the eMC lookups into the final entries. Pure, so the
22
+ * pairing rule (UK-approved iff the eMC returned at least one product for the
23
+ * generic name) is unit-testable without the network.
24
+ */
25
+ export function mergeIndicationResults(fdaDrugs, emcResults) {
26
+ return fdaDrugs.map((fda) => {
27
+ const emcMatches = emcResults.get(fda.generic_name);
28
+ return {
29
+ name: fda.generic_name.toLowerCase(),
30
+ brand_name: fda.brand_name,
31
+ manufacturer: fda.manufacturer,
32
+ us_approved: true,
33
+ uk_approved: emcMatches !== undefined && emcMatches.length > 0,
34
+ us_setid: fda.set_id || undefined,
35
+ uk_product_id: emcMatches?.[0]?.product_id,
36
+ };
37
+ });
38
+ }
20
39
  const schema = {
21
40
  condition: z.string().describe("Medical condition or indication to search for (e.g., 'type 2 diabetes', 'hypertension')"),
22
41
  maxResults: z.number().min(1).max(50).default(10).describe("Maximum number of drug results to return"),
@@ -41,18 +60,7 @@ export function registerSearchIndicationTool(server) {
41
60
  const genericNames = fdaDrugs.map((d) => d.generic_name);
42
61
  const emcResults = await batchEmcLookups(genericNames);
43
62
  // Step 3: Merge into final results
44
- const drugs = fdaDrugs.map((fda) => {
45
- const emcMatches = emcResults.get(fda.generic_name);
46
- return {
47
- name: fda.generic_name.toLowerCase(),
48
- brand_name: fda.brand_name,
49
- manufacturer: fda.manufacturer,
50
- us_approved: true,
51
- uk_approved: emcMatches !== undefined,
52
- us_setid: fda.set_id || undefined,
53
- uk_product_id: emcMatches?.[0]?.product_id,
54
- };
55
- });
63
+ const drugs = mergeIndicationResults(fdaDrugs, emcResults);
56
64
  const result = {
57
65
  condition: params.condition,
58
66
  drugs: drugs.slice(0, params.maxResults),
@@ -1 +1 @@
1
- {"version":3,"file":"search-indication.js","sourceRoot":"","sources":["../../src/tools/search-indication.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"search-indication.js","sourceRoot":"","sources":["../../src/tools/search-indication.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"smpc.d.ts","sourceRoot":"","sources":["../../src/tools/smpc.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAYzC;;;GAGG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBzC;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuBxD"}
1
+ {"version":3,"file":"smpc.d.ts","sourceRoot":"","sources":["../../src/tools/smpc.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAYzC;;;GAGG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBzC;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuBxD"}
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { getUkSmpc } from "@pharmatools/drug-data";
3
3
  import { cache, TTL } from "../lib/cache.js";
4
+ import { markTruncated } from "../lib/label-mapping.js";
4
5
  const schema = {
5
6
  drug: z.string().describe("Drug name to look up (e.g., 'metformin', 'atorvastatin')"),
6
7
  sections: z
@@ -24,7 +25,7 @@ export async function buildSmpcResult(drug, sections) {
24
25
  const result = {
25
26
  drug_name: smpc.drugName,
26
27
  product_id: smpc.productId,
27
- sections: smpc.sections,
28
+ sections: markTruncated(smpc.sections),
28
29
  url: smpc.url,
29
30
  };
30
31
  cache.set(cacheKey, result, TTL.LABEL);
@@ -1 +1 @@
1
- {"version":3,"file":"smpc.js","sourceRoot":"","sources":["../../src/tools/smpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAG7C,MAAM,MAAM,GAAG;IACb,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0DAA0D,CAAC;IACrF,QAAQ,EAAE,CAAC;SACR,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CACP,0HAA0H,CAC3H;CACJ,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,QAAmB;IAEnB,MAAM,QAAQ,GAAG,QAAQ,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;IAC1F,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAa,QAAQ,CAAC,CAAC;IAC/C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,EAAE,KAAK,EAAE,sBAAsB,IAAI,UAAU,EAAE,CAAC;IACzD,CAAC;IAED,MAAM,MAAM,GAAe;QACzB,SAAS,EAAE,IAAI,CAAC,QAAQ;QACxB,UAAU,EAAE,IAAI,CAAC,SAAS;QAC1B,QAAQ,EAAE,IAAI,CAAC,QAAQ;QACvB,GAAG,EAAE,IAAI,CAAC,GAAG;KACd,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IACvC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,IAAI,CACT,UAAU,EACV,oIAAoI,EACpI,MAAM,EACN,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,EACnE,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YACnE,MAAM,OAAO,GAAG,OAAO,IAAI,MAAM,CAAC;YAClC,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;gBAClE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,wBAAwB,OAAO,EAAE,EAAE,CAAC;gBACpE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"smpc.js","sourceRoot":"","sources":["../../src/tools/smpc.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAGxD,MAAM,MAAM,GAAG;IACb,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0DAA0D,CAAC;IACrF,QAAQ,EAAE,CAAC;SACR,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CACP,0HAA0H,CAC3H;CACJ,CAAC;AAEF;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,QAAmB;IAEnB,MAAM,QAAQ,GAAG,QAAQ,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;IAC1F,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAa,QAAQ,CAAC,CAAC;IAC/C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC7C,IAAI,CAAC,IAAI,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACxC,OAAO,EAAE,KAAK,EAAE,sBAAsB,IAAI,UAAU,EAAE,CAAC;IACzD,CAAC;IAED,MAAM,MAAM,GAAe;QACzB,SAAS,EAAE,IAAI,CAAC,QAAQ;QACxB,UAAU,EAAE,IAAI,CAAC,SAAS;QAC1B,QAAQ,EAAE,aAAa,CAAC,IAAI,CAAC,QAAQ,CAAC;QACtC,GAAG,EAAE,IAAI,CAAC,GAAG;KACd,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IACvC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,IAAI,CACT,UAAU,EACV,oIAAoI,EACpI,MAAM,EACN,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,EACnE,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YACnE,MAAM,OAAO,GAAG,OAAO,IAAI,MAAM,CAAC;YAClC,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;gBAClE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,wBAAwB,OAAO,EAAE,EAAE,CAAC;gBACpE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"uspi.d.ts","sourceRoot":"","sources":["../../src/tools/uspi.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAGpE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAYzC;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAoBzC;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuBxD"}
1
+ {"version":3,"file":"uspi.d.ts","sourceRoot":"","sources":["../../src/tools/uspi.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAIpE,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAYzC;;;;GAIG;AACH,wBAAsB,eAAe,CACnC,IAAI,EAAE,MAAM,EACZ,QAAQ,CAAC,EAAE,MAAM,EAAE,GAClB,OAAO,CAAC,UAAU,GAAG;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAoBzC;AAED,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAuBxD"}
@@ -1,6 +1,7 @@
1
1
  import { z } from "zod";
2
2
  import { getUsLabel } from "@pharmatools/drug-data";
3
3
  import { cache, TTL } from "../lib/cache.js";
4
+ import { markTruncated } from "../lib/label-mapping.js";
4
5
  const schema = {
5
6
  drug: z.string().describe("Drug name to look up (e.g., 'metformin', 'atorvastatin')"),
6
7
  sections: z
@@ -27,7 +28,7 @@ export async function buildUspiResult(drug, sections) {
27
28
  setid: label.setId,
28
29
  spl_version: "",
29
30
  published_date: label.publishedDate,
30
- sections: label.sections,
31
+ sections: markTruncated(label.sections),
31
32
  dailymed_url: label.dailymedUrl,
32
33
  };
33
34
  cache.set(cacheKey, result, TTL.LABEL);
@@ -1 +1 @@
1
- {"version":3,"file":"uspi.js","sourceRoot":"","sources":["../../src/tools/uspi.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAC;AACpD,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,iBAAiB,CAAC;AAG7C,MAAM,MAAM,GAAG;IACb,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,0DAA0D,CAAC;IACrF,QAAQ,EAAE,CAAC;SACR,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC;SACjB,QAAQ,EAAE;SACV,QAAQ,CACP,mIAAmI,CACpI;CACJ,CAAC;AAEF;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,IAAY,EACZ,QAAmB;IAEnB,MAAM,QAAQ,GAAG,QAAQ,IAAI,CAAC,WAAW,EAAE,IAAI,CAAC,QAAQ,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,WAAW,EAAE,EAAE,CAAC;IAC1F,MAAM,MAAM,GAAG,KAAK,CAAC,GAAG,CAAa,QAAQ,CAAC,CAAC;IAC/C,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAE1B,MAAM,KAAK,GAAG,MAAM,UAAU,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC;IAC/C,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC1C,OAAO,EAAE,KAAK,EAAE,+BAA+B,IAAI,GAAG,EAAE,CAAC;IAC3D,CAAC;IAED,MAAM,MAAM,GAAe;QACzB,SAAS,EAAE,KAAK,CAAC,QAAQ;QACzB,KAAK,EAAE,KAAK,CAAC,KAAK;QAClB,WAAW,EAAE,EAAE;QACf,cAAc,EAAE,KAAK,CAAC,aAAa;QACnC,QAAQ,EAAE,KAAK,CAAC,QAAQ;QACxB,YAAY,EAAE,KAAK,CAAC,WAAW;KAChC,CAAC;IACF,KAAK,CAAC,GAAG,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,CAAC,KAAK,CAAC,CAAC;IACvC,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAiB;IAChD,MAAM,CAAC,IAAI,CACT,UAAU,EACV,gJAAgJ,EAChJ,MAAM,EACN,EAAE,YAAY,EAAE,IAAI,EAAE,eAAe,EAAE,KAAK,EAAE,aAAa,EAAE,IAAI,EAAE,EACnE,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,eAAe,CAAC,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC;YACnE,MAAM,OAAO,GAAG,OAAO,IAAI,MAAM,CAAC;YAClC,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;gBAClE,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACtC,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,OAAO,GAAG,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;YACvE,OAAO;gBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,wBAAwB,OAAO,EAAE,EAAE,CAAC;gBACpE,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
1
+ {"version":3,"file":"uspi.js","sourceRoot":"","sources":["../../src/tools/uspi.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -67,6 +67,13 @@ export interface LabelSection {
67
67
  code: string;
68
68
  title: string;
69
69
  content: string;
70
+ /**
71
+ * True when the shared engine cut the section at its per-section character
72
+ * cap (content then ends with an ellipsis). The text returned is verbatim
73
+ * but incomplete: anything after the cut is not visible, so absence of a
74
+ * phrase from a truncated section proves nothing. Follow the source URL.
75
+ */
76
+ truncated?: boolean;
70
77
  }
71
78
  export interface USPIResult {
72
79
  drug_name: string;
@@ -82,16 +89,43 @@ export interface SmPCResult {
82
89
  sections: LabelSection[];
83
90
  url: string;
84
91
  }
92
+ /**
93
+ * Whether a whole label was retrieved from its source. "unavailable" covers
94
+ * both "no product under that name in this market" and "source unreachable" —
95
+ * the shared engine returns null for either, so the note tells the caller
96
+ * which follow-up to try rather than pretending to know.
97
+ */
98
+ export type LabelAvailability = "ok" | "unavailable";
99
+ export interface LabelSourceStatus {
100
+ status: LabelAvailability;
101
+ /** Product name as the source lists it (null when unavailable). */
102
+ product: string | null;
103
+ /** Number of mapped sections the source returned. */
104
+ sections_returned: number;
105
+ /** Present when status is "unavailable": what it can and cannot mean. */
106
+ note?: string;
107
+ }
85
108
  export interface LabelComparison {
86
109
  topic: string;
87
110
  us_section: LabelSection | null;
88
111
  uk_section: LabelSection | null;
112
+ /** Present when us_section is null: why (label unavailable vs section absent). */
113
+ us_note?: string;
114
+ /** Present when uk_section is null: why (label unavailable vs section absent). */
115
+ uk_note?: string;
89
116
  }
90
117
  export interface CompareLabelsResult {
91
118
  drug: string;
119
+ /** Present when a per-side name override was used (e.g. Farxiga / Forxiga). */
120
+ lookup_names?: {
121
+ us: string;
122
+ uk: string;
123
+ };
92
124
  comparisons: LabelComparison[];
93
125
  us_source: string | null;
94
126
  uk_source: string | null;
127
+ us_label: LabelSourceStatus;
128
+ uk_label: LabelSourceStatus;
95
129
  }
96
130
  export interface DrugApprovalEntry {
97
131
  name: string;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pharmatools/pubcrawl",
3
- "version": "2.5.1",
3
+ "version": "2.6.0",
4
4
  "description": "MCP server for PubMed & Europe PMC literature search, US/UK drug labelling, and clinical trials — built by PharmaTools.AI",
5
5
  "mcpName": "io.github.nickjlamb/pubcrawl",
6
6
  "author": "PharmaTools.AI",
@@ -34,6 +34,7 @@
34
34
  "test": "vitest run",
35
35
  "test:watch": "vitest",
36
36
  "coverage": "vitest run --coverage",
37
+ "bench": "node benchmark/run.mjs",
37
38
  "lint": "eslint .",
38
39
  "prepublishOnly": "npm run build"
39
40
  },
package/server.json CHANGED
@@ -6,12 +6,12 @@
6
6
  "url": "https://github.com/nickjlamb/pubcrawl",
7
7
  "source": "github"
8
8
  },
9
- "version": "2.5.1",
9
+ "version": "2.6.0",
10
10
  "packages": [
11
11
  {
12
12
  "registryType": "npm",
13
13
  "identifier": "@pharmatools/pubcrawl",
14
- "version": "2.5.1",
14
+ "version": "2.6.0",
15
15
  "transport": {
16
16
  "type": "stdio"
17
17
  },