@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.
Files changed (80) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +111 -0
  3. package/dist/index.d.ts +3 -0
  4. package/dist/index.d.ts.map +1 -0
  5. package/dist/index.js +45 -0
  6. package/dist/index.js.map +1 -0
  7. package/dist/lib/cache.d.ts +19 -0
  8. package/dist/lib/cache.d.ts.map +1 -0
  9. package/dist/lib/cache.js +52 -0
  10. package/dist/lib/cache.js.map +1 -0
  11. package/dist/lib/dailymed.d.ts +9 -0
  12. package/dist/lib/dailymed.d.ts.map +1 -0
  13. package/dist/lib/dailymed.js +58 -0
  14. package/dist/lib/dailymed.js.map +1 -0
  15. package/dist/lib/emc.d.ts +13 -0
  16. package/dist/lib/emc.d.ts.map +1 -0
  17. package/dist/lib/emc.js +215 -0
  18. package/dist/lib/emc.js.map +1 -0
  19. package/dist/lib/label-mapping.d.ts +8 -0
  20. package/dist/lib/label-mapping.d.ts.map +1 -0
  21. package/dist/lib/label-mapping.js +23 -0
  22. package/dist/lib/label-mapping.js.map +1 -0
  23. package/dist/lib/ncbi.d.ts +37 -0
  24. package/dist/lib/ncbi.d.ts.map +1 -0
  25. package/dist/lib/ncbi.js +175 -0
  26. package/dist/lib/ncbi.js.map +1 -0
  27. package/dist/lib/openfda.d.ts +8 -0
  28. package/dist/lib/openfda.d.ts.map +1 -0
  29. package/dist/lib/openfda.js +83 -0
  30. package/dist/lib/openfda.js.map +1 -0
  31. package/dist/lib/xml-parser.d.ts +23 -0
  32. package/dist/lib/xml-parser.d.ts.map +1 -0
  33. package/dist/lib/xml-parser.js +273 -0
  34. package/dist/lib/xml-parser.js.map +1 -0
  35. package/dist/tools/abstract.d.ts +3 -0
  36. package/dist/tools/abstract.d.ts.map +1 -0
  37. package/dist/tools/abstract.js +107 -0
  38. package/dist/tools/abstract.js.map +1 -0
  39. package/dist/tools/cite.d.ts +3 -0
  40. package/dist/tools/cite.d.ts.map +1 -0
  41. package/dist/tools/cite.js +188 -0
  42. package/dist/tools/cite.js.map +1 -0
  43. package/dist/tools/compare-labels.d.ts +3 -0
  44. package/dist/tools/compare-labels.d.ts.map +1 -0
  45. package/dist/tools/compare-labels.js +126 -0
  46. package/dist/tools/compare-labels.js.map +1 -0
  47. package/dist/tools/fulltext.d.ts +3 -0
  48. package/dist/tools/fulltext.d.ts.map +1 -0
  49. package/dist/tools/fulltext.js +88 -0
  50. package/dist/tools/fulltext.js.map +1 -0
  51. package/dist/tools/related.d.ts +3 -0
  52. package/dist/tools/related.d.ts.map +1 -0
  53. package/dist/tools/related.js +63 -0
  54. package/dist/tools/related.js.map +1 -0
  55. package/dist/tools/search-indication.d.ts +3 -0
  56. package/dist/tools/search-indication.d.ts.map +1 -0
  57. package/dist/tools/search-indication.js +73 -0
  58. package/dist/tools/search-indication.js.map +1 -0
  59. package/dist/tools/search.d.ts +3 -0
  60. package/dist/tools/search.d.ts.map +1 -0
  61. package/dist/tools/search.js +69 -0
  62. package/dist/tools/search.js.map +1 -0
  63. package/dist/tools/smpc.d.ts +3 -0
  64. package/dist/tools/smpc.d.ts.map +1 -0
  65. package/dist/tools/smpc.js +52 -0
  66. package/dist/tools/smpc.js.map +1 -0
  67. package/dist/tools/trending.d.ts +3 -0
  68. package/dist/tools/trending.d.ts.map +1 -0
  69. package/dist/tools/trending.js +106 -0
  70. package/dist/tools/trending.js.map +1 -0
  71. package/dist/tools/uspi.d.ts +3 -0
  72. package/dist/tools/uspi.d.ts.map +1 -0
  73. package/dist/tools/uspi.js +117 -0
  74. package/dist/tools/uspi.js.map +1 -0
  75. package/dist/types.d.ts +93 -0
  76. package/dist/types.d.ts.map +1 -0
  77. package/dist/types.js +2 -0
  78. package/dist/types.js.map +1 -0
  79. package/package.json +49 -0
  80. 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":"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"}
@@ -0,0 +1,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSearchIndicationTool(server: McpServer): void;
3
+ //# sourceMappingURL=search-indication.d.ts.map
@@ -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,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSearchTool(server: McpServer): void;
3
+ //# sourceMappingURL=search.d.ts.map
@@ -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,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerSmpcTool(server: McpServer): void;
3
+ //# sourceMappingURL=smpc.d.ts.map
@@ -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,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerTrendingTool(server: McpServer): void;
3
+ //# sourceMappingURL=trending.d.ts.map
@@ -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,3 @@
1
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
+ export declare function registerUspiTool(server: McpServer): void;
3
+ //# sourceMappingURL=uspi.d.ts.map
@@ -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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"}