@ythalorossy/openfda 1.0.18 → 1.0.19

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 (2) hide show
  1. package/dist/index.js +230 -162
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -4,7 +4,21 @@ var D = (n, t, r) => t in n ? v(n, t, { enumerable: !0, configurable: !0, writab
4
4
  var k = (n, t, r) => D(n, typeof t != "symbol" ? t + "" : t, r);
5
5
  import { McpServer as N } from "@modelcontextprotocol/sdk/server/mcp.js";
6
6
  import { StdioServerTransport as C } from "@modelcontextprotocol/sdk/server/stdio.js";
7
- import l from "zod";
7
+ import d from "zod";
8
+ class T {
9
+ constructor(t) {
10
+ k(this, "registerTool", (t) => this.server.registerTool(
11
+ t.name,
12
+ {
13
+ title: t.name,
14
+ description: t.description,
15
+ inputSchema: t.inputSchema
16
+ },
17
+ t.handler
18
+ ));
19
+ this.server = t;
20
+ }
21
+ }
8
22
  class g {
9
23
  constructor() {
10
24
  k(this, "urlBase", "https://api.fda.gov");
@@ -23,24 +37,10 @@ class g {
23
37
  return this.params.set("limit", t), this;
24
38
  }
25
39
  build() {
26
- const t = this.params.get("dataset"), r = this.params.get("context"), s = this.params.get("search"), e = this.params.get("limit") ?? 1, i = process.env.OPENFDA_API_KEY;
40
+ const t = this.params.get("dataset"), r = this.params.get("context"), s = this.params.get("search"), e = this.params.get("limit") ?? 1, o = process.env.OPENFDA_API_KEY;
27
41
  if (!t || !r || !s)
28
42
  throw new Error("Missing required parameters: context or search");
29
- return `${this.urlBase}/${t}/${r}.json?api_key=${i}&search=${s}&limit=${e}`;
30
- }
31
- }
32
- class T {
33
- constructor(t) {
34
- k(this, "registerTool", (t) => this.server.registerTool(
35
- t.name,
36
- {
37
- title: t.name,
38
- description: t.description,
39
- inputSchema: t.inputSchema
40
- },
41
- t.handler
42
- ));
43
- this.server = t;
43
+ return `${this.urlBase}/${t}/${r}.json?api_key=${o}&search=${s}&limit=${e}`;
44
44
  }
45
45
  }
46
46
  const F = {
@@ -56,19 +56,19 @@ function x(n) {
56
56
  function w(n) {
57
57
  return new Promise((t) => setTimeout(t, n));
58
58
  }
59
- async function y(n, t = {}) {
60
- const { maxRetries: r, retryDelay: s, timeout: e } = { ...F, ...t }, i = {
59
+ async function h(n, t = {}) {
60
+ const { maxRetries: r, retryDelay: s, timeout: e } = { ...F, ...t }, o = {
61
61
  "User-Agent": "@ythalorossy/openfda",
62
62
  Accept: "application/json"
63
63
  };
64
64
  let a = null;
65
65
  for (let p = 0; p <= r; p++)
66
66
  try {
67
- const o = new AbortController(), d = setTimeout(() => o.abort(), e), c = await fetch(n, {
68
- headers: i,
69
- signal: o.signal
67
+ const i = new AbortController(), l = setTimeout(() => i.abort(), e), c = await fetch(n, {
68
+ headers: o,
69
+ signal: i.signal
70
70
  });
71
- if (clearTimeout(d), !c.ok) {
71
+ if (clearTimeout(l), !c.ok) {
72
72
  const f = await c.text().catch(() => "Unable to read error response"), m = {
73
73
  type: "http",
74
74
  message: `HTTP ${c.status}: ${c.statusText}`,
@@ -100,8 +100,8 @@ async function y(n, t = {}) {
100
100
  if (a = m, c.status >= 400 && c.status < 500 && c.status !== 429)
101
101
  break;
102
102
  if (p < r && x({ status: c.status })) {
103
- const h = s * Math.pow(2, p);
104
- await w(h);
103
+ const b = s * Math.pow(2, p);
104
+ await w(b);
105
105
  continue;
106
106
  }
107
107
  break;
@@ -125,21 +125,21 @@ async function y(n, t = {}) {
125
125
  break;
126
126
  }
127
127
  return { data: u, error: null };
128
- } catch (o) {
129
- let d;
130
- if (o.name === "AbortError" ? d = {
128
+ } catch (i) {
129
+ let l;
130
+ if (i.name === "AbortError" ? l = {
131
131
  type: "timeout",
132
132
  message: `Request timeout after ${e}ms`,
133
- details: o
134
- } : o instanceof TypeError && o.message.includes("fetch") ? d = {
133
+ details: i
134
+ } : i instanceof TypeError && i.message.includes("fetch") ? l = {
135
135
  type: "network",
136
136
  message: "Network error: Unable to connect to OpenFDA API",
137
- details: o.message
138
- } : d = {
137
+ details: i.message
138
+ } : l = {
139
139
  type: "unknown",
140
- message: `Unexpected error: ${o.message || "Unknown error occurred"}`,
141
- details: o
142
- }, a = d, p < r && x(o)) {
140
+ message: `Unexpected error: ${i.message || "Unknown error occurred"}`,
141
+ details: i
142
+ }, a = l, p < r && x(i)) {
143
143
  const c = s * Math.pow(2, p);
144
144
  await w(c);
145
145
  continue;
@@ -148,47 +148,14 @@ async function y(n, t = {}) {
148
148
  }
149
149
  return { data: null, error: a };
150
150
  }
151
- const X = new N(
152
- {
153
- name: "openfda",
154
- version: "1.0.0",
155
- description: "OpenFDA Model Context Protocol"
156
- },
157
- {
158
- capabilities: {
159
- resources: {},
160
- tools: {}
161
- }
162
- }
163
- ), b = new T(X);
164
- function E(n) {
165
- const t = n.trim().toUpperCase();
166
- let r, s = null;
167
- if (t.includes("-")) {
168
- const i = t.split("-");
169
- if (i.length === 2)
170
- r = t, s = null;
171
- else if (i.length === 3)
172
- r = `${i[0]}-${i[1]}`, s = t;
173
- else
174
- return { productNDC: t, packageNDC: null, isValid: !1 };
175
- } else if (t.length === 11)
176
- r = `${t.substring(0, 5)}-${t.substring(5, 9)}`, s = `${t.substring(0, 5)}-${t.substring(5, 9)}-${t.substring(9, 11)}`;
177
- else if (t.length === 9)
178
- r = `${t.substring(0, 5)}-${t.substring(5, 9)}`, s = null;
179
- else
180
- return { productNDC: t, packageNDC: null, isValid: !1 };
181
- const e = /^\d{5}-\d{4}$/.test(r);
182
- return { productNDC: r, packageNDC: s, isValid: e };
183
- }
184
- b.registerTool({
151
+ const S = {
185
152
  name: "get-drug-by-name",
186
153
  description: "Get drug by name. Use this tool to get the drug information by name. The drug name should be the brand name. It returns the brand name, generic name, manufacturer name, product NDC, product type, route, substance name, indications and usage, warnings, do not use, ask doctor, ask doctor or pharmacist, stop use, pregnancy or breast feeding.",
187
- inputSchema: l.object({
188
- drugName: l.string().describe("Drug name")
154
+ inputSchema: d.object({
155
+ drugName: d.string().describe("Drug name")
189
156
  }),
190
- handler: async ({ drugName: n }) => {
191
- const t = new g().dataset("drug").context("label").search(`openfda.brand_name:"${n}"`).limit(1).build(), { data: r, error: s } = await y(t);
157
+ async handler({ drugName: n }) {
158
+ const t = new g().dataset("drug").context("label").search(`openfda.brand_name:"${n}"`).limit(1).build(), { data: r, error: s } = await h(t);
192
159
  if (s) {
193
160
  let a = `Failed to retrieve drug data for "${n}": ${s.message}`;
194
161
  switch (s.type) {
@@ -214,12 +181,7 @@ The request took too long. Please try again.`;
214
181
  break;
215
182
  }
216
183
  return {
217
- content: [
218
- {
219
- type: "text",
220
- text: a
221
- }
222
- ],
184
+ content: [{ type: "text", text: a }],
223
185
  isError: !0
224
186
  };
225
187
  }
@@ -232,7 +194,7 @@ The request took too long. Please try again.`;
232
194
  }
233
195
  ]
234
196
  };
235
- const e = r.results[0], i = {
197
+ const e = r.results[0], o = {
236
198
  brand_name: e == null ? void 0 : e.openfda.brand_name,
237
199
  generic_name: e == null ? void 0 : e.openfda.generic_name,
238
200
  manufacturer_name: e == null ? void 0 : e.openfda.manufacturer_name,
@@ -254,21 +216,23 @@ The request took too long. Please try again.`;
254
216
  type: "text",
255
217
  text: `Drug information retrieved successfully:
256
218
 
257
- ${JSON.stringify(i, null, 2)}`
219
+ ${JSON.stringify(o, null, 2)}`
258
220
  }
259
221
  ]
260
222
  };
261
223
  }
262
- });
263
- b.registerTool({
224
+ }, E = {
264
225
  name: "get-drug-by-generic-name",
265
226
  description: "Get drug information by generic (active ingredient) name. Useful when you know the generic name but not the brand name. Returns all brand versions of the generic drug.",
266
- inputSchema: l.object({
267
- genericName: l.string().describe("Generic drug name (active ingredient)"),
268
- limit: l.number().optional().default(5).describe("Maximum number of results to return")
227
+ inputSchema: d.object({
228
+ genericName: d.string().describe("Generic drug name (active ingredient)"),
229
+ limit: d.number().optional().default(5).describe("Maximum number of results to return")
269
230
  }),
270
- handler: async ({ genericName: n, limit: t }) => {
271
- const r = new g().dataset("drug").context("label").search(`openfda.generic_name:"${n}"`).limit(t).build(), { data: s, error: e } = await y(r);
231
+ async handler({
232
+ genericName: n,
233
+ limit: t
234
+ }) {
235
+ const r = new g().dataset("drug").context("label").search(`openfda.generic_name:"${n}"`).limit(t).build(), { data: s, error: e } = await h(r);
272
236
  if (e)
273
237
  return {
274
238
  content: [
@@ -288,12 +252,12 @@ b.registerTool({
288
252
  }
289
253
  ]
290
254
  };
291
- const i = s.results.map((a) => {
292
- var p, o, d, c;
255
+ const o = s.results.map((a) => {
256
+ var p, i, l, c;
293
257
  return {
294
258
  brand_name: ((p = a == null ? void 0 : a.openfda.brand_name) == null ? void 0 : p[0]) || "Unknown",
295
- generic_name: ((o = a == null ? void 0 : a.openfda.generic_name) == null ? void 0 : o[0]) || "Unknown",
296
- manufacturer_name: ((d = a == null ? void 0 : a.openfda.manufacturer_name) == null ? void 0 : d[0]) || "Unknown",
259
+ generic_name: ((i = a == null ? void 0 : a.openfda.generic_name) == null ? void 0 : i[0]) || "Unknown",
260
+ manufacturer_name: ((l = a == null ? void 0 : a.openfda.manufacturer_name) == null ? void 0 : l[0]) || "Unknown",
297
261
  product_type: ((c = a == null ? void 0 : a.openfda.product_type) == null ? void 0 : c[0]) || "Unknown",
298
262
  route: (a == null ? void 0 : a.openfda.route) || []
299
263
  };
@@ -302,26 +266,29 @@ b.registerTool({
302
266
  content: [
303
267
  {
304
268
  type: "text",
305
- text: `Found ${i.length} drug(s) with generic name "${n}":
269
+ text: `Found ${o.length} drug(s) with generic name "${n}":
306
270
 
307
- ${JSON.stringify(i, null, 2)}`
271
+ ${JSON.stringify(o, null, 2)}`
308
272
  }
309
273
  ]
310
274
  };
311
275
  }
312
- });
313
- b.registerTool({
276
+ }, P = {
314
277
  name: "get-drug-adverse-events",
315
278
  description: "Get adverse event reports for a drug. This provides safety information about reported side effects and reactions. Use brand name or generic name.",
316
- inputSchema: l.object({
317
- drugName: l.string().describe("Drug name (brand or generic)"),
318
- limit: l.number().optional().default(10).describe("Maximum number of events to return"),
319
- seriousness: l.enum(["serious", "non-serious", "all"]).optional().default("all").describe("Filter by event seriousness")
279
+ inputSchema: d.object({
280
+ drugName: d.string().describe("Drug name (brand or generic)"),
281
+ limit: d.number().optional().default(10).describe("Maximum number of events to return"),
282
+ seriousness: d.enum(["serious", "non-serious", "all"]).optional().default("all").describe("Filter by event seriousness")
320
283
  }),
321
- handler: async ({ drugName: n, limit: t, seriousness: r }) => {
284
+ async handler({
285
+ drugName: n,
286
+ limit: t,
287
+ seriousness: r
288
+ }) {
322
289
  let s = `patient.drug.medicinalproduct:"${n}"`;
323
290
  r !== "all" && (s += `+AND+serious:${r === "serious" ? "1" : "2"}`);
324
- const e = new g().dataset("drug").context("event").search(s).limit(t).build(), { data: i, error: a } = await y(e);
291
+ const e = new g().dataset("drug").context("event").search(s).limit(t).build(), { data: o, error: a } = await h(e);
325
292
  if (a)
326
293
  return {
327
294
  content: [
@@ -332,7 +299,7 @@ b.registerTool({
332
299
  ],
333
300
  isError: !0
334
301
  };
335
- if (!(i != null && i.results) || i.results.length === 0)
302
+ if (!(o != null && o.results) || o.results.length === 0)
336
303
  return {
337
304
  content: [
338
305
  {
@@ -341,16 +308,16 @@ b.registerTool({
341
308
  }
342
309
  ]
343
310
  };
344
- const p = i.results.map((o) => {
345
- var d, c, u, f, m, h, $;
311
+ const p = o.results.map((i) => {
312
+ var l, c, u, f, m, b, $;
346
313
  return {
347
- report_id: o.safetyreportid,
348
- serious: o.serious === "1" ? "Yes" : "No",
349
- patient_age: ((d = o.patient) == null ? void 0 : d.patientonsetage) || "Unknown",
350
- patient_sex: ((c = o.patient) == null ? void 0 : c.patientsex) === "1" ? "Male" : ((u = o.patient) == null ? void 0 : u.patientsex) === "2" ? "Female" : "Unknown",
351
- reactions: ((m = (f = o.patient) == null ? void 0 : f.reaction) == null ? void 0 : m.map((_) => _.reactionmeddrapt).slice(0, 3)) || [],
352
- outcomes: (($ = (h = o.patient) == null ? void 0 : h.reaction) == null ? void 0 : $.map((_) => _.reactionoutcome).slice(0, 3)) || [],
353
- report_date: o.receiptdate || "Unknown"
314
+ report_id: i.safetyreportid,
315
+ serious: i.serious === "1" ? "Yes" : "No",
316
+ patient_age: ((l = i.patient) == null ? void 0 : l.patientonsetage) || "Unknown",
317
+ patient_sex: ((c = i.patient) == null ? void 0 : c.patientsex) === "1" ? "Male" : ((u = i.patient) == null ? void 0 : u.patientsex) === "2" ? "Female" : "Unknown",
318
+ reactions: ((m = (f = i.patient) == null ? void 0 : f.reaction) == null ? void 0 : m.map((_) => _.reactionmeddrapt).slice(0, 3)) || [],
319
+ outcomes: (($ = (b = i.patient) == null ? void 0 : b.reaction) == null ? void 0 : $.map((_) => _.reactionoutcome).slice(0, 3)) || [],
320
+ report_date: i.receiptdate || "Unknown"
354
321
  };
355
322
  });
356
323
  return {
@@ -364,16 +331,18 @@ ${JSON.stringify(p, null, 2)}`
364
331
  ]
365
332
  };
366
333
  }
367
- });
368
- b.registerTool({
334
+ }, A = {
369
335
  name: "get-drugs-by-manufacturer",
370
336
  description: "Get all drugs manufactured by a specific company. Useful for finding alternatives or checking manufacturer portfolios.",
371
- inputSchema: l.object({
372
- manufacturerName: l.string().describe("Manufacturer/company name"),
373
- limit: l.number().optional().default(20).describe("Maximum number of drugs to return")
337
+ inputSchema: d.object({
338
+ manufacturerName: d.string().describe("Manufacturer/company name"),
339
+ limit: d.number().optional().default(20).describe("Maximum number of drugs to return")
374
340
  }),
375
- handler: async ({ manufacturerName: n, limit: t }) => {
376
- const r = new g().dataset("drug").context("label").search(`openfda.manufacturer_name:"${n}"`).limit(t).build(), { data: s, error: e } = await y(r);
341
+ async handler({
342
+ manufacturerName: n,
343
+ limit: t
344
+ }) {
345
+ const r = new g().dataset("drug").context("label").search(`openfda.manufacturer_name:"${n}"`).limit(t).build(), { data: s, error: e } = await h(r);
377
346
  if (e)
378
347
  return {
379
348
  content: [
@@ -394,12 +363,12 @@ Failed to retrieve drugs for manufacturer "${n}": ${e.message}`
394
363
  }
395
364
  ]
396
365
  };
397
- const i = s.results.map((a) => {
398
- var p, o, d, c;
366
+ const o = s.results.map((a) => {
367
+ var p, i, l, c;
399
368
  return {
400
369
  brand_name: ((p = a == null ? void 0 : a.openfda.brand_name) == null ? void 0 : p[0]) || "Unknown",
401
- generic_name: ((o = a == null ? void 0 : a.openfda.generic_name) == null ? void 0 : o[0]) || "Unknown",
402
- product_type: ((d = a == null ? void 0 : a.openfda.product_type) == null ? void 0 : d[0]) || "Unknown",
370
+ generic_name: ((i = a == null ? void 0 : a.openfda.generic_name) == null ? void 0 : i[0]) || "Unknown",
371
+ product_type: ((l = a == null ? void 0 : a.openfda.product_type) == null ? void 0 : l[0]) || "Unknown",
403
372
  route: (a == null ? void 0 : a.openfda.route) || [],
404
373
  ndc: ((c = a == null ? void 0 : a.openfda.product_ndc) == null ? void 0 : c[0]) || "Unknown"
405
374
  };
@@ -408,23 +377,22 @@ Failed to retrieve drugs for manufacturer "${n}": ${e.message}`
408
377
  content: [
409
378
  {
410
379
  type: "text",
411
- text: `Found ${i.length} drug(s) from manufacturer "${n}":
380
+ text: `Found ${o.length} drug(s) from manufacturer "${n}":
412
381
 
413
- ${JSON.stringify(i, null, 2)}`
382
+ ${JSON.stringify(o, null, 2)}`
414
383
  }
415
384
  ]
416
385
  };
417
386
  }
418
- });
419
- b.registerTool({
387
+ }, U = {
420
388
  name: "get-drug-safety-info",
421
389
  description: "Get comprehensive safety information for a drug including warnings, contraindications, drug interactions, and precautions. Use brand name.",
422
- inputSchema: l.object({
423
- drugName: l.string().describe("Drug brand name")
390
+ inputSchema: d.object({
391
+ drugName: d.string().describe("Drug brand name")
424
392
  }),
425
- handler: async ({ drugName: n }) => {
393
+ async handler({ drugName: n }) {
426
394
  var a, p;
427
- const t = new g().dataset("drug").context("label").search(`openfda.brand_name:"${n}"`).limit(1).build(), { data: r, error: s } = await y(t);
395
+ const t = new g().dataset("drug").context("label").search(`openfda.brand_name:"${n}"`).limit(1).build(), { data: r, error: s } = await h(t);
428
396
  if (s)
429
397
  return {
430
398
  content: [
@@ -444,7 +412,7 @@ b.registerTool({
444
412
  }
445
413
  ]
446
414
  };
447
- const e = r.results[0], i = {
415
+ const e = r.results[0], o = {
448
416
  drug_name: ((a = e == null ? void 0 : e.openfda.brand_name) == null ? void 0 : a[0]) || n,
449
417
  generic_name: ((p = e == null ? void 0 : e.openfda.generic_name) == null ? void 0 : p[0]) || "Unknown",
450
418
  warnings: (e == null ? void 0 : e.warnings) || [],
@@ -464,22 +432,42 @@ b.registerTool({
464
432
  type: "text",
465
433
  text: `Safety information for "${n}":
466
434
 
467
- ${JSON.stringify(i, null, 2)}`
435
+ ${JSON.stringify(o, null, 2)}`
468
436
  }
469
437
  ]
470
438
  };
471
439
  }
472
- });
473
- b.registerTool({
440
+ };
441
+ function O(n) {
442
+ const t = n.trim().toUpperCase();
443
+ let r, s = null;
444
+ if (t.includes("-")) {
445
+ const o = t.split("-");
446
+ if (o.length === 2)
447
+ r = t, s = null;
448
+ else if (o.length === 3)
449
+ r = `${o[0]}-${o[1]}`, s = t;
450
+ else
451
+ return { productNDC: t, packageNDC: null, isValid: !1 };
452
+ } else if (t.length === 11)
453
+ r = `${t.substring(0, 5)}-${t.substring(5, 9)}`, s = `${t.substring(0, 5)}-${t.substring(5, 9)}-${t.substring(9, 11)}`;
454
+ else if (t.length === 9)
455
+ r = `${t.substring(0, 5)}-${t.substring(5, 9)}`, s = null;
456
+ else
457
+ return { productNDC: t, packageNDC: null, isValid: !1 };
458
+ const e = /^\d{5}-\d{4}$/.test(r);
459
+ return { productNDC: r, packageNDC: s, isValid: e };
460
+ }
461
+ const I = {
474
462
  name: "get-drug-by-ndc",
475
463
  description: "Get drug information by National Drug Code (NDC). Accepts both product NDC (XXXXX-XXXX) and package NDC (XXXXX-XXXX-XX) formats. Also accepts NDC codes without dashes.",
476
- inputSchema: l.object({
477
- ndcCode: l.string().describe(
464
+ inputSchema: d.object({
465
+ ndcCode: d.string().describe(
478
466
  "National Drug Code (NDC) - accepts formats: XXXXX-XXXX, XXXXX-XXXX-XX, or without dashes"
479
467
  )
480
468
  }),
481
- handler: async ({ ndcCode: n }) => {
482
- const { productNDC: t, packageNDC: r, isValid: s } = E(n);
469
+ async handler({ ndcCode: n }) {
470
+ const { productNDC: t, packageNDC: r, isValid: s } = O(n);
483
471
  if (!s)
484
472
  return {
485
473
  content: [
@@ -497,7 +485,7 @@ b.registerTool({
497
485
  };
498
486
  let e = `openfda.product_ndc:"${t}"`;
499
487
  r && (e += `+OR+openfda.package_ndc:"${r}"`);
500
- const i = new g().dataset("drug").context("label").search(e).limit(10).build(), { data: a, error: p } = await y(i);
488
+ const o = new g().dataset("drug").context("label").search(e).limit(10).build(), { data: a, error: p } = await h(o);
501
489
  if (p)
502
490
  return {
503
491
  content: [
@@ -522,31 +510,28 @@ b.registerTool({
522
510
  }
523
511
  ]
524
512
  };
525
- const o = a.results.map((u) => {
526
- var h, $;
527
- const f = ((h = u.openfda.product_ndc) == null ? void 0 : h.filter((_) => _ === t)) || [], m = (($ = u.openfda.package_ndc) == null ? void 0 : $.filter(
513
+ const i = a.results.map((u) => {
514
+ var b, $;
515
+ const f = ((b = u.openfda.product_ndc) == null ? void 0 : b.filter((_) => _ === t)) || [], m = (($ = u.openfda.package_ndc) == null ? void 0 : $.filter(
528
516
  (_) => r ? _ === r : _.startsWith(t)
529
517
  )) || [];
530
518
  return {
531
- // Basic drug information
532
519
  brand_name: u.openfda.brand_name || [],
533
520
  generic_name: u.openfda.generic_name || [],
534
521
  manufacturer_name: u.openfda.manufacturer_name || [],
535
522
  product_type: u.openfda.product_type || [],
536
523
  route: u.openfda.route || [],
537
524
  substance_name: u.openfda.substance_name || [],
538
- // NDC information
539
525
  matching_product_ndc: f,
540
526
  matching_package_ndc: m,
541
527
  all_product_ndc: u.openfda.product_ndc || [],
542
528
  all_package_ndc: u.openfda.package_ndc || [],
543
- // Additional product details
544
529
  dosage_and_administration: u.dosage_and_administration || [],
545
530
  package_label_principal_display_panel: u.package_label_principal_display_panel || [],
546
531
  active_ingredient: u.active_ingredient || [],
547
532
  purpose: u.purpose || []
548
533
  };
549
- }), d = o.reduce(
534
+ }), l = i.reduce(
550
535
  (u, f) => u + f.matching_package_ndc.length,
551
536
  0
552
537
  ), c = r ? `Searched for specific package NDC: ${r}` : `Searched for product NDC: ${t} (all packages)`;
@@ -554,23 +539,22 @@ b.registerTool({
554
539
  content: [
555
540
  {
556
541
  type: "text",
557
- text: `✅ Found ${o.length} drug(s) with ${d} package(s) for NDC "${n}"
542
+ text: `✅ Found ${i.length} drug(s) with ${l} package(s) for NDC "${n}"
558
543
 
559
544
  ${c}
560
545
 
561
- ${JSON.stringify(o, null, 2)}`
546
+ ${JSON.stringify(i, null, 2)}`
562
547
  }
563
548
  ]
564
549
  };
565
550
  }
566
- });
567
- b.registerTool({
551
+ }, M = {
568
552
  name: "get-drug-by-product-ndc",
569
553
  description: "Get drug information by product NDC only (XXXXX-XXXX format). This ignores package variations and finds all packages for a product.",
570
- inputSchema: l.object({
571
- productNDC: l.string().describe("Product NDC in format XXXXX-XXXX")
554
+ inputSchema: d.object({
555
+ productNDC: d.string().describe("Product NDC in format XXXXX-XXXX")
572
556
  }),
573
- handler: async ({ productNDC: n }) => {
557
+ async handler({ productNDC: n }) {
574
558
  var p;
575
559
  if (!/^\d{5}-\d{4}$/.test(n.trim()))
576
560
  return {
@@ -584,7 +568,7 @@ b.registerTool({
584
568
  ],
585
569
  isError: !0
586
570
  };
587
- const t = new g().dataset("drug").context("label").search(`openfda.product_ndc:"${n.trim()}"`).limit(1).build(), { data: r, error: s } = await y(t);
571
+ const t = new g().dataset("drug").context("label").search(`openfda.product_ndc:"${n.trim()}"`).limit(1).build(), { data: r, error: s } = await h(t);
588
572
  if (s)
589
573
  return {
590
574
  content: [
@@ -605,11 +589,11 @@ b.registerTool({
605
589
  ],
606
590
  structuredContent: null
607
591
  };
608
- const e = r.results[0], i = ((p = e.openfda.package_ndc) == null ? void 0 : p.filter(
609
- (o) => o.startsWith(n.trim())
592
+ const e = r.results[0], o = ((p = e.openfda.package_ndc) == null ? void 0 : p.filter(
593
+ (i) => i.startsWith(n.trim())
610
594
  )) || [], a = {
611
595
  product_ndc: n,
612
- available_packages: i,
596
+ available_packages: o,
613
597
  brand_name: e.openfda.brand_name || [],
614
598
  generic_name: e.openfda.generic_name || [],
615
599
  manufacturer_name: e.openfda.manufacturer_name || [],
@@ -624,18 +608,102 @@ b.registerTool({
624
608
  content: [
625
609
  {
626
610
  type: "text",
627
- text: `✅ Product NDC "${n}" found with ${i.length} package variation(s):
611
+ text: `✅ Product NDC "${n}" found with ${o.length} package variation(s):
628
612
 
629
613
  ${JSON.stringify(a, null, 2)}`
630
614
  }
631
615
  ]
632
616
  };
633
617
  }
634
- });
635
- async function S() {
618
+ }, R = {
619
+ name: "get-drugsfda",
620
+ description: "Get drugsfda data by section and field. Search OpenFDA drugsfda endpoint by specifying a section (application, openfda, products, submissions, application_docs), a field name within that section, and a search value.",
621
+ inputSchema: d.object({
622
+ sectionName: d.string().describe(
623
+ "Section within drugsfda. Valid values: application, openfda, products, submissions, application_docs"
624
+ ),
625
+ fieldName: d.string().describe(
626
+ "Field name within the selected section. application: application_number. openfda: application_number, brand_name, generic_name, manufacturer_name, nui, package_ndc, pharm_class_cs, pharm_class_epc, pharm_class_pe, pharm_class_moa, product_ndc, route, rxcui, spl_id, spl_set_id, substance_name, unii. products: active_ingredients.name, active_ingredients.strength, dosage_form, marketing_status, product_number, reference_drug, reference_standard, route, te_code. submissions: application_docs, review_priority, submission_class_code, submission_class_code_description, submission_number, submission_property_type.code, submission_public_notes, submission_status, submission_status_date, submission_type. application_docs: applications_doc_id, applications_doc_date, application_docs_title, applications_doc_type, applications_doc_url"
627
+ ),
628
+ searchValue: d.string().describe("Value to search for in the specified field")
629
+ }),
630
+ async handler({
631
+ sectionName: n,
632
+ fieldName: t,
633
+ searchValue: r
634
+ }) {
635
+ const s = new g().dataset("drug").context("drugsfda").search(`${n}.${t}:"${r}"`).limit(1).build(), { data: e, error: o } = await h(s);
636
+ if (o) {
637
+ let a = `${s} Failed to retrieve drugsfda data for "${r}" in ${n}.${t}: ${o.message}`;
638
+ switch (o.type) {
639
+ case "http":
640
+ o.status === 404 ? a += `
641
+
642
+ Suggestions:
643
+ - Verify the field name is correct for the section
644
+ - Check the search value spelling` : (o.status === 401 || o.status === 403) && (a += `
645
+
646
+ Please check the API key configuration.`);
647
+ break;
648
+ case "network":
649
+ a += `
650
+
651
+ Please check your internet connection and try again.`;
652
+ break;
653
+ case "timeout":
654
+ a += `
655
+
656
+ The request took too long. Please try again.`;
657
+ break;
658
+ }
659
+ return {
660
+ content: [{ type: "text", text: a }],
661
+ isError: !0
662
+ };
663
+ }
664
+ return !(e != null && e.results) || e.results.length === 0 ? {
665
+ content: [
666
+ {
667
+ type: "text",
668
+ text: `No drugsfda data found for "${r}" in ${n}.${t}. Please verify the search parameters.`
669
+ }
670
+ ]
671
+ } : {
672
+ content: [
673
+ {
674
+ type: "text",
675
+ text: `drugsfda data retrieved successfully:
676
+
677
+ ${JSON.stringify(e.results[0], null, 2)}`
678
+ }
679
+ ]
680
+ };
681
+ }
682
+ }, X = new N(
683
+ {
684
+ name: "openfda",
685
+ version: "1.0.0",
686
+ description: "OpenFDA Model Context Protocol"
687
+ },
688
+ {
689
+ capabilities: {
690
+ resources: {},
691
+ tools: {}
692
+ }
693
+ }
694
+ ), y = new T(X);
695
+ y.registerTool(S);
696
+ y.registerTool(E);
697
+ y.registerTool(P);
698
+ y.registerTool(A);
699
+ y.registerTool(U);
700
+ y.registerTool(I);
701
+ y.registerTool(M);
702
+ y.registerTool(R);
703
+ async function j() {
636
704
  const n = new C();
637
705
  await X.connect(n), console.error("OpenFDA MCP Server running on stdio");
638
706
  }
639
- S().catch((n) => {
707
+ j().catch((n) => {
640
708
  console.error("Fatal error in main():", n), process.exit(1);
641
709
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ythalorossy/openfda",
3
- "version": "1.0.18",
3
+ "version": "1.0.19",
4
4
  "description": "OpenFDA Model Context Protocol",
5
5
  "repository": {
6
6
  "type": "git",