@pharmatools/pubcrawl 2.0.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/LICENSE +21 -0
- package/README.md +111 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +45 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/cache.d.ts +19 -0
- package/dist/lib/cache.d.ts.map +1 -0
- package/dist/lib/cache.js +52 -0
- package/dist/lib/cache.js.map +1 -0
- package/dist/lib/dailymed.d.ts +9 -0
- package/dist/lib/dailymed.d.ts.map +1 -0
- package/dist/lib/dailymed.js +58 -0
- package/dist/lib/dailymed.js.map +1 -0
- package/dist/lib/emc.d.ts +13 -0
- package/dist/lib/emc.d.ts.map +1 -0
- package/dist/lib/emc.js +215 -0
- package/dist/lib/emc.js.map +1 -0
- package/dist/lib/label-mapping.d.ts +8 -0
- package/dist/lib/label-mapping.d.ts.map +1 -0
- package/dist/lib/label-mapping.js +23 -0
- package/dist/lib/label-mapping.js.map +1 -0
- package/dist/lib/ncbi.d.ts +37 -0
- package/dist/lib/ncbi.d.ts.map +1 -0
- package/dist/lib/ncbi.js +175 -0
- package/dist/lib/ncbi.js.map +1 -0
- package/dist/lib/openfda.d.ts +8 -0
- package/dist/lib/openfda.d.ts.map +1 -0
- package/dist/lib/openfda.js +83 -0
- package/dist/lib/openfda.js.map +1 -0
- package/dist/lib/xml-parser.d.ts +23 -0
- package/dist/lib/xml-parser.d.ts.map +1 -0
- package/dist/lib/xml-parser.js +273 -0
- package/dist/lib/xml-parser.js.map +1 -0
- package/dist/tools/abstract.d.ts +3 -0
- package/dist/tools/abstract.d.ts.map +1 -0
- package/dist/tools/abstract.js +107 -0
- package/dist/tools/abstract.js.map +1 -0
- package/dist/tools/cite.d.ts +3 -0
- package/dist/tools/cite.d.ts.map +1 -0
- package/dist/tools/cite.js +188 -0
- package/dist/tools/cite.js.map +1 -0
- package/dist/tools/compare-labels.d.ts +3 -0
- package/dist/tools/compare-labels.d.ts.map +1 -0
- package/dist/tools/compare-labels.js +126 -0
- package/dist/tools/compare-labels.js.map +1 -0
- package/dist/tools/fulltext.d.ts +3 -0
- package/dist/tools/fulltext.d.ts.map +1 -0
- package/dist/tools/fulltext.js +88 -0
- package/dist/tools/fulltext.js.map +1 -0
- package/dist/tools/related.d.ts +3 -0
- package/dist/tools/related.d.ts.map +1 -0
- package/dist/tools/related.js +63 -0
- package/dist/tools/related.js.map +1 -0
- package/dist/tools/search-indication.d.ts +3 -0
- package/dist/tools/search-indication.d.ts.map +1 -0
- package/dist/tools/search-indication.js +73 -0
- package/dist/tools/search-indication.js.map +1 -0
- package/dist/tools/search.d.ts +3 -0
- package/dist/tools/search.d.ts.map +1 -0
- package/dist/tools/search.js +69 -0
- package/dist/tools/search.js.map +1 -0
- package/dist/tools/smpc.d.ts +3 -0
- package/dist/tools/smpc.d.ts.map +1 -0
- package/dist/tools/smpc.js +52 -0
- package/dist/tools/smpc.js.map +1 -0
- package/dist/tools/trending.d.ts +3 -0
- package/dist/tools/trending.d.ts.map +1 -0
- package/dist/tools/trending.js +106 -0
- package/dist/tools/trending.js.map +1 -0
- package/dist/tools/uspi.d.ts +3 -0
- package/dist/tools/uspi.d.ts.map +1 -0
- package/dist/tools/uspi.js +117 -0
- package/dist/tools/uspi.js.map +1 -0
- package/dist/types.d.ts +93 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +49 -0
- package/server.json +29 -0
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { elink, esummary } from "../lib/ncbi.js";
|
|
3
|
+
import { parseSummaryAuthors } from "../lib/xml-parser.js";
|
|
4
|
+
const schema = {
|
|
5
|
+
pmid: z.string().describe("PubMed ID to find related articles for"),
|
|
6
|
+
maxResults: z.number().min(1).max(100).default(10).describe("Maximum number of results"),
|
|
7
|
+
};
|
|
8
|
+
export function registerRelatedTool(server) {
|
|
9
|
+
server.tool("find_related", "Find related articles for a given PubMed article. Returns similar papers ranked by relevance score using PubMed's neighbor algorithm.", schema, async (params) => {
|
|
10
|
+
try {
|
|
11
|
+
const linkResult = await elink({
|
|
12
|
+
id: params.pmid,
|
|
13
|
+
cmd: "neighbor_score",
|
|
14
|
+
linkname: "pubmed_pubmed",
|
|
15
|
+
});
|
|
16
|
+
if (linkResult.links.length === 0) {
|
|
17
|
+
return {
|
|
18
|
+
content: [{ type: "text", text: JSON.stringify({ results: [], message: "No related articles found" }, null, 2) }],
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
// Take top N results
|
|
22
|
+
const topLinks = linkResult.links.slice(0, params.maxResults);
|
|
23
|
+
const ids = topLinks.map((l) => l.id);
|
|
24
|
+
const scoreMap = new Map(topLinks.map((l) => [l.id, l.score ?? 0]));
|
|
25
|
+
const summaryData = await esummary({ id: ids });
|
|
26
|
+
const articles = ids
|
|
27
|
+
.filter((uid) => summaryData[uid])
|
|
28
|
+
.map((uid) => {
|
|
29
|
+
const doc = summaryData[uid];
|
|
30
|
+
const authors = parseSummaryAuthors(doc.authors);
|
|
31
|
+
const pubDate = String(doc.pubdate ?? "");
|
|
32
|
+
const year = pubDate.match(/\d{4}/)?.[0] ?? "";
|
|
33
|
+
const doi = (doc.elocationid ?? "")
|
|
34
|
+
.toString()
|
|
35
|
+
.replace(/^doi:\s*/i, "");
|
|
36
|
+
return {
|
|
37
|
+
pmid: uid,
|
|
38
|
+
title: String(doc.title ?? ""),
|
|
39
|
+
authors,
|
|
40
|
+
journal: String(doc.fulljournalname ?? doc.source ?? ""),
|
|
41
|
+
year,
|
|
42
|
+
doi,
|
|
43
|
+
abstract_snippet: String(doc.sorttitle ?? "").slice(0, 200),
|
|
44
|
+
relevance_score: scoreMap.get(uid) ?? 0,
|
|
45
|
+
};
|
|
46
|
+
});
|
|
47
|
+
return {
|
|
48
|
+
content: [{
|
|
49
|
+
type: "text",
|
|
50
|
+
text: JSON.stringify({ results: articles }, null, 2),
|
|
51
|
+
}],
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
catch (error) {
|
|
55
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
56
|
+
return {
|
|
57
|
+
content: [{ type: "text", text: `Error finding related articles: ${message}` }],
|
|
58
|
+
isError: true,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
}
|
|
63
|
+
//# sourceMappingURL=related.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"related.js","sourceRoot":"","sources":["../../src/tools/related.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAC;AACjD,OAAO,EAAE,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAG3D,MAAM,MAAM,GAAG;IACb,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,wCAAwC,CAAC;IACnE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,2BAA2B,CAAC;CACzF,CAAC;AAEF,MAAM,UAAU,mBAAmB,CAAC,MAAiB;IACnD,MAAM,CAAC,IAAI,CACT,cAAc,EACd,uIAAuI,EACvI,MAAM,EACN,KAAK,EAAE,MAAM,EAAE,EAAE;QACf,IAAI,CAAC;YACH,MAAM,UAAU,GAAG,MAAM,KAAK,CAAC;gBAC7B,EAAE,EAAE,MAAM,CAAC,IAAI;gBACf,GAAG,EAAE,gBAAgB;gBACrB,QAAQ,EAAE,eAAe;aAC1B,CAAC,CAAC;YAEH,IAAI,UAAU,CAAC,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAClC,OAAO;oBACL,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,OAAO,EAAE,2BAA2B,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC;iBAClH,CAAC;YACJ,CAAC;YAED,qBAAqB;YACrB,MAAM,QAAQ,GAAG,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC,CAAC;YAC9D,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YACtC,MAAM,QAAQ,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;YAEpE,MAAM,WAAW,GAAG,MAAM,QAAQ,CAAC,EAAE,EAAE,EAAE,GAAG,EAAE,CAAC,CAAC;YAEhD,MAAM,QAAQ,GAAqB,GAAG;iBACnC,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,WAAW,CAAC,GAAG,CAAC,CAAC;iBACjC,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE;gBACX,MAAM,GAAG,GAAG,WAAW,CAAC,GAAG,CAA4B,CAAC;gBACxD,MAAM,OAAO,GAAG,mBAAmB,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;gBACjD,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;gBAC1C,MAAM,IAAI,GAAG,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;gBAC/C,MAAM,GAAG,GAAG,CAAC,GAAG,CAAC,WAAW,IAAI,EAAE,CAAC;qBAChC,QAAQ,EAAE;qBACV,OAAO,CAAC,WAAW,EAAE,EAAE,CAAC,CAAC;gBAE5B,OAAO;oBACL,IAAI,EAAE,GAAG;oBACT,KAAK,EAAE,MAAM,CAAC,GAAG,CAAC,KAAK,IAAI,EAAE,CAAC;oBAC9B,OAAO;oBACP,OAAO,EAAE,MAAM,CAAC,GAAG,CAAC,eAAe,IAAI,GAAG,CAAC,MAAM,IAAI,EAAE,CAAC;oBACxD,IAAI;oBACJ,GAAG;oBACH,gBAAgB,EAAE,MAAM,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC;oBAC3D,eAAe,EAAE,QAAQ,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC;iBACxC,CAAC;YACJ,CAAC,CAAC,CAAC;YAEL,OAAO;gBACL,OAAO,EAAE,CAAC;wBACR,IAAI,EAAE,MAAM;wBACZ,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,OAAO,EAAE,QAAQ,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC;qBACrD,CAAC;aACH,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,mCAAmC,OAAO,EAAE,EAAE,CAAC;gBAC/E,OAAO,EAAE,IAAI;aACd,CAAC;QACJ,CAAC;IACH,CAAC,CACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +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,CA4DpE"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { searchByIndication } from "../lib/openfda.js";
|
|
3
|
+
import { searchEmc } from "../lib/emc.js";
|
|
4
|
+
const MAX_CONCURRENT_EMC = 5;
|
|
5
|
+
async function batchEmcLookups(drugNames) {
|
|
6
|
+
const results = new Map();
|
|
7
|
+
// Process in batches to cap concurrency
|
|
8
|
+
for (let i = 0; i < drugNames.length; i += MAX_CONCURRENT_EMC) {
|
|
9
|
+
const batch = drugNames.slice(i, i + MAX_CONCURRENT_EMC);
|
|
10
|
+
const settled = await Promise.allSettled(batch.map((name) => searchEmc(name)));
|
|
11
|
+
for (let j = 0; j < batch.length; j++) {
|
|
12
|
+
const outcome = settled[j];
|
|
13
|
+
if (outcome.status === "fulfilled" && outcome.value.length > 0) {
|
|
14
|
+
results.set(batch[j], outcome.value);
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
return results;
|
|
19
|
+
}
|
|
20
|
+
const schema = {
|
|
21
|
+
condition: z.string().describe("Medical condition or indication to search for (e.g., 'type 2 diabetes', 'hypertension')"),
|
|
22
|
+
maxResults: z.number().min(1).max(50).default(10).describe("Maximum number of drug results to return"),
|
|
23
|
+
};
|
|
24
|
+
export function registerSearchIndicationTool(server) {
|
|
25
|
+
server.tool("search_by_indication", "Find drugs approved for a medical condition. Searches US FDA labelling for the condition, then checks UK (eMC) availability for each drug found.", schema, async (params) => {
|
|
26
|
+
try {
|
|
27
|
+
// Step 1: Search OpenFDA for drugs with this indication
|
|
28
|
+
const fdaDrugs = await searchByIndication(params.condition, params.maxResults);
|
|
29
|
+
if (fdaDrugs.length === 0) {
|
|
30
|
+
return {
|
|
31
|
+
content: [{
|
|
32
|
+
type: "text",
|
|
33
|
+
text: JSON.stringify({
|
|
34
|
+
error: `No drugs found for "${params.condition}" in FDA labelling`,
|
|
35
|
+
}, null, 2),
|
|
36
|
+
}],
|
|
37
|
+
isError: true,
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
// Step 2: For each unique generic name, check eMC for UK availability
|
|
41
|
+
const genericNames = fdaDrugs.map((d) => d.generic_name);
|
|
42
|
+
const emcResults = await batchEmcLookups(genericNames);
|
|
43
|
+
// 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
|
+
});
|
|
56
|
+
const result = {
|
|
57
|
+
condition: params.condition,
|
|
58
|
+
drugs: drugs.slice(0, params.maxResults),
|
|
59
|
+
};
|
|
60
|
+
return {
|
|
61
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
catch (error) {
|
|
65
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
66
|
+
return {
|
|
67
|
+
content: [{ type: "text", text: `Error searching by indication: ${message}` }],
|
|
68
|
+
isError: true,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
//# sourceMappingURL=search-indication.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search-indication.js","sourceRoot":"","sources":["../../src/tools/search-indication.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.d.ts","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAiCpE,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAgD1D"}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { esearch, esummary } from "../lib/ncbi.js";
|
|
3
|
+
import { parseSummaryAuthors } from "../lib/xml-parser.js";
|
|
4
|
+
const schema = {
|
|
5
|
+
query: z.string().describe("PubMed search query"),
|
|
6
|
+
maxResults: z.number().min(1).max(100).default(10).describe("Maximum number of results"),
|
|
7
|
+
sort: z.enum(["relevance", "date"]).default("relevance").describe("Sort order"),
|
|
8
|
+
dateFrom: z.string().optional().describe("Start date (YYYY/MM/DD)"),
|
|
9
|
+
dateTo: z.string().optional().describe("End date (YYYY/MM/DD)"),
|
|
10
|
+
articleType: z.string().optional().describe("Article type filter (e.g., review, clinical trial)"),
|
|
11
|
+
};
|
|
12
|
+
function formatArticle(uid, doc) {
|
|
13
|
+
const authors = parseSummaryAuthors(doc.authors);
|
|
14
|
+
const pubDate = String(doc.pubdate ?? "");
|
|
15
|
+
const year = pubDate.match(/\d{4}/)?.[0] ?? "";
|
|
16
|
+
const doi = (doc.elocationid ?? "")
|
|
17
|
+
.toString()
|
|
18
|
+
.replace(/^doi:\s*/i, "");
|
|
19
|
+
return {
|
|
20
|
+
pmid: uid,
|
|
21
|
+
title: String(doc.title ?? ""),
|
|
22
|
+
authors,
|
|
23
|
+
journal: String(doc.fulljournalname ?? doc.source ?? ""),
|
|
24
|
+
year,
|
|
25
|
+
doi,
|
|
26
|
+
abstract_snippet: String(doc.sorttitle ?? "").slice(0, 200),
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
export function registerSearchTool(server) {
|
|
30
|
+
server.tool("search_pubmed", "Search PubMed for biomedical literature. Returns article summaries with PMIDs, titles, authors, journals, and DOIs.", schema, async (params) => {
|
|
31
|
+
try {
|
|
32
|
+
let term = params.query;
|
|
33
|
+
if (params.articleType) {
|
|
34
|
+
term += ` AND ${params.articleType}[pt]`;
|
|
35
|
+
}
|
|
36
|
+
const searchResult = await esearch({
|
|
37
|
+
term,
|
|
38
|
+
retmax: params.maxResults,
|
|
39
|
+
sort: params.sort === "date" ? "pub_date" : "relevance",
|
|
40
|
+
datetype: params.dateFrom || params.dateTo ? "pdat" : undefined,
|
|
41
|
+
mindate: params.dateFrom,
|
|
42
|
+
maxdate: params.dateTo,
|
|
43
|
+
});
|
|
44
|
+
if (searchResult.idlist.length === 0) {
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: "text", text: JSON.stringify({ results: [], total_count: 0 }, null, 2) }],
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
const summaryData = await esummary({ id: searchResult.idlist });
|
|
50
|
+
const articles = searchResult.idlist
|
|
51
|
+
.filter((uid) => summaryData[uid])
|
|
52
|
+
.map((uid) => formatArticle(uid, summaryData[uid]));
|
|
53
|
+
return {
|
|
54
|
+
content: [{
|
|
55
|
+
type: "text",
|
|
56
|
+
text: JSON.stringify({ results: articles, total_count: searchResult.count }, null, 2),
|
|
57
|
+
}],
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
62
|
+
return {
|
|
63
|
+
content: [{ type: "text", text: `Error searching PubMed: ${message}` }],
|
|
64
|
+
isError: true,
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/tools/search.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smpc.d.ts","sourceRoot":"","sources":["../../src/tools/smpc.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAcpE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAkDxD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { searchEmc, fetchSmpcHtml, parseSmpcSections } from "../lib/emc.js";
|
|
3
|
+
const schema = {
|
|
4
|
+
drug: z.string().describe("Drug name to look up (e.g., 'metformin', 'atorvastatin')"),
|
|
5
|
+
sections: z
|
|
6
|
+
.array(z.string())
|
|
7
|
+
.optional()
|
|
8
|
+
.describe("Specific sections to retrieve — accepts numbers like '4.1' or names like 'indications'. Returns all sections if omitted."),
|
|
9
|
+
};
|
|
10
|
+
export function registerSmpcTool(server) {
|
|
11
|
+
server.tool("get_smpc", "Get UK/EU Summary of Product Characteristics (SmPC) for a drug from eMC (medicines.org.uk). Returns structured labelling sections.", schema, async (params) => {
|
|
12
|
+
try {
|
|
13
|
+
const searchResults = await searchEmc(params.drug);
|
|
14
|
+
if (searchResults.length === 0) {
|
|
15
|
+
return {
|
|
16
|
+
content: [{
|
|
17
|
+
type: "text",
|
|
18
|
+
text: JSON.stringify({ error: `No SmPC found for "${params.drug}" on eMC` }, null, 2),
|
|
19
|
+
}],
|
|
20
|
+
isError: true,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
// Select best match: prefer name containing the drug
|
|
24
|
+
const drugLower = params.drug.toLowerCase();
|
|
25
|
+
const sorted = [...searchResults].sort((a, b) => {
|
|
26
|
+
const aMatch = a.name.toLowerCase().includes(drugLower) ? 1 : 0;
|
|
27
|
+
const bMatch = b.name.toLowerCase().includes(drugLower) ? 1 : 0;
|
|
28
|
+
return bMatch - aMatch;
|
|
29
|
+
});
|
|
30
|
+
const best = sorted[0];
|
|
31
|
+
const html = await fetchSmpcHtml(best.product_id);
|
|
32
|
+
const sections = parseSmpcSections(html, params.sections);
|
|
33
|
+
const result = {
|
|
34
|
+
drug_name: best.name,
|
|
35
|
+
product_id: best.product_id,
|
|
36
|
+
sections: sections.map((s) => ({ code: s.code, title: s.title, content: s.content })),
|
|
37
|
+
url: `https://www.medicines.org.uk/emc/product/${best.product_id}/smpc`,
|
|
38
|
+
};
|
|
39
|
+
return {
|
|
40
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
45
|
+
return {
|
|
46
|
+
content: [{ type: "text", text: `Error fetching SmPC: ${message}` }],
|
|
47
|
+
isError: true,
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=smpc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"smpc.js","sourceRoot":"","sources":["../../src/tools/smpc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trending.d.ts","sourceRoot":"","sources":["../../src/tools/trending.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAqCpE,wBAAgB,oBAAoB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAmF5D"}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { esearch, esummary } from "../lib/ncbi.js";
|
|
3
|
+
import { parseSummaryAuthors } from "../lib/xml-parser.js";
|
|
4
|
+
const HIGH_IMPACT_JOURNALS = [
|
|
5
|
+
"nature",
|
|
6
|
+
"science",
|
|
7
|
+
"cell",
|
|
8
|
+
"the new england journal of medicine",
|
|
9
|
+
"the lancet",
|
|
10
|
+
"jama",
|
|
11
|
+
"bmj",
|
|
12
|
+
"nature medicine",
|
|
13
|
+
"nature biotechnology",
|
|
14
|
+
"nature genetics",
|
|
15
|
+
"nature reviews",
|
|
16
|
+
"annals of internal medicine",
|
|
17
|
+
"plos medicine",
|
|
18
|
+
"circulation",
|
|
19
|
+
"journal of clinical oncology",
|
|
20
|
+
];
|
|
21
|
+
const schema = {
|
|
22
|
+
topic: z.string().describe("Topic or search term"),
|
|
23
|
+
days: z.number().min(1).max(365).default(30).describe("Number of days to look back"),
|
|
24
|
+
maxResults: z.number().min(1).max(100).default(20).describe("Maximum number of results"),
|
|
25
|
+
highImpactOnly: z.boolean().default(false).describe("Filter to high-impact journals only"),
|
|
26
|
+
};
|
|
27
|
+
function formatDate(date) {
|
|
28
|
+
const y = date.getFullYear();
|
|
29
|
+
const m = String(date.getMonth() + 1).padStart(2, "0");
|
|
30
|
+
const d = String(date.getDate()).padStart(2, "0");
|
|
31
|
+
return `${y}/${m}/${d}`;
|
|
32
|
+
}
|
|
33
|
+
export function registerTrendingTool(server) {
|
|
34
|
+
server.tool("trending_papers", "Find recent/trending papers on a topic. Sorted by date, with optional filtering to high-impact journals.", schema, async (params) => {
|
|
35
|
+
try {
|
|
36
|
+
const now = new Date();
|
|
37
|
+
const from = new Date(now.getTime() - params.days * 24 * 60 * 60 * 1000);
|
|
38
|
+
let term = params.topic;
|
|
39
|
+
if (params.highImpactOnly) {
|
|
40
|
+
const journalFilter = HIGH_IMPACT_JOURNALS
|
|
41
|
+
.map((j) => `"${j}"[journal]`)
|
|
42
|
+
.join(" OR ");
|
|
43
|
+
term += ` AND (${journalFilter})`;
|
|
44
|
+
}
|
|
45
|
+
const searchResult = await esearch({
|
|
46
|
+
term,
|
|
47
|
+
retmax: params.maxResults,
|
|
48
|
+
sort: "pub_date",
|
|
49
|
+
datetype: "pdat",
|
|
50
|
+
mindate: formatDate(from),
|
|
51
|
+
maxdate: formatDate(now),
|
|
52
|
+
});
|
|
53
|
+
if (searchResult.idlist.length === 0) {
|
|
54
|
+
return {
|
|
55
|
+
content: [{
|
|
56
|
+
type: "text",
|
|
57
|
+
text: JSON.stringify({
|
|
58
|
+
results: [],
|
|
59
|
+
total_count: 0,
|
|
60
|
+
topic: params.topic,
|
|
61
|
+
period_days: params.days,
|
|
62
|
+
}, null, 2),
|
|
63
|
+
}],
|
|
64
|
+
};
|
|
65
|
+
}
|
|
66
|
+
const summaryData = await esummary({ id: searchResult.idlist });
|
|
67
|
+
const articles = searchResult.idlist
|
|
68
|
+
.filter((uid) => summaryData[uid])
|
|
69
|
+
.map((uid) => {
|
|
70
|
+
const doc = summaryData[uid];
|
|
71
|
+
const authors = parseSummaryAuthors(doc.authors);
|
|
72
|
+
const pubDate = String(doc.pubdate ?? "");
|
|
73
|
+
const year = pubDate.match(/\d{4}/)?.[0] ?? "";
|
|
74
|
+
const doi = (doc.elocationid ?? "").toString().replace(/^doi:\s*/i, "");
|
|
75
|
+
return {
|
|
76
|
+
pmid: uid,
|
|
77
|
+
title: String(doc.title ?? ""),
|
|
78
|
+
authors,
|
|
79
|
+
journal: String(doc.fulljournalname ?? doc.source ?? ""),
|
|
80
|
+
year,
|
|
81
|
+
doi,
|
|
82
|
+
abstract_snippet: String(doc.sorttitle ?? "").slice(0, 200),
|
|
83
|
+
};
|
|
84
|
+
});
|
|
85
|
+
return {
|
|
86
|
+
content: [{
|
|
87
|
+
type: "text",
|
|
88
|
+
text: JSON.stringify({
|
|
89
|
+
results: articles,
|
|
90
|
+
total_count: searchResult.count,
|
|
91
|
+
topic: params.topic,
|
|
92
|
+
period_days: params.days,
|
|
93
|
+
}, null, 2),
|
|
94
|
+
}],
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
catch (error) {
|
|
98
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
99
|
+
return {
|
|
100
|
+
content: [{ type: "text", text: `Error finding trending papers: ${message}` }],
|
|
101
|
+
isError: true,
|
|
102
|
+
};
|
|
103
|
+
}
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
//# sourceMappingURL=trending.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trending.js","sourceRoot":"","sources":["../../src/tools/trending.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uspi.d.ts","sourceRoot":"","sources":["../../src/tools/uspi.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAmEpE,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,SAAS,GAAG,IAAI,CAwExD"}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { searchDrugLabels, fetchSplXml } from "../lib/dailymed.js";
|
|
3
|
+
import { parseXml, parseSplSections } from "../lib/xml-parser.js";
|
|
4
|
+
// LOINC codes for FDA prescribing information sections
|
|
5
|
+
const LOINC_MAP = {
|
|
6
|
+
"boxed warning": "34071-1",
|
|
7
|
+
"indications": "34067-9",
|
|
8
|
+
"indications and usage": "34067-9",
|
|
9
|
+
"dosage": "34068-7",
|
|
10
|
+
"dosage and administration": "34068-7",
|
|
11
|
+
"dosage forms": "43678-2",
|
|
12
|
+
"contraindications": "34070-3",
|
|
13
|
+
"warnings": "43685-7",
|
|
14
|
+
"warnings and precautions": "43685-7",
|
|
15
|
+
"adverse reactions": "34084-4",
|
|
16
|
+
"drug interactions": "34073-7",
|
|
17
|
+
"use in specific populations": "42228-7",
|
|
18
|
+
"pregnancy": "42228-7",
|
|
19
|
+
"overdosage": "34088-5",
|
|
20
|
+
"clinical pharmacology": "34090-1",
|
|
21
|
+
"description": "34089-3",
|
|
22
|
+
"how supplied": "34069-5",
|
|
23
|
+
"storage": "44425-7",
|
|
24
|
+
"patient counseling": "34076-0",
|
|
25
|
+
"medication guide": "42231-1",
|
|
26
|
+
};
|
|
27
|
+
// All known PI LOINC codes
|
|
28
|
+
const ALL_PI_CODES = [...new Set(Object.values(LOINC_MAP))];
|
|
29
|
+
function resolveLoincCodes(sections) {
|
|
30
|
+
if (!sections || sections.length === 0)
|
|
31
|
+
return undefined;
|
|
32
|
+
const codes = [];
|
|
33
|
+
for (const input of sections) {
|
|
34
|
+
const lower = input.toLowerCase().trim();
|
|
35
|
+
// Direct LOINC code (e.g., "34067-9")
|
|
36
|
+
if (/^\d{5}-\d$/.test(lower)) {
|
|
37
|
+
codes.push(lower);
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
// Fuzzy match against section names
|
|
41
|
+
const match = Object.entries(LOINC_MAP).find(([name]) => name.includes(lower) || lower.includes(name));
|
|
42
|
+
if (match) {
|
|
43
|
+
codes.push(match[1]);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return codes.length > 0 ? codes : undefined;
|
|
47
|
+
}
|
|
48
|
+
const schema = {
|
|
49
|
+
drug: z.string().describe("Drug name to look up (e.g., 'metformin', 'atorvastatin')"),
|
|
50
|
+
sections: z
|
|
51
|
+
.array(z.string())
|
|
52
|
+
.optional()
|
|
53
|
+
.describe("Specific sections to retrieve (e.g., ['indications', 'adverse reactions', 'contraindications']). Returns all sections if omitted."),
|
|
54
|
+
};
|
|
55
|
+
export function registerUspiTool(server) {
|
|
56
|
+
server.tool("get_uspi", "Get FDA US Prescribing Information (USPI) for a drug from DailyMed. Returns structured labelling sections with LOINC codes.", schema, async (params) => {
|
|
57
|
+
try {
|
|
58
|
+
const searchResults = await searchDrugLabels(params.drug);
|
|
59
|
+
if (searchResults.length === 0) {
|
|
60
|
+
return {
|
|
61
|
+
content: [{
|
|
62
|
+
type: "text",
|
|
63
|
+
text: JSON.stringify({ error: `No FDA labelling found for "${params.drug}"` }, null, 2),
|
|
64
|
+
}],
|
|
65
|
+
isError: true,
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
// Select best match: filter by drug name, sort by date descending
|
|
69
|
+
const drugLower = params.drug.toLowerCase();
|
|
70
|
+
const sorted = [...searchResults].sort((a, b) => {
|
|
71
|
+
const aMatch = a.title.toLowerCase().includes(drugLower) ? 1 : 0;
|
|
72
|
+
const bMatch = b.title.toLowerCase().includes(drugLower) ? 1 : 0;
|
|
73
|
+
if (aMatch !== bMatch)
|
|
74
|
+
return bMatch - aMatch;
|
|
75
|
+
return b.published_date.localeCompare(a.published_date);
|
|
76
|
+
});
|
|
77
|
+
const best = sorted[0];
|
|
78
|
+
const xml = await fetchSplXml(best.setid);
|
|
79
|
+
const parsed = parseXml(xml);
|
|
80
|
+
// Navigate SPL XML structure: document > component > structuredBody
|
|
81
|
+
// component may be an array due to XML parser isArray config
|
|
82
|
+
const document = parsed?.document;
|
|
83
|
+
const docComponent = document?.component;
|
|
84
|
+
const firstComponent = Array.isArray(docComponent) ? docComponent[0] : docComponent;
|
|
85
|
+
const structuredBody = firstComponent?.structuredBody;
|
|
86
|
+
const requestedCodes = resolveLoincCodes(params.sections);
|
|
87
|
+
const rawSections = parseSplSections(structuredBody, requestedCodes);
|
|
88
|
+
// If no specific sections requested and we got nothing from filtering, try all PI codes
|
|
89
|
+
const sections = rawSections.length > 0
|
|
90
|
+
? rawSections.map((s) => ({ code: s.code, title: s.title, content: s.content }))
|
|
91
|
+
: parseSplSections(structuredBody, ALL_PI_CODES).map((s) => ({
|
|
92
|
+
code: s.code,
|
|
93
|
+
title: s.title,
|
|
94
|
+
content: s.content,
|
|
95
|
+
}));
|
|
96
|
+
const result = {
|
|
97
|
+
drug_name: best.title,
|
|
98
|
+
setid: best.setid,
|
|
99
|
+
spl_version: best.spl_version,
|
|
100
|
+
published_date: best.published_date,
|
|
101
|
+
sections,
|
|
102
|
+
dailymed_url: `https://dailymed.nlm.nih.gov/dailymed/drugInfo.cfm?setid=${best.setid}`,
|
|
103
|
+
};
|
|
104
|
+
return {
|
|
105
|
+
content: [{ type: "text", text: JSON.stringify(result, null, 2) }],
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
110
|
+
return {
|
|
111
|
+
content: [{ type: "text", text: `Error fetching USPI: ${message}` }],
|
|
112
|
+
isError: true,
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
//# sourceMappingURL=uspi.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"uspi.js","sourceRoot":"","sources":["../../src/tools/uspi.ts"],"names":[],"mappings":"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"}
|