@ythalorossy/openfda 1.0.18 → 1.1.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 (4) hide show
  1. package/LICENSE +20 -20
  2. package/README.md +101 -94
  3. package/dist/index.js +506 -345
  4. package/package.json +5 -4
package/dist/index.js CHANGED
@@ -1,14 +1,79 @@
1
1
  #!/usr/bin/env node
2
- var v = Object.defineProperty;
3
- var D = (n, t, r) => t in n ? v(n, t, { enumerable: !0, configurable: !0, writable: !0, value: r }) : n[t] = r;
4
- var k = (n, t, r) => D(n, typeof t != "symbol" ? t + "" : t, r);
5
- import { McpServer as N } from "@modelcontextprotocol/sdk/server/mcp.js";
6
- import { StdioServerTransport as C } from "@modelcontextprotocol/sdk/server/stdio.js";
7
- import l from "zod";
8
- class g {
2
+ var M = Object.defineProperty;
3
+ var G = (e, t, n) => t in e ? M(e, t, { enumerable: !0, configurable: !0, writable: !0, value: n }) : e[t] = n;
4
+ var D = (e, t, n) => G(e, typeof t != "symbol" ? t + "" : t, n);
5
+ import { McpServer as K } from "@modelcontextprotocol/sdk/server/mcp.js";
6
+ import { StdioServerTransport as L } from "@modelcontextprotocol/sdk/server/stdio.js";
7
+ import d from "zod";
8
+ const j = `OPENFDA_API_KEY is not set. This server reads the key from its process environment; a .env file is not loaded. Add it to the "env" block of your MCP client configuration. Get a free key at https://open.fda.gov/apis/authentication/
9
+
10
+ To run without a key on the unauthenticated tier (40 requests/minute, 1,000/day per IP, and no rate-limit headers), set OPENFDA_ALLOW_KEYLESS=1.`, q = "openfda: OPENFDA_ALLOW_KEYLESS=1 — using the unauthenticated tier (40 requests/minute, no rate-limit visibility). Set OPENFDA_API_KEY for 240 requests/minute.", Y = "openfda: OPENFDA_API_KEY is not set; every tool call will return a configuration error. See https://open.fda.gov/apis/authentication/";
11
+ function E(e = process.env) {
12
+ var n;
13
+ const t = (n = e.OPENFDA_API_KEY) == null ? void 0 : n.trim();
14
+ return t ? { ok: !0, apiKey: t } : e.OPENFDA_ALLOW_KEYLESS === "1" ? { ok: !0, apiKey: null } : { ok: !1, message: j };
15
+ }
16
+ function B(e = process.env) {
17
+ const t = E(e);
18
+ t.ok ? t.apiKey === null && console.error(q) : console.error(Y);
19
+ }
20
+ class J {
21
+ constructor(t) {
22
+ D(this, "registerTool", (t) => this.server.registerTool(
23
+ t.name,
24
+ {
25
+ title: t.name,
26
+ description: t.description,
27
+ inputSchema: t.inputSchema
28
+ },
29
+ async (n) => {
30
+ const a = E();
31
+ return a.ok ? t.handler(n) : {
32
+ content: [{ type: "text", text: a.message }],
33
+ isError: !0
34
+ };
35
+ }
36
+ ));
37
+ this.server = t;
38
+ }
39
+ }
40
+ const m = (e) => Array.isArray(e) ? e : [], P = (e) => {
41
+ const t = m(e.warnings);
42
+ return t.length > 0 ? t : m(e.warnings_and_cautions);
43
+ };
44
+ function W(e) {
45
+ return {
46
+ boxed_warning: m(e.boxed_warning),
47
+ warnings: P(e),
48
+ warnings_and_cautions: m(e.warnings_and_cautions),
49
+ contraindications: m(e.contraindications),
50
+ drug_interactions: m(e.drug_interactions),
51
+ precautions: m(e.precautions),
52
+ adverse_reactions: m(e.adverse_reactions),
53
+ overdosage: m(e.overdosage),
54
+ do_not_use: m(e.do_not_use),
55
+ ask_doctor: m(e.ask_doctor),
56
+ stop_use: m(e.stop_use),
57
+ pregnancy_or_breast_feeding: m(e.pregnancy_or_breast_feeding)
58
+ };
59
+ }
60
+ function V(e) {
61
+ return {
62
+ indications_and_usage: m(e.indications_and_usage),
63
+ boxed_warning: m(e.boxed_warning),
64
+ warnings: P(e),
65
+ warnings_and_cautions: m(e.warnings_and_cautions),
66
+ do_not_use: m(e.do_not_use),
67
+ ask_doctor: m(e.ask_doctor),
68
+ ask_doctor_or_pharmacist: m(e.ask_doctor_or_pharmacist),
69
+ stop_use: m(e.stop_use),
70
+ pregnancy_or_breast_feeding: m(e.pregnancy_or_breast_feeding)
71
+ };
72
+ }
73
+ class b {
9
74
  constructor() {
10
- k(this, "urlBase", "https://api.fda.gov");
11
- k(this, "params", /* @__PURE__ */ new Map());
75
+ D(this, "urlBase", "https://api.fda.gov");
76
+ D(this, "params", /* @__PURE__ */ new Map());
12
77
  }
13
78
  dataset(t) {
14
79
  return this.params.set("dataset", t), this;
@@ -23,230 +88,179 @@ class g {
23
88
  return this.params.set("limit", t), this;
24
89
  }
25
90
  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;
27
- if (!t || !r || !s)
91
+ const t = this.params.get("dataset"), n = this.params.get("context"), a = this.params.get("search"), i = this.params.get("limit") ?? 1;
92
+ if (!t || !n || !a)
28
93
  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;
94
+ const o = E(), s = new URLSearchParams();
95
+ return o.ok && o.apiKey && s.set("api_key", o.apiKey), s.set("search", String(a)), s.set("limit", String(i)), `${this.urlBase}/${t}/${n}.json?${s}`;
44
96
  }
45
97
  }
46
- const F = {
98
+ const C = (e) => e.replace(/([?&]api_key=)[^&\s]*/gi, "$1<REDACTED>"), z = {
47
99
  maxRetries: 3,
48
100
  retryDelay: 1e3,
49
101
  // 1 second
50
102
  timeout: 3e4
51
103
  // 30 seconds
52
104
  };
53
- function x(n) {
54
- return !!(n.name === "TypeError" && n.message.includes("fetch") || n.name === "AbortError" || n.status >= 500 && n.status <= 599 || n.status === 429);
105
+ function T(e) {
106
+ return !!(e.name === "TypeError" && e.message.includes("fetch") || e.name === "AbortError" || e.status >= 500 && e.status <= 599 || e.status === 429);
55
107
  }
56
- function w(n) {
57
- return new Promise((t) => setTimeout(t, n));
108
+ function F(e) {
109
+ return new Promise((t) => setTimeout(t, e));
58
110
  }
59
- async function y(n, t = {}) {
60
- const { maxRetries: r, retryDelay: s, timeout: e } = { ...F, ...t }, i = {
111
+ async function k(e, t = {}) {
112
+ const { maxRetries: n, retryDelay: a, timeout: i } = { ...z, ...t }, o = {
61
113
  "User-Agent": "@ythalorossy/openfda",
62
114
  Accept: "application/json"
63
115
  };
64
- let a = null;
65
- for (let p = 0; p <= r; p++)
116
+ let s = null;
117
+ for (let p = 0; p <= n; p++)
66
118
  try {
67
- const o = new AbortController(), d = setTimeout(() => o.abort(), e), c = await fetch(n, {
68
- headers: i,
69
- signal: o.signal
119
+ const c = new AbortController(), f = setTimeout(() => c.abort(), i), r = await fetch(e, {
120
+ headers: o,
121
+ signal: c.signal
70
122
  });
71
- if (clearTimeout(d), !c.ok) {
72
- const f = await c.text().catch(() => "Unable to read error response"), m = {
123
+ if (clearTimeout(f), !r.ok) {
124
+ const u = await r.text().catch(() => "Unable to read error response"), l = {
73
125
  type: "http",
74
- message: `HTTP ${c.status}: ${c.statusText}`,
75
- status: c.status,
76
- details: f
126
+ message: `HTTP ${r.status}: ${r.statusText}`,
127
+ status: r.status,
128
+ details: u
77
129
  };
78
- switch (c.status) {
130
+ switch (r.status) {
79
131
  case 400:
80
- m.message = "Bad Request: Invalid search query or parameters";
132
+ l.message = "Bad Request: Invalid search query or parameters";
81
133
  break;
82
134
  case 401:
83
- m.message = "Unauthorized: Invalid or missing API key";
135
+ l.message = "Unauthorized: Invalid or missing API key";
84
136
  break;
85
137
  case 403:
86
- m.message = "Forbidden: API key may be invalid or quota exceeded";
138
+ l.message = "Forbidden: API key may be invalid or quota exceeded";
87
139
  break;
88
140
  case 404:
89
- m.message = "Not Found: No results found for the specified query";
141
+ l.message = "Not Found: No results found for the specified query";
90
142
  break;
91
143
  case 429:
92
- m.message = "Rate Limited: Too many requests. Retrying...";
144
+ l.message = "Rate Limited: Too many requests. Retrying...";
93
145
  break;
94
146
  case 500:
95
- m.message = "Server Error: OpenFDA service is experiencing issues";
147
+ l.message = "Server Error: OpenFDA service is experiencing issues";
96
148
  break;
97
149
  default:
98
- m.message = `HTTP Error ${c.status}: ${c.statusText}`;
150
+ l.message = `HTTP Error ${r.status}: ${r.statusText}`;
99
151
  }
100
- if (a = m, c.status >= 400 && c.status < 500 && c.status !== 429)
152
+ if (s = l, r.status >= 400 && r.status < 500 && r.status !== 429)
101
153
  break;
102
- if (p < r && x({ status: c.status })) {
103
- const h = s * Math.pow(2, p);
104
- await w(h);
154
+ if (p < n && T({ status: r.status })) {
155
+ const h = a * Math.pow(2, p);
156
+ await F(h);
105
157
  continue;
106
158
  }
107
159
  break;
108
160
  }
109
- let u;
161
+ let g;
110
162
  try {
111
- u = await c.json();
112
- } catch (f) {
113
- a = {
163
+ g = await r.json();
164
+ } catch (u) {
165
+ s = {
114
166
  type: "parsing",
115
- message: `Failed to parse JSON response: ${f instanceof Error ? f.message : "Unknown parsing error"}`,
116
- details: f
167
+ message: C(
168
+ `Failed to parse JSON response: ${u instanceof Error ? u.message : "Unknown parsing error"}`
169
+ ),
170
+ details: u
117
171
  };
118
172
  break;
119
173
  }
120
- if (!u) {
121
- a = {
174
+ if (!g) {
175
+ s = {
122
176
  type: "empty_response",
123
177
  message: "Received empty response from OpenFDA API"
124
178
  };
125
179
  break;
126
180
  }
127
- return { data: u, error: null };
128
- } catch (o) {
129
- let d;
130
- if (o.name === "AbortError" ? d = {
181
+ return { data: g, error: null };
182
+ } catch (c) {
183
+ let f;
184
+ if (c.name === "AbortError" ? f = {
131
185
  type: "timeout",
132
- message: `Request timeout after ${e}ms`,
133
- details: o
134
- } : o instanceof TypeError && o.message.includes("fetch") ? d = {
186
+ message: `Request timeout after ${i}ms`,
187
+ details: c
188
+ } : c instanceof TypeError && c.message.includes("fetch") ? f = {
135
189
  type: "network",
136
190
  message: "Network error: Unable to connect to OpenFDA API",
137
- details: o.message
138
- } : d = {
191
+ details: c.message
192
+ } : f = {
139
193
  type: "unknown",
140
- message: `Unexpected error: ${o.message || "Unknown error occurred"}`,
141
- details: o
142
- }, a = d, p < r && x(o)) {
143
- const c = s * Math.pow(2, p);
144
- await w(c);
194
+ message: C(
195
+ `Unexpected error: ${c.message || "Unknown error occurred"}`
196
+ ),
197
+ details: c
198
+ }, s = f, p < n && T(c)) {
199
+ const r = a * Math.pow(2, p);
200
+ await F(r);
145
201
  continue;
146
202
  }
147
203
  break;
148
204
  }
149
- return { data: null, error: a };
205
+ return { data: null, error: s };
150
206
  }
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: {}
207
+ const X = [
208
+ "openfda.brand_name",
209
+ "openfda.generic_name",
210
+ "openfda.substance_name",
211
+ "spl_product_data_elements"
212
+ ];
213
+ async function O(e, t = 1) {
214
+ let n;
215
+ for (const a of X) {
216
+ const i = new b().dataset("drug").context("label").search(`${a}:"${e}"`).limit(t).build(), { data: o, error: s } = await k(i);
217
+ if (s) {
218
+ n = s;
219
+ continue;
161
220
  }
221
+ if (o != null && o.results && o.results.length > 0)
222
+ return { found: !0, matched_via: a, data: o };
162
223
  }
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 };
224
+ return { found: !1, error: n };
183
225
  }
184
- b.registerTool({
185
- name: "get-drug-by-name",
186
- 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")
189
- }),
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);
192
- if (s) {
193
- let a = `Failed to retrieve drug data for "${n}": ${s.message}`;
194
- switch (s.type) {
195
- case "http":
196
- s.status === 404 ? a += `${t}
197
-
198
- Suggestions:
199
- - Verify the exact brand name spelling
200
- - Try searching for the generic name instead
201
- - Check if the drug is FDA-approved` : (s.status === 401 || s.status === 403) && (a += `
226
+ const U = (e) => `No label found for "${e}".
202
227
 
203
- Please check the API key configuration.`);
204
- break;
205
- case "network":
206
- a += `
207
-
208
- Please check your internet connection and try again.`;
209
- break;
210
- case "timeout":
211
- a += `
228
+ Searched, in order: ${X.join(", ")}.
212
229
 
213
- The request took too long. Please try again.`;
214
- break;
215
- }
216
- return {
230
+ Suggestions:
231
+ - Check the spelling.
232
+ - Try the generic name instead of the brand (e.g. "amiodarone" rather than "Cordarone").
233
+ - Try the originator brand rather than a repackager's name.
234
+ - Some discontinued brands have no current FDA label.`, H = {
235
+ name: "get-drug-by-name",
236
+ description: "Get drug information by brand name, generic name, or active substance. 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. The response reports which field matched via matched_via.",
237
+ inputSchema: d.object({
238
+ drugName: d.string().describe("Drug name")
239
+ }),
240
+ async handler({ drugName: e }) {
241
+ const t = await O(e, 1);
242
+ if (!t.found)
243
+ return t.error ? {
217
244
  content: [
218
245
  {
219
246
  type: "text",
220
- text: a
247
+ text: `Failed to retrieve drug data for "${e}": ${t.error.message}`
221
248
  }
222
249
  ],
223
250
  isError: !0
251
+ } : {
252
+ content: [{ type: "text", text: U(e) }]
224
253
  };
225
- }
226
- if (!(r != null && r.results) || r.results.length === 0)
227
- return {
228
- content: [
229
- {
230
- type: "text",
231
- text: `No drug information found for "${n}". Please verify the brand name spelling or try searching for the generic name.`
232
- }
233
- ]
234
- };
235
- const e = r.results[0], i = {
236
- brand_name: e == null ? void 0 : e.openfda.brand_name,
237
- generic_name: e == null ? void 0 : e.openfda.generic_name,
238
- manufacturer_name: e == null ? void 0 : e.openfda.manufacturer_name,
239
- product_ndc: e == null ? void 0 : e.openfda.product_ndc,
240
- product_type: e == null ? void 0 : e.openfda.product_type,
241
- route: e == null ? void 0 : e.openfda.route,
242
- substance_name: e == null ? void 0 : e.openfda.substance_name,
243
- indications_and_usage: e == null ? void 0 : e.indications_and_usage,
244
- warnings: e == null ? void 0 : e.warnings,
245
- do_not_use: e == null ? void 0 : e.do_not_use,
246
- ask_doctor: e == null ? void 0 : e.ask_doctor,
247
- ask_doctor_or_pharmacist: e == null ? void 0 : e.ask_doctor_or_pharmacist,
248
- stop_use: e == null ? void 0 : e.stop_use,
249
- pregnancy_or_breast_feeding: e == null ? void 0 : e.pregnancy_or_breast_feeding
254
+ const n = t.data.results[0], a = {
255
+ brand_name: n == null ? void 0 : n.openfda.brand_name,
256
+ generic_name: n == null ? void 0 : n.openfda.generic_name,
257
+ manufacturer_name: n == null ? void 0 : n.openfda.manufacturer_name,
258
+ product_ndc: n == null ? void 0 : n.openfda.product_ndc,
259
+ product_type: n == null ? void 0 : n.openfda.product_type,
260
+ route: n == null ? void 0 : n.openfda.route,
261
+ substance_name: n == null ? void 0 : n.openfda.substance_name,
262
+ matched_via: t.matched_via,
263
+ ...V(n)
250
264
  };
251
265
  return {
252
266
  content: [
@@ -254,238 +268,294 @@ The request took too long. Please try again.`;
254
268
  type: "text",
255
269
  text: `Drug information retrieved successfully:
256
270
 
257
- ${JSON.stringify(i, null, 2)}`
271
+ ${JSON.stringify(a, null, 2)}`
258
272
  }
259
273
  ]
260
274
  };
261
275
  }
262
- });
263
- b.registerTool({
276
+ };
277
+ function N(e, t, n) {
278
+ return typeof t != "number" ? `Showing ${e} ${n} (total unknown)` : e >= t ? `Showing all ${t} ${n}` : `Showing ${e} of ${t} ${n}`;
279
+ }
280
+ function S(e, t, n) {
281
+ return {
282
+ total: typeof t == "number" ? t : null,
283
+ returned: e.length,
284
+ limit: n,
285
+ results: e
286
+ };
287
+ }
288
+ const Q = {
264
289
  name: "get-drug-by-generic-name",
265
290
  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")
291
+ inputSchema: d.object({
292
+ genericName: d.string().describe("Generic drug name (active ingredient)"),
293
+ limit: d.number().optional().default(5).describe("Maximum number of results to return")
269
294
  }),
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);
272
- if (e)
295
+ async handler({
296
+ genericName: e,
297
+ limit: t
298
+ }) {
299
+ var s, p, c, f;
300
+ const n = new b().dataset("drug").context("label").search(`openfda.generic_name:"${e}"`).limit(t).build(), { data: a, error: i } = await k(n);
301
+ if (i)
273
302
  return {
274
303
  content: [
275
304
  {
276
305
  type: "text",
277
- text: `Failed to retrieve drug data for generic name "${n}": ${e.message}`
306
+ text: `Failed to retrieve drug data for generic name "${e}": ${i.message}`
278
307
  }
279
308
  ],
280
309
  isError: !0
281
310
  };
282
- if (!(s != null && s.results) || s.results.length === 0)
311
+ if (!(a != null && a.results) || a.results.length === 0)
283
312
  return {
284
313
  content: [
285
314
  {
286
315
  type: "text",
287
- text: `No drug information found for generic name "${n}".`
316
+ text: `No drug information found for generic name "${e}".`
288
317
  }
289
318
  ]
290
319
  };
291
- const i = s.results.map((a) => {
292
- var p, o, d, c;
320
+ const o = a.results.map((r) => {
321
+ var g, u, l, h;
293
322
  return {
294
- 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",
297
- product_type: ((c = a == null ? void 0 : a.openfda.product_type) == null ? void 0 : c[0]) || "Unknown",
298
- route: (a == null ? void 0 : a.openfda.route) || []
323
+ brand_name: ((g = r == null ? void 0 : r.openfda.brand_name) == null ? void 0 : g[0]) || "Unknown",
324
+ generic_name: ((u = r == null ? void 0 : r.openfda.generic_name) == null ? void 0 : u[0]) || "Unknown",
325
+ manufacturer_name: ((l = r == null ? void 0 : r.openfda.manufacturer_name) == null ? void 0 : l[0]) || "Unknown",
326
+ product_type: ((h = r == null ? void 0 : r.openfda.product_type) == null ? void 0 : h[0]) || "Unknown",
327
+ route: (r == null ? void 0 : r.openfda.route) || []
299
328
  };
300
329
  });
301
330
  return {
302
331
  content: [
303
332
  {
304
333
  type: "text",
305
- text: `Found ${i.length} drug(s) with generic name "${n}":
334
+ text: `${N(o.length, (p = (s = a.meta) == null ? void 0 : s.results) == null ? void 0 : p.total, `labels with generic name "${e}"`)}
306
335
 
307
- ${JSON.stringify(i, null, 2)}`
336
+ ${JSON.stringify(S(o, (f = (c = a.meta) == null ? void 0 : c.results) == null ? void 0 : f.total, t ?? 5), null, 2)}`
308
337
  }
309
338
  ]
310
339
  };
311
340
  }
312
- });
313
- b.registerTool({
341
+ }, Z = {
342
+ 1: "Recovered/resolved",
343
+ 2: "Recovering/resolving",
344
+ 3: "Not recovered/not resolved",
345
+ 4: "Recovered/resolved with sequelae",
346
+ 5: "Fatal",
347
+ 6: "Unknown"
348
+ };
349
+ function ee(e) {
350
+ if (e == null || e === "") return "Not reported";
351
+ const t = String(e);
352
+ return Z[t] ?? `Unrecognized outcome code "${t}"`;
353
+ }
354
+ function te(e) {
355
+ const t = /* @__PURE__ */ new Set(), n = [];
356
+ for (const a of e) {
357
+ const i = a == null ? void 0 : a.reactionmeddrapt;
358
+ if (!i) continue;
359
+ const o = `${i}\0${String(a == null ? void 0 : a.reactionoutcome)}`;
360
+ t.has(o) || (t.add(o), n.push({ reaction: i, outcome: a == null ? void 0 : a.reactionoutcome }));
361
+ }
362
+ return n.slice(0, 3);
363
+ }
364
+ const ne = {
314
365
  name: "get-drug-adverse-events",
315
366
  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")
367
+ inputSchema: d.object({
368
+ drugName: d.string().describe("Drug name (brand or generic)"),
369
+ limit: d.number().optional().default(10).describe("Maximum number of events to return"),
370
+ seriousness: d.enum(["serious", "non-serious", "all"]).optional().default("all").describe("Filter by event seriousness")
320
371
  }),
321
- handler: async ({ drugName: n, limit: t, seriousness: r }) => {
322
- let s = `patient.drug.medicinalproduct:"${n}"`;
323
- 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);
325
- if (a)
372
+ async handler({
373
+ drugName: e,
374
+ limit: t,
375
+ seriousness: n
376
+ }) {
377
+ var c, f, r, g;
378
+ let a = `patient.drug.medicinalproduct:"${e}"`;
379
+ n !== "all" && (a += ` AND serious:${n === "serious" ? "1" : "2"}`);
380
+ const i = new b().dataset("drug").context("event").search(a).limit(t).build(), { data: o, error: s } = await k(i);
381
+ if (s)
326
382
  return {
327
383
  content: [
328
384
  {
329
385
  type: "text",
330
- text: `Failed to retrieve adverse events for "${n}": ${a.message}`
386
+ text: `Failed to retrieve adverse events for "${e}": ${s.message}`
331
387
  }
332
388
  ],
333
389
  isError: !0
334
390
  };
335
- if (!(i != null && i.results) || i.results.length === 0)
391
+ if (!(o != null && o.results) || o.results.length === 0)
336
392
  return {
337
393
  content: [
338
394
  {
339
395
  type: "text",
340
- text: `No adverse events found for "${n}".`
396
+ text: `No adverse events found for "${e}".`
341
397
  }
342
398
  ]
343
399
  };
344
- const p = i.results.map((o) => {
345
- var d, c, u, f, m, h, $;
400
+ const p = o.results.map((u) => {
401
+ var h, _, $, v;
402
+ const l = te(((h = u.patient) == null ? void 0 : h.reaction) ?? []);
346
403
  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"
404
+ report_id: u.safetyreportid,
405
+ serious: u.serious === "1" ? "Yes" : "No",
406
+ patient_age: ((_ = u.patient) == null ? void 0 : _.patientonsetage) || "Unknown",
407
+ patient_sex: (($ = u.patient) == null ? void 0 : $.patientsex) === "1" ? "Male" : ((v = u.patient) == null ? void 0 : v.patientsex) === "2" ? "Female" : "Unknown",
408
+ // Derived from the same deduped pairs so the two arrays stay the
409
+ // same length and positionally aligned (see dedupeReactionPairs).
410
+ reactions: l.map((w) => w.reaction),
411
+ outcomes: l.map((w) => ee(w.outcome)),
412
+ report_date: u.receiptdate || "Unknown"
354
413
  };
355
414
  });
356
415
  return {
357
416
  content: [
358
417
  {
359
418
  type: "text",
360
- text: `Found ${p.length} adverse event report(s) for "${n}":
419
+ text: `${N(p.length, (f = (c = o.meta) == null ? void 0 : c.results) == null ? void 0 : f.total, `adverse event reports for "${e}"`)}
361
420
 
362
- ${JSON.stringify(p, null, 2)}`
421
+ ${JSON.stringify(S(p, (g = (r = o.meta) == null ? void 0 : r.results) == null ? void 0 : g.total, t ?? 10), null, 2)}`
363
422
  }
364
423
  ]
365
424
  };
366
425
  }
367
- });
368
- b.registerTool({
426
+ }, ae = {
369
427
  name: "get-drugs-by-manufacturer",
370
428
  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")
429
+ inputSchema: d.object({
430
+ manufacturerName: d.string().describe("Manufacturer/company name"),
431
+ limit: d.number().optional().default(20).describe("Maximum number of drugs to return")
374
432
  }),
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);
377
- if (e)
433
+ async handler({
434
+ manufacturerName: e,
435
+ limit: t
436
+ }) {
437
+ var s, p, c, f;
438
+ const n = new b().dataset("drug").context("label").search(`openfda.manufacturer_name:"${e}"`).limit(t).build(), { data: a, error: i } = await k(n);
439
+ if (i)
378
440
  return {
379
441
  content: [
380
442
  {
381
443
  type: "text",
382
- text: `${r}
383
- Failed to retrieve drugs for manufacturer "${n}": ${e.message}`
444
+ text: `Failed to retrieve drugs for manufacturer "${e}": ${i.message}`
384
445
  }
385
446
  ],
386
447
  isError: !0
387
448
  };
388
- if (!(s != null && s.results) || s.results.length === 0)
449
+ if (!(a != null && a.results) || a.results.length === 0)
389
450
  return {
390
451
  content: [
391
452
  {
392
453
  type: "text",
393
- text: `No drugs found for manufacturer "${n}".`
454
+ text: `No drugs found for manufacturer "${e}".`
394
455
  }
395
456
  ]
396
457
  };
397
- const i = s.results.map((a) => {
398
- var p, o, d, c;
458
+ const o = a.results.map((r) => {
459
+ var g, u, l, h;
399
460
  return {
400
- 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",
403
- route: (a == null ? void 0 : a.openfda.route) || [],
404
- ndc: ((c = a == null ? void 0 : a.openfda.product_ndc) == null ? void 0 : c[0]) || "Unknown"
461
+ brand_name: ((g = r == null ? void 0 : r.openfda.brand_name) == null ? void 0 : g[0]) || "Unknown",
462
+ generic_name: ((u = r == null ? void 0 : r.openfda.generic_name) == null ? void 0 : u[0]) || "Unknown",
463
+ product_type: ((l = r == null ? void 0 : r.openfda.product_type) == null ? void 0 : l[0]) || "Unknown",
464
+ route: (r == null ? void 0 : r.openfda.route) || [],
465
+ ndc: ((h = r == null ? void 0 : r.openfda.product_ndc) == null ? void 0 : h[0]) || "Unknown"
405
466
  };
406
467
  });
407
468
  return {
408
469
  content: [
409
470
  {
410
471
  type: "text",
411
- text: `Found ${i.length} drug(s) from manufacturer "${n}":
472
+ text: `${N(o.length, (p = (s = a.meta) == null ? void 0 : s.results) == null ? void 0 : p.total, `labels from manufacturer "${e}"`)}
412
473
 
413
- ${JSON.stringify(i, null, 2)}`
474
+ ${JSON.stringify(S(o, (f = (c = a.meta) == null ? void 0 : c.results) == null ? void 0 : f.total, t ?? 20), null, 2)}`
414
475
  }
415
476
  ]
416
477
  };
417
478
  }
418
- });
419
- b.registerTool({
479
+ }, re = {
420
480
  name: "get-drug-safety-info",
421
- 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")
481
+ description: "Get comprehensive safety information for a drug including the boxed warning, warnings and cautions, contraindications, drug interactions, and precautions. Accepts a brand name, generic name, or active substance; the response reports which field matched via matched_via.",
482
+ inputSchema: d.object({
483
+ drugName: d.string().describe("Drug brand name")
424
484
  }),
425
- handler: async ({ drugName: n }) => {
426
- 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);
428
- if (s)
429
- return {
485
+ async handler({ drugName: e }) {
486
+ var i, o;
487
+ const t = await O(e, 1);
488
+ if (!t.found)
489
+ return t.error ? {
430
490
  content: [
431
491
  {
432
492
  type: "text",
433
- text: `Failed to retrieve safety information for "${n}": ${s.message}`
493
+ text: `Failed to retrieve safety information for "${e}": ${t.error.message}`
434
494
  }
435
495
  ],
436
496
  isError: !0
497
+ } : {
498
+ content: [{ type: "text", text: U(e) }]
437
499
  };
438
- if (!(r != null && r.results) || r.results.length === 0)
439
- return {
440
- content: [
441
- {
442
- type: "text",
443
- text: `No safety information found for "${n}".`
444
- }
445
- ]
446
- };
447
- const e = r.results[0], i = {
448
- drug_name: ((a = e == null ? void 0 : e.openfda.brand_name) == null ? void 0 : a[0]) || n,
449
- generic_name: ((p = e == null ? void 0 : e.openfda.generic_name) == null ? void 0 : p[0]) || "Unknown",
450
- warnings: (e == null ? void 0 : e.warnings) || [],
451
- contraindications: (e == null ? void 0 : e.contraindications) || [],
452
- drug_interactions: (e == null ? void 0 : e.drug_interactions) || [],
453
- precautions: (e == null ? void 0 : e.precautions) || [],
454
- adverse_reactions: (e == null ? void 0 : e.adverse_reactions) || [],
455
- overdosage: (e == null ? void 0 : e.overdosage) || [],
456
- do_not_use: (e == null ? void 0 : e.do_not_use) || [],
457
- ask_doctor: (e == null ? void 0 : e.ask_doctor) || [],
458
- stop_use: (e == null ? void 0 : e.stop_use) || [],
459
- pregnancy_or_breast_feeding: (e == null ? void 0 : e.pregnancy_or_breast_feeding) || []
500
+ const n = t.data.results[0], a = {
501
+ drug_name: ((i = n == null ? void 0 : n.openfda.brand_name) == null ? void 0 : i[0]) || e,
502
+ generic_name: ((o = n == null ? void 0 : n.openfda.generic_name) == null ? void 0 : o[0]) || "Unknown",
503
+ matched_via: t.matched_via,
504
+ ...W(n)
460
505
  };
461
506
  return {
462
507
  content: [
463
508
  {
464
509
  type: "text",
465
- text: `Safety information for "${n}":
510
+ text: `Safety information for "${e}":
466
511
 
467
- ${JSON.stringify(i, null, 2)}`
512
+ ${JSON.stringify(a, null, 2)}`
468
513
  }
469
514
  ]
470
515
  };
471
516
  }
472
- });
473
- b.registerTool({
517
+ }, se = /^(?:\d{4}-\d{4}|\d{5}-\d{3,4})$/, oe = /^\d{1,2}$/;
518
+ function I(e) {
519
+ const t = e.trim().toUpperCase(), n = { productNDC: t, packageNDC: null, isValid: !1 };
520
+ let a, i = null;
521
+ if (t.includes("-")) {
522
+ const o = t.split("-");
523
+ if (o.length === 2)
524
+ a = t;
525
+ else if (o.length === 3) {
526
+ const s = o[2];
527
+ if (!s || !oe.test(s)) return n;
528
+ a = `${o[0]}-${o[1]}`, i = t;
529
+ } else
530
+ return n;
531
+ } else if (/^\d+$/.test(t))
532
+ if (t.length === 11)
533
+ a = `${t.slice(0, 5)}-${t.slice(5, 9)}`, i = `${a}-${t.slice(9, 11)}`;
534
+ else if (t.length === 9)
535
+ a = `${t.slice(0, 5)}-${t.slice(5, 9)}`;
536
+ else
537
+ return n;
538
+ else
539
+ return n;
540
+ return se.test(a) ? { productNDC: a, packageNDC: i, isValid: !0 } : n;
541
+ }
542
+ const ie = {
474
543
  name: "get-drug-by-ndc",
475
544
  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(
545
+ inputSchema: d.object({
546
+ ndcCode: d.string().describe(
478
547
  "National Drug Code (NDC) - accepts formats: XXXXX-XXXX, XXXXX-XXXX-XX, or without dashes"
479
548
  )
480
549
  }),
481
- handler: async ({ ndcCode: n }) => {
482
- const { productNDC: t, packageNDC: r, isValid: s } = E(n);
483
- if (!s)
550
+ async handler({ ndcCode: e }) {
551
+ var g, u, l, h;
552
+ const { productNDC: t, packageNDC: n, isValid: a } = I(e);
553
+ if (!a)
484
554
  return {
485
555
  content: [
486
556
  {
487
557
  type: "text",
488
- text: `Invalid NDC format: "${n}"
558
+ text: `Invalid NDC format: "${e}"
489
559
 
490
560
  ✅ Accepted formats:
491
561
  • Product NDC: 12345-1234
@@ -495,25 +565,25 @@ b.registerTool({
495
565
  ],
496
566
  isError: !0
497
567
  };
498
- let e = `openfda.product_ndc:"${t}"`;
499
- 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);
568
+ let i = `openfda.product_ndc:"${t}"`;
569
+ n && (i += ` OR openfda.package_ndc:"${n}"`);
570
+ const o = new b().dataset("drug").context("label").search(i).limit(10).build(), { data: s, error: p } = await k(o);
501
571
  if (p)
502
572
  return {
503
573
  content: [
504
574
  {
505
575
  type: "text",
506
- text: `Failed to retrieve drug data for NDC "${n}": ${p.message}`
576
+ text: `Failed to retrieve drug data for NDC "${e}": ${p.message}`
507
577
  }
508
578
  ],
509
579
  isError: !0
510
580
  };
511
- if (!(a != null && a.results) || a.results.length === 0)
581
+ if (!(s != null && s.results) || s.results.length === 0)
512
582
  return {
513
583
  content: [
514
584
  {
515
585
  type: "text",
516
- text: `No drug found with NDC "${n}" (product: ${t}).
586
+ text: `No drug found with NDC "${e}" (product: ${t}).
517
587
 
518
588
  💡 Tips:
519
589
  • Verify the NDC format
@@ -522,120 +592,211 @@ b.registerTool({
522
592
  }
523
593
  ]
524
594
  };
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(
528
- (_) => r ? _ === r : _.startsWith(t)
595
+ const c = s.results.map((_) => {
596
+ var w, A;
597
+ const $ = ((w = _.openfda.product_ndc) == null ? void 0 : w.filter((x) => x === t)) || [], v = ((A = _.openfda.package_ndc) == null ? void 0 : A.filter(
598
+ (x) => n ? x === n : x.startsWith(t)
529
599
  )) || [];
530
600
  return {
531
- // Basic drug information
532
- brand_name: u.openfda.brand_name || [],
533
- generic_name: u.openfda.generic_name || [],
534
- manufacturer_name: u.openfda.manufacturer_name || [],
535
- product_type: u.openfda.product_type || [],
536
- route: u.openfda.route || [],
537
- substance_name: u.openfda.substance_name || [],
538
- // NDC information
539
- matching_product_ndc: f,
540
- matching_package_ndc: m,
541
- all_product_ndc: u.openfda.product_ndc || [],
542
- all_package_ndc: u.openfda.package_ndc || [],
543
- // Additional product details
544
- dosage_and_administration: u.dosage_and_administration || [],
545
- package_label_principal_display_panel: u.package_label_principal_display_panel || [],
546
- active_ingredient: u.active_ingredient || [],
547
- purpose: u.purpose || []
601
+ brand_name: _.openfda.brand_name || [],
602
+ generic_name: _.openfda.generic_name || [],
603
+ manufacturer_name: _.openfda.manufacturer_name || [],
604
+ product_type: _.openfda.product_type || [],
605
+ route: _.openfda.route || [],
606
+ substance_name: _.openfda.substance_name || [],
607
+ matching_product_ndc: $,
608
+ matching_package_ndc: v,
609
+ all_product_ndc: _.openfda.product_ndc || [],
610
+ all_package_ndc: _.openfda.package_ndc || [],
611
+ dosage_and_administration: _.dosage_and_administration || [],
612
+ package_label_principal_display_panel: _.package_label_principal_display_panel || [],
613
+ active_ingredient: _.active_ingredient || [],
614
+ purpose: _.purpose || []
548
615
  };
549
- }), d = o.reduce(
550
- (u, f) => u + f.matching_package_ndc.length,
616
+ }), f = c.reduce(
617
+ (_, $) => _ + $.matching_package_ndc.length,
551
618
  0
552
- ), c = r ? `Searched for specific package NDC: ${r}` : `Searched for product NDC: ${t} (all packages)`;
619
+ ), r = n ? `Searched for specific package NDC: ${n}` : `Searched for product NDC: ${t} (all packages)`;
553
620
  return {
554
621
  content: [
555
622
  {
556
623
  type: "text",
557
- text: `✅ Found ${o.length} drug(s) with ${d} package(s) for NDC "${n}"
624
+ text: `${N(c.length, (u = (g = s.meta) == null ? void 0 : g.results) == null ? void 0 : u.total, `labels for NDC "${e}"`)} with ${f} package(s)
558
625
 
559
- ${c}
626
+ ${r}
560
627
 
561
- ${JSON.stringify(o, null, 2)}`
628
+ ${JSON.stringify(S(c, (h = (l = s.meta) == null ? void 0 : l.results) == null ? void 0 : h.total, 10), null, 2)}`
562
629
  }
563
630
  ]
564
631
  };
565
632
  }
566
- });
567
- b.registerTool({
633
+ }, ce = {
568
634
  name: "get-drug-by-product-ndc",
569
- 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")
635
+ description: "Get drug information by product NDC. Accepts the dashed forms 4-4 (0456-4020), 5-3 (58151-155) and 5-4 (12345-1234), plus undashed 9-digit (5-4) and 11-digit (5-4-2) input. Undashed 8- and 10-digit input is rejected as ambiguous — dash it. This ignores package variations and finds all packages for a product.",
636
+ inputSchema: d.object({
637
+ productNDC: d.string().describe(
638
+ "Product NDC: dashed 4-4 (0456-4020), 5-3 (58151-155) or 5-4 (12345-1234); undashed 9-digit (123451234) or 11-digit (12345123401) also work"
639
+ )
572
640
  }),
573
- handler: async ({ productNDC: n }) => {
574
- var p;
575
- if (!/^\d{5}-\d{4}$/.test(n.trim()))
641
+ async handler({ productNDC: e }) {
642
+ var f;
643
+ const { productNDC: t, isValid: n } = I(e);
644
+ if (!n)
576
645
  return {
577
646
  content: [
578
647
  {
579
648
  type: "text",
580
- text: `Invalid product NDC format: "${n}"
649
+ text: `Invalid product NDC format: "${e}"
581
650
 
582
- Required format: XXXXX-XXXX (e.g., 12345-1234)`
651
+ Accepted formats:
652
+ • 4-4 product NDC: 0456-4020
653
+ • 5-3 product NDC: 58151-155
654
+ • 5-4 product NDC: 12345-1234
655
+ • Undashed 9 digits: 123451234 (read as 5-4)
656
+ • Undashed 11 digits: 12345123401 (read as 5-4-2)
657
+
658
+ Undashed 8- and 10-digit input is rejected because the split is ambiguous: 8 digits could be 5-3 or 4-4, and 10 could be 4-4-2, 5-3-2 or 5-4-1. Guessing could return a different drug, so add the dashes instead.`
583
659
  }
584
660
  ],
585
661
  isError: !0
586
662
  };
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);
588
- if (s)
663
+ const a = new b().dataset("drug").context("label").search(`openfda.product_ndc:"${t}"`).limit(1).build(), { data: i, error: o } = await k(a);
664
+ if (o)
589
665
  return {
590
666
  content: [
591
667
  {
592
668
  type: "text",
593
- text: `${t}Failed to retrieve drug data for product NDC "${n}": ${s.message}`
669
+ text: `Failed to retrieve drug data for product NDC "${e}": ${o.message}`
594
670
  }
595
671
  ],
596
672
  isError: !0
597
673
  };
598
- if (!(r != null && r.results) || r.results.length === 0)
674
+ if (!(i != null && i.results) || i.results.length === 0)
599
675
  return {
600
676
  content: [
601
677
  {
602
678
  type: "text",
603
- text: `No drug found with product NDC "${n}".`
679
+ text: `No drug found with product NDC "${e}".`
604
680
  }
605
681
  ],
606
682
  structuredContent: null
607
683
  };
608
- const e = r.results[0], i = ((p = e.openfda.package_ndc) == null ? void 0 : p.filter(
609
- (o) => o.startsWith(n.trim())
610
- )) || [], a = {
611
- product_ndc: n,
612
- available_packages: i,
613
- brand_name: e.openfda.brand_name || [],
614
- generic_name: e.openfda.generic_name || [],
615
- manufacturer_name: e.openfda.manufacturer_name || [],
616
- product_type: e.openfda.product_type || [],
617
- route: e.openfda.route || [],
618
- substance_name: e.openfda.substance_name || [],
619
- active_ingredient: e.active_ingredient || [],
620
- purpose: e.purpose || [],
621
- dosage_and_administration: e.dosage_and_administration || []
684
+ const s = i.results[0], p = ((f = s.openfda.package_ndc) == null ? void 0 : f.filter(
685
+ (r) => r.startsWith(t)
686
+ )) || [], c = {
687
+ product_ndc: t,
688
+ available_packages: p,
689
+ brand_name: s.openfda.brand_name || [],
690
+ generic_name: s.openfda.generic_name || [],
691
+ manufacturer_name: s.openfda.manufacturer_name || [],
692
+ product_type: s.openfda.product_type || [],
693
+ route: s.openfda.route || [],
694
+ substance_name: s.openfda.substance_name || [],
695
+ active_ingredient: s.active_ingredient || [],
696
+ purpose: s.purpose || [],
697
+ dosage_and_administration: s.dosage_and_administration || []
622
698
  };
623
699
  return {
624
700
  content: [
625
701
  {
626
702
  type: "text",
627
- text: `✅ Product NDC "${n}" found with ${i.length} package variation(s):
703
+ text: `✅ Product NDC "${t}" found with ${p.length} package variation(s):
628
704
 
629
- ${JSON.stringify(a, null, 2)}`
705
+ ${JSON.stringify(c, null, 2)}`
630
706
  }
631
707
  ]
632
708
  };
633
709
  }
634
- });
635
- async function S() {
636
- const n = new C();
637
- await X.connect(n), console.error("OpenFDA MCP Server running on stdio");
710
+ }, ue = {
711
+ name: "get-drugsfda",
712
+ 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.",
713
+ inputSchema: d.object({
714
+ sectionName: d.string().describe(
715
+ "Section within drugsfda. Valid values: application, openfda, products, submissions, application_docs"
716
+ ),
717
+ fieldName: d.string().describe(
718
+ "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"
719
+ ),
720
+ searchValue: d.string().describe("Value to search for in the specified field")
721
+ }),
722
+ async handler({
723
+ sectionName: e,
724
+ fieldName: t,
725
+ searchValue: n
726
+ }) {
727
+ const a = new b().dataset("drug").context("drugsfda").search(`${e}.${t}:"${n}"`).limit(1).build(), { data: i, error: o } = await k(a);
728
+ if (o) {
729
+ let s = `Failed to retrieve drugsfda data for "${n}" in ${e}.${t}: ${o.message}`;
730
+ switch (o.type) {
731
+ case "http":
732
+ o.status === 404 ? s += `
733
+
734
+ Suggestions:
735
+ - Verify the field name is correct for the section
736
+ - Check the search value spelling` : (o.status === 401 || o.status === 403) && (s += `
737
+
738
+ Please check the API key configuration.`);
739
+ break;
740
+ case "network":
741
+ s += `
742
+
743
+ Please check your internet connection and try again.`;
744
+ break;
745
+ case "timeout":
746
+ s += `
747
+
748
+ The request took too long. Please try again.`;
749
+ break;
750
+ }
751
+ return {
752
+ content: [{ type: "text", text: s }],
753
+ isError: !0
754
+ };
755
+ }
756
+ return !(i != null && i.results) || i.results.length === 0 ? {
757
+ content: [
758
+ {
759
+ type: "text",
760
+ text: `No drugsfda data found for "${n}" in ${e}.${t}. Please verify the search parameters.`
761
+ }
762
+ ]
763
+ } : {
764
+ content: [
765
+ {
766
+ type: "text",
767
+ text: `drugsfda data retrieved successfully:
768
+
769
+ ${JSON.stringify(i.results[0], null, 2)}`
770
+ }
771
+ ]
772
+ };
773
+ }
774
+ }, de = "1.1.0", R = new K(
775
+ {
776
+ name: "openfda",
777
+ version: de,
778
+ description: "OpenFDA Model Context Protocol"
779
+ },
780
+ {
781
+ capabilities: {
782
+ resources: {},
783
+ tools: {}
784
+ }
785
+ }
786
+ ), y = new J(R);
787
+ y.registerTool(H);
788
+ y.registerTool(Q);
789
+ y.registerTool(ne);
790
+ y.registerTool(ae);
791
+ y.registerTool(re);
792
+ y.registerTool(ie);
793
+ y.registerTool(ce);
794
+ y.registerTool(ue);
795
+ async function pe() {
796
+ B();
797
+ const e = new L();
798
+ await R.connect(e), console.error("OpenFDA MCP Server running on stdio");
638
799
  }
639
- S().catch((n) => {
640
- console.error("Fatal error in main():", n), process.exit(1);
800
+ pe().catch((e) => {
801
+ console.error("Fatal error in main():", e), process.exit(1);
641
802
  });