@ythalorossy/openfda 1.0.17 → 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.
- package/README.md +23 -12
- package/dist/index.js +355 -295
- package/package.json +2 -1
package/README.md
CHANGED
|
@@ -34,18 +34,29 @@ A Model Context Protocol (MCP) server for querying drug information from the Ope
|
|
|
34
34
|
If you are integrating this server with a larger MCP system, your configuration might look like:
|
|
35
35
|
|
|
36
36
|
```json
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
37
|
+
{
|
|
38
|
+
"mcpServers": {
|
|
39
|
+
"openfda": {
|
|
40
|
+
"command": "npx",
|
|
41
|
+
"args": [
|
|
42
|
+
"@ythalorossy/openfda"
|
|
43
|
+
],
|
|
44
|
+
"env": {
|
|
45
|
+
"OPENFDA_API_KEY": "*****************************************"
|
|
46
|
+
},
|
|
47
|
+
"timeout": 60000,
|
|
48
|
+
"autoApprove": [
|
|
49
|
+
"get-drug-by-name",
|
|
50
|
+
"get-drug-by-generic-name",
|
|
51
|
+
"get-drug-adverse-events",
|
|
52
|
+
"get-drugs-by-manufacturer",
|
|
53
|
+
"get-drug-safety-info",
|
|
54
|
+
"get-drug-by-ndc",
|
|
55
|
+
"get-drug-by-product-ndc"
|
|
56
|
+
]
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
49
60
|
```
|
|
50
61
|
|
|
51
62
|
Replace the asterisks with your actual API key, or ensure it is loaded from your `.env` file.
|
package/dist/index.js
CHANGED
|
@@ -1,44 +1,46 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
var
|
|
3
|
-
var
|
|
4
|
-
var k = (
|
|
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
5
|
import { McpServer as N } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
6
|
-
import { StdioServerTransport as
|
|
7
|
-
import
|
|
8
|
-
class
|
|
6
|
+
import { StdioServerTransport as C } from "@modelcontextprotocol/sdk/server/stdio.js";
|
|
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
|
+
}
|
|
22
|
+
class g {
|
|
9
23
|
constructor() {
|
|
10
|
-
k(this, "
|
|
24
|
+
k(this, "urlBase", "https://api.fda.gov");
|
|
11
25
|
k(this, "params", /* @__PURE__ */ new Map());
|
|
12
26
|
}
|
|
13
|
-
|
|
14
|
-
return this.params.set("
|
|
27
|
+
dataset(t) {
|
|
28
|
+
return this.params.set("dataset", t), this;
|
|
15
29
|
}
|
|
16
|
-
|
|
17
|
-
return this.params.set("
|
|
30
|
+
context(t) {
|
|
31
|
+
return this.params.set("context", t), this;
|
|
18
32
|
}
|
|
19
|
-
|
|
20
|
-
return this.params.set("
|
|
33
|
+
search(t) {
|
|
34
|
+
return this.params.set("search", t), this;
|
|
35
|
+
}
|
|
36
|
+
limit(t = 1) {
|
|
37
|
+
return this.params.set("limit", t), this;
|
|
21
38
|
}
|
|
22
39
|
build() {
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
const e = process.env.OPENFDA_API_KEY;
|
|
26
|
-
if (!n || !r)
|
|
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;
|
|
41
|
+
if (!t || !r || !s)
|
|
27
42
|
throw new Error("Missing required parameters: context or search");
|
|
28
|
-
return
|
|
29
|
-
}
|
|
30
|
-
}
|
|
31
|
-
class C {
|
|
32
|
-
constructor(n) {
|
|
33
|
-
this.server = n;
|
|
34
|
-
}
|
|
35
|
-
registerTool(n) {
|
|
36
|
-
this.server.tool(
|
|
37
|
-
n.name,
|
|
38
|
-
n.description,
|
|
39
|
-
n.schema.shape,
|
|
40
|
-
n.handler
|
|
41
|
-
);
|
|
43
|
+
return `${this.urlBase}/${t}/${r}.json?api_key=${o}&search=${s}&limit=${e}`;
|
|
42
44
|
}
|
|
43
45
|
}
|
|
44
46
|
const F = {
|
|
@@ -48,168 +50,117 @@ const F = {
|
|
|
48
50
|
timeout: 3e4
|
|
49
51
|
// 30 seconds
|
|
50
52
|
};
|
|
51
|
-
function x(
|
|
52
|
-
return !!(
|
|
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);
|
|
53
55
|
}
|
|
54
|
-
function w(
|
|
55
|
-
return new Promise((
|
|
56
|
+
function w(n) {
|
|
57
|
+
return new Promise((t) => setTimeout(t, n));
|
|
56
58
|
}
|
|
57
|
-
async function
|
|
58
|
-
const { maxRetries: r, retryDelay: s, timeout: e } = { ...F, ...
|
|
59
|
+
async function h(n, t = {}) {
|
|
60
|
+
const { maxRetries: r, retryDelay: s, timeout: e } = { ...F, ...t }, o = {
|
|
59
61
|
"User-Agent": "@ythalorossy/openfda",
|
|
60
62
|
Accept: "application/json"
|
|
61
63
|
};
|
|
62
64
|
let a = null;
|
|
63
|
-
for (let
|
|
65
|
+
for (let p = 0; p <= r; p++)
|
|
64
66
|
try {
|
|
65
|
-
const
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
);
|
|
69
|
-
const i = await fetch(t, {
|
|
70
|
-
headers: p,
|
|
71
|
-
signal: o.signal
|
|
67
|
+
const i = new AbortController(), l = setTimeout(() => i.abort(), e), c = await fetch(n, {
|
|
68
|
+
headers: o,
|
|
69
|
+
signal: i.signal
|
|
72
70
|
});
|
|
73
|
-
if (clearTimeout(
|
|
74
|
-
const
|
|
71
|
+
if (clearTimeout(l), !c.ok) {
|
|
72
|
+
const f = await c.text().catch(() => "Unable to read error response"), m = {
|
|
75
73
|
type: "http",
|
|
76
|
-
message: `HTTP ${
|
|
77
|
-
status:
|
|
78
|
-
details:
|
|
74
|
+
message: `HTTP ${c.status}: ${c.statusText}`,
|
|
75
|
+
status: c.status,
|
|
76
|
+
details: f
|
|
79
77
|
};
|
|
80
|
-
switch (
|
|
81
|
-
url: t,
|
|
82
|
-
status: i.status,
|
|
83
|
-
statusText: i.statusText,
|
|
84
|
-
errorText: m.substring(0, 200)
|
|
85
|
-
// Truncate long error messages
|
|
86
|
-
}), i.status) {
|
|
78
|
+
switch (c.status) {
|
|
87
79
|
case 400:
|
|
88
|
-
|
|
80
|
+
m.message = "Bad Request: Invalid search query or parameters";
|
|
89
81
|
break;
|
|
90
82
|
case 401:
|
|
91
|
-
|
|
83
|
+
m.message = "Unauthorized: Invalid or missing API key";
|
|
92
84
|
break;
|
|
93
85
|
case 403:
|
|
94
|
-
|
|
86
|
+
m.message = "Forbidden: API key may be invalid or quota exceeded";
|
|
95
87
|
break;
|
|
96
88
|
case 404:
|
|
97
|
-
|
|
89
|
+
m.message = "Not Found: No results found for the specified query";
|
|
98
90
|
break;
|
|
99
91
|
case 429:
|
|
100
|
-
|
|
92
|
+
m.message = "Rate Limited: Too many requests. Retrying...";
|
|
101
93
|
break;
|
|
102
94
|
case 500:
|
|
103
|
-
|
|
95
|
+
m.message = "Server Error: OpenFDA service is experiencing issues";
|
|
104
96
|
break;
|
|
105
97
|
default:
|
|
106
|
-
|
|
98
|
+
m.message = `HTTP Error ${c.status}: ${c.statusText}`;
|
|
107
99
|
}
|
|
108
|
-
if (a =
|
|
100
|
+
if (a = m, c.status >= 400 && c.status < 500 && c.status !== 429)
|
|
109
101
|
break;
|
|
110
|
-
if (
|
|
111
|
-
const
|
|
112
|
-
|
|
102
|
+
if (p < r && x({ status: c.status })) {
|
|
103
|
+
const b = s * Math.pow(2, p);
|
|
104
|
+
await w(b);
|
|
113
105
|
continue;
|
|
114
106
|
}
|
|
115
107
|
break;
|
|
116
108
|
}
|
|
117
|
-
let
|
|
109
|
+
let u;
|
|
118
110
|
try {
|
|
119
|
-
|
|
120
|
-
} catch (
|
|
121
|
-
|
|
111
|
+
u = await c.json();
|
|
112
|
+
} catch (f) {
|
|
113
|
+
a = {
|
|
122
114
|
type: "parsing",
|
|
123
|
-
message: `Failed to parse JSON response: ${
|
|
124
|
-
details:
|
|
115
|
+
message: `Failed to parse JSON response: ${f instanceof Error ? f.message : "Unknown parsing error"}`,
|
|
116
|
+
details: f
|
|
125
117
|
};
|
|
126
|
-
console.error("OpenFDA JSON Parsing Error:", {
|
|
127
|
-
url: t,
|
|
128
|
-
parseError: m instanceof Error ? m.message : m
|
|
129
|
-
}), a = f;
|
|
130
118
|
break;
|
|
131
119
|
}
|
|
132
|
-
if (!
|
|
120
|
+
if (!u) {
|
|
133
121
|
a = {
|
|
134
122
|
type: "empty_response",
|
|
135
123
|
message: "Received empty response from OpenFDA API"
|
|
136
124
|
};
|
|
137
125
|
break;
|
|
138
126
|
}
|
|
139
|
-
return
|
|
140
|
-
} catch (
|
|
141
|
-
let
|
|
142
|
-
if (
|
|
127
|
+
return { data: u, error: null };
|
|
128
|
+
} catch (i) {
|
|
129
|
+
let l;
|
|
130
|
+
if (i.name === "AbortError" ? l = {
|
|
143
131
|
type: "timeout",
|
|
144
132
|
message: `Request timeout after ${e}ms`,
|
|
145
|
-
details:
|
|
146
|
-
} :
|
|
133
|
+
details: i
|
|
134
|
+
} : i instanceof TypeError && i.message.includes("fetch") ? l = {
|
|
147
135
|
type: "network",
|
|
148
136
|
message: "Network error: Unable to connect to OpenFDA API",
|
|
149
|
-
details:
|
|
150
|
-
} :
|
|
137
|
+
details: i.message
|
|
138
|
+
} : l = {
|
|
151
139
|
type: "unknown",
|
|
152
|
-
message: `Unexpected error: ${
|
|
153
|
-
details:
|
|
154
|
-
},
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
type: o.name
|
|
158
|
-
}), a = d, c < r && x(o)) {
|
|
159
|
-
const i = s * Math.pow(2, c);
|
|
160
|
-
console.log(`Network error, retrying in ${i}ms...`), await w(i);
|
|
140
|
+
message: `Unexpected error: ${i.message || "Unknown error occurred"}`,
|
|
141
|
+
details: i
|
|
142
|
+
}, a = l, p < r && x(i)) {
|
|
143
|
+
const c = s * Math.pow(2, p);
|
|
144
|
+
await w(c);
|
|
161
145
|
continue;
|
|
162
146
|
}
|
|
163
147
|
break;
|
|
164
148
|
}
|
|
165
149
|
return { data: null, error: a };
|
|
166
150
|
}
|
|
167
|
-
const
|
|
168
|
-
{
|
|
169
|
-
name: "openfda",
|
|
170
|
-
version: "1.0.0",
|
|
171
|
-
description: "OpenFDA Model Context Protocol"
|
|
172
|
-
},
|
|
173
|
-
{
|
|
174
|
-
capabilities: {
|
|
175
|
-
resources: {},
|
|
176
|
-
tools: {}
|
|
177
|
-
}
|
|
178
|
-
}
|
|
179
|
-
), b = new C(X);
|
|
180
|
-
function A(t) {
|
|
181
|
-
const n = t.trim().toUpperCase();
|
|
182
|
-
let r, s = null;
|
|
183
|
-
if (n.includes("-")) {
|
|
184
|
-
const p = n.split("-");
|
|
185
|
-
if (p.length === 2)
|
|
186
|
-
r = n, s = null;
|
|
187
|
-
else if (p.length === 3)
|
|
188
|
-
r = `${p[0]}-${p[1]}`, s = n;
|
|
189
|
-
else
|
|
190
|
-
return { productNDC: n, packageNDC: null, isValid: !1 };
|
|
191
|
-
} else if (n.length === 11)
|
|
192
|
-
r = `${n.substring(0, 5)}-${n.substring(5, 9)}`, s = `${n.substring(0, 5)}-${n.substring(5, 9)}-${n.substring(9, 11)}`;
|
|
193
|
-
else if (n.length === 9)
|
|
194
|
-
r = `${n.substring(0, 5)}-${n.substring(5, 9)}`, s = null;
|
|
195
|
-
else
|
|
196
|
-
return { productNDC: n, packageNDC: null, isValid: !1 };
|
|
197
|
-
const e = /^\d{5}-\d{4}$/.test(r);
|
|
198
|
-
return { productNDC: r, packageNDC: s, isValid: e };
|
|
199
|
-
}
|
|
200
|
-
b.registerTool({
|
|
151
|
+
const S = {
|
|
201
152
|
name: "get-drug-by-name",
|
|
202
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.",
|
|
203
|
-
|
|
204
|
-
drugName:
|
|
154
|
+
inputSchema: d.object({
|
|
155
|
+
drugName: d.string().describe("Drug name")
|
|
205
156
|
}),
|
|
206
|
-
|
|
207
|
-
const
|
|
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);
|
|
208
159
|
if (s) {
|
|
209
|
-
let a = `Failed to retrieve drug data for "${
|
|
160
|
+
let a = `Failed to retrieve drug data for "${n}": ${s.message}`;
|
|
210
161
|
switch (s.type) {
|
|
211
162
|
case "http":
|
|
212
|
-
s.status === 404 ? a +=
|
|
163
|
+
s.status === 404 ? a += `${t}
|
|
213
164
|
|
|
214
165
|
Suggestions:
|
|
215
166
|
- Verify the exact brand name spelling
|
|
@@ -230,24 +181,20 @@ The request took too long. Please try again.`;
|
|
|
230
181
|
break;
|
|
231
182
|
}
|
|
232
183
|
return {
|
|
233
|
-
content: [
|
|
234
|
-
|
|
235
|
-
type: "text",
|
|
236
|
-
text: a
|
|
237
|
-
}
|
|
238
|
-
]
|
|
184
|
+
content: [{ type: "text", text: a }],
|
|
185
|
+
isError: !0
|
|
239
186
|
};
|
|
240
187
|
}
|
|
241
|
-
if (!r
|
|
188
|
+
if (!(r != null && r.results) || r.results.length === 0)
|
|
242
189
|
return {
|
|
243
190
|
content: [
|
|
244
191
|
{
|
|
245
192
|
type: "text",
|
|
246
|
-
text: `No drug information found for "${
|
|
193
|
+
text: `No drug information found for "${n}". Please verify the brand name spelling or try searching for the generic name.`
|
|
247
194
|
}
|
|
248
195
|
]
|
|
249
196
|
};
|
|
250
|
-
const e = r.results[0],
|
|
197
|
+
const e = r.results[0], o = {
|
|
251
198
|
brand_name: e == null ? void 0 : e.openfda.brand_name,
|
|
252
199
|
generic_name: e == null ? void 0 : e.openfda.generic_name,
|
|
253
200
|
manufacturer_name: e == null ? void 0 : e.openfda.manufacturer_name,
|
|
@@ -269,46 +216,49 @@ The request took too long. Please try again.`;
|
|
|
269
216
|
type: "text",
|
|
270
217
|
text: `Drug information retrieved successfully:
|
|
271
218
|
|
|
272
|
-
${JSON.stringify(
|
|
219
|
+
${JSON.stringify(o, null, 2)}`
|
|
273
220
|
}
|
|
274
221
|
]
|
|
275
222
|
};
|
|
276
223
|
}
|
|
277
|
-
}
|
|
278
|
-
b.registerTool({
|
|
224
|
+
}, E = {
|
|
279
225
|
name: "get-drug-by-generic-name",
|
|
280
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.",
|
|
281
|
-
|
|
282
|
-
genericName:
|
|
283
|
-
limit:
|
|
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")
|
|
284
230
|
}),
|
|
285
|
-
|
|
286
|
-
|
|
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);
|
|
287
236
|
if (e)
|
|
288
237
|
return {
|
|
289
238
|
content: [
|
|
290
239
|
{
|
|
291
240
|
type: "text",
|
|
292
|
-
text: `Failed to retrieve drug data for generic name "${
|
|
241
|
+
text: `Failed to retrieve drug data for generic name "${n}": ${e.message}`
|
|
293
242
|
}
|
|
294
|
-
]
|
|
243
|
+
],
|
|
244
|
+
isError: !0
|
|
295
245
|
};
|
|
296
|
-
if (!s
|
|
246
|
+
if (!(s != null && s.results) || s.results.length === 0)
|
|
297
247
|
return {
|
|
298
248
|
content: [
|
|
299
249
|
{
|
|
300
250
|
type: "text",
|
|
301
|
-
text: `No drug information found for generic name "${
|
|
251
|
+
text: `No drug information found for generic name "${n}".`
|
|
302
252
|
}
|
|
303
253
|
]
|
|
304
254
|
};
|
|
305
|
-
const
|
|
306
|
-
var
|
|
255
|
+
const o = s.results.map((a) => {
|
|
256
|
+
var p, i, l, c;
|
|
307
257
|
return {
|
|
308
|
-
brand_name: ((
|
|
309
|
-
generic_name: ((
|
|
310
|
-
manufacturer_name: ((
|
|
311
|
-
product_type: ((
|
|
258
|
+
brand_name: ((p = a == null ? void 0 : a.openfda.brand_name) == null ? void 0 : p[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",
|
|
261
|
+
product_type: ((c = a == null ? void 0 : a.openfda.product_type) == null ? void 0 : c[0]) || "Unknown",
|
|
312
262
|
route: (a == null ? void 0 : a.openfda.route) || []
|
|
313
263
|
};
|
|
314
264
|
});
|
|
@@ -316,147 +266,155 @@ b.registerTool({
|
|
|
316
266
|
content: [
|
|
317
267
|
{
|
|
318
268
|
type: "text",
|
|
319
|
-
text: `Found ${
|
|
269
|
+
text: `Found ${o.length} drug(s) with generic name "${n}":
|
|
320
270
|
|
|
321
|
-
${JSON.stringify(
|
|
271
|
+
${JSON.stringify(o, null, 2)}`
|
|
322
272
|
}
|
|
323
273
|
]
|
|
324
274
|
};
|
|
325
275
|
}
|
|
326
|
-
}
|
|
327
|
-
b.registerTool({
|
|
276
|
+
}, P = {
|
|
328
277
|
name: "get-drug-adverse-events",
|
|
329
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.",
|
|
330
|
-
|
|
331
|
-
drugName:
|
|
332
|
-
limit:
|
|
333
|
-
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")
|
|
334
283
|
}),
|
|
335
|
-
|
|
336
|
-
|
|
284
|
+
async handler({
|
|
285
|
+
drugName: n,
|
|
286
|
+
limit: t,
|
|
287
|
+
seriousness: r
|
|
288
|
+
}) {
|
|
289
|
+
let s = `patient.drug.medicinalproduct:"${n}"`;
|
|
337
290
|
r !== "all" && (s += `+AND+serious:${r === "serious" ? "1" : "2"}`);
|
|
338
|
-
const e = new
|
|
291
|
+
const e = new g().dataset("drug").context("event").search(s).limit(t).build(), { data: o, error: a } = await h(e);
|
|
339
292
|
if (a)
|
|
340
293
|
return {
|
|
341
294
|
content: [
|
|
342
295
|
{
|
|
343
296
|
type: "text",
|
|
344
|
-
text: `Failed to retrieve adverse events for "${
|
|
297
|
+
text: `Failed to retrieve adverse events for "${n}": ${a.message}`
|
|
345
298
|
}
|
|
346
|
-
]
|
|
299
|
+
],
|
|
300
|
+
isError: !0
|
|
347
301
|
};
|
|
348
|
-
if (!
|
|
302
|
+
if (!(o != null && o.results) || o.results.length === 0)
|
|
349
303
|
return {
|
|
350
304
|
content: [
|
|
351
305
|
{
|
|
352
306
|
type: "text",
|
|
353
|
-
text: `No adverse events found for "${
|
|
307
|
+
text: `No adverse events found for "${n}".`
|
|
354
308
|
}
|
|
355
309
|
]
|
|
356
310
|
};
|
|
357
|
-
const
|
|
358
|
-
var
|
|
311
|
+
const p = o.results.map((i) => {
|
|
312
|
+
var l, c, u, f, m, b, $;
|
|
359
313
|
return {
|
|
360
|
-
report_id:
|
|
361
|
-
serious:
|
|
362
|
-
patient_age: ((
|
|
363
|
-
patient_sex: ((
|
|
364
|
-
reactions: ((
|
|
365
|
-
outcomes: (($ = (
|
|
366
|
-
report_date:
|
|
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"
|
|
367
321
|
};
|
|
368
322
|
});
|
|
369
323
|
return {
|
|
370
324
|
content: [
|
|
371
325
|
{
|
|
372
326
|
type: "text",
|
|
373
|
-
text: `Found ${
|
|
327
|
+
text: `Found ${p.length} adverse event report(s) for "${n}":
|
|
374
328
|
|
|
375
|
-
${JSON.stringify(
|
|
329
|
+
${JSON.stringify(p, null, 2)}`
|
|
376
330
|
}
|
|
377
331
|
]
|
|
378
332
|
};
|
|
379
333
|
}
|
|
380
|
-
}
|
|
381
|
-
b.registerTool({
|
|
334
|
+
}, A = {
|
|
382
335
|
name: "get-drugs-by-manufacturer",
|
|
383
336
|
description: "Get all drugs manufactured by a specific company. Useful for finding alternatives or checking manufacturer portfolios.",
|
|
384
|
-
|
|
385
|
-
manufacturerName:
|
|
386
|
-
limit:
|
|
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")
|
|
387
340
|
}),
|
|
388
|
-
|
|
389
|
-
|
|
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);
|
|
390
346
|
if (e)
|
|
391
347
|
return {
|
|
392
348
|
content: [
|
|
393
349
|
{
|
|
394
350
|
type: "text",
|
|
395
|
-
text:
|
|
351
|
+
text: `${r}
|
|
352
|
+
Failed to retrieve drugs for manufacturer "${n}": ${e.message}`
|
|
396
353
|
}
|
|
397
|
-
]
|
|
354
|
+
],
|
|
355
|
+
isError: !0
|
|
398
356
|
};
|
|
399
|
-
if (!s
|
|
357
|
+
if (!(s != null && s.results) || s.results.length === 0)
|
|
400
358
|
return {
|
|
401
359
|
content: [
|
|
402
360
|
{
|
|
403
361
|
type: "text",
|
|
404
|
-
text: `No drugs found for manufacturer "${
|
|
362
|
+
text: `No drugs found for manufacturer "${n}".`
|
|
405
363
|
}
|
|
406
364
|
]
|
|
407
365
|
};
|
|
408
|
-
const
|
|
409
|
-
var
|
|
366
|
+
const o = s.results.map((a) => {
|
|
367
|
+
var p, i, l, c;
|
|
410
368
|
return {
|
|
411
|
-
brand_name: ((
|
|
412
|
-
generic_name: ((
|
|
413
|
-
product_type: ((
|
|
369
|
+
brand_name: ((p = a == null ? void 0 : a.openfda.brand_name) == null ? void 0 : p[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",
|
|
414
372
|
route: (a == null ? void 0 : a.openfda.route) || [],
|
|
415
|
-
ndc: ((
|
|
373
|
+
ndc: ((c = a == null ? void 0 : a.openfda.product_ndc) == null ? void 0 : c[0]) || "Unknown"
|
|
416
374
|
};
|
|
417
375
|
});
|
|
418
376
|
return {
|
|
419
377
|
content: [
|
|
420
378
|
{
|
|
421
379
|
type: "text",
|
|
422
|
-
text: `Found ${
|
|
380
|
+
text: `Found ${o.length} drug(s) from manufacturer "${n}":
|
|
423
381
|
|
|
424
|
-
${JSON.stringify(
|
|
382
|
+
${JSON.stringify(o, null, 2)}`
|
|
425
383
|
}
|
|
426
384
|
]
|
|
427
385
|
};
|
|
428
386
|
}
|
|
429
|
-
}
|
|
430
|
-
b.registerTool({
|
|
387
|
+
}, U = {
|
|
431
388
|
name: "get-drug-safety-info",
|
|
432
389
|
description: "Get comprehensive safety information for a drug including warnings, contraindications, drug interactions, and precautions. Use brand name.",
|
|
433
|
-
|
|
434
|
-
drugName:
|
|
390
|
+
inputSchema: d.object({
|
|
391
|
+
drugName: d.string().describe("Drug brand name")
|
|
435
392
|
}),
|
|
436
|
-
|
|
437
|
-
var a,
|
|
438
|
-
const
|
|
393
|
+
async handler({ drugName: n }) {
|
|
394
|
+
var a, p;
|
|
395
|
+
const t = new g().dataset("drug").context("label").search(`openfda.brand_name:"${n}"`).limit(1).build(), { data: r, error: s } = await h(t);
|
|
439
396
|
if (s)
|
|
440
397
|
return {
|
|
441
398
|
content: [
|
|
442
399
|
{
|
|
443
400
|
type: "text",
|
|
444
|
-
text: `Failed to retrieve safety information for "${
|
|
401
|
+
text: `Failed to retrieve safety information for "${n}": ${s.message}`
|
|
445
402
|
}
|
|
446
|
-
]
|
|
403
|
+
],
|
|
404
|
+
isError: !0
|
|
447
405
|
};
|
|
448
|
-
if (!r
|
|
406
|
+
if (!(r != null && r.results) || r.results.length === 0)
|
|
449
407
|
return {
|
|
450
408
|
content: [
|
|
451
409
|
{
|
|
452
410
|
type: "text",
|
|
453
|
-
text: `No safety information found for "${
|
|
411
|
+
text: `No safety information found for "${n}".`
|
|
454
412
|
}
|
|
455
413
|
]
|
|
456
414
|
};
|
|
457
|
-
const e = r.results[0],
|
|
458
|
-
drug_name: ((a = e == null ? void 0 : e.openfda.brand_name) == null ? void 0 : a[0]) ||
|
|
459
|
-
generic_name: ((
|
|
415
|
+
const e = r.results[0], o = {
|
|
416
|
+
drug_name: ((a = e == null ? void 0 : e.openfda.brand_name) == null ? void 0 : a[0]) || n,
|
|
417
|
+
generic_name: ((p = e == null ? void 0 : e.openfda.generic_name) == null ? void 0 : p[0]) || "Unknown",
|
|
460
418
|
warnings: (e == null ? void 0 : e.warnings) || [],
|
|
461
419
|
contraindications: (e == null ? void 0 : e.contraindications) || [],
|
|
462
420
|
drug_interactions: (e == null ? void 0 : e.drug_interactions) || [],
|
|
@@ -472,59 +430,78 @@ b.registerTool({
|
|
|
472
430
|
content: [
|
|
473
431
|
{
|
|
474
432
|
type: "text",
|
|
475
|
-
text: `Safety information for "${
|
|
433
|
+
text: `Safety information for "${n}":
|
|
476
434
|
|
|
477
|
-
${JSON.stringify(
|
|
435
|
+
${JSON.stringify(o, null, 2)}`
|
|
478
436
|
}
|
|
479
437
|
]
|
|
480
438
|
};
|
|
481
439
|
}
|
|
482
|
-
}
|
|
483
|
-
|
|
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 = {
|
|
484
462
|
name: "get-drug-by-ndc",
|
|
485
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.",
|
|
486
|
-
|
|
487
|
-
ndcCode:
|
|
464
|
+
inputSchema: d.object({
|
|
465
|
+
ndcCode: d.string().describe(
|
|
488
466
|
"National Drug Code (NDC) - accepts formats: XXXXX-XXXX, XXXXX-XXXX-XX, or without dashes"
|
|
489
467
|
)
|
|
490
468
|
}),
|
|
491
|
-
|
|
492
|
-
const { productNDC:
|
|
469
|
+
async handler({ ndcCode: n }) {
|
|
470
|
+
const { productNDC: t, packageNDC: r, isValid: s } = O(n);
|
|
493
471
|
if (!s)
|
|
494
472
|
return {
|
|
495
473
|
content: [
|
|
496
474
|
{
|
|
497
475
|
type: "text",
|
|
498
|
-
text: `Invalid NDC format: "${
|
|
476
|
+
text: `Invalid NDC format: "${n}"
|
|
499
477
|
|
|
500
478
|
✅ Accepted formats:
|
|
501
479
|
• Product NDC: 12345-1234
|
|
502
480
|
• Package NDC: 12345-1234-01
|
|
503
481
|
• Without dashes: 123451234 or 12345123401`
|
|
504
482
|
}
|
|
505
|
-
]
|
|
483
|
+
],
|
|
484
|
+
isError: !0
|
|
506
485
|
};
|
|
507
|
-
|
|
508
|
-
`Searching for NDC: input="${t}", productNDC="${n}", packageNDC="${r}"`
|
|
509
|
-
);
|
|
510
|
-
let e = `openfda.product_ndc:"${n}"`;
|
|
486
|
+
let e = `openfda.product_ndc:"${t}"`;
|
|
511
487
|
r && (e += `+OR+openfda.package_ndc:"${r}"`);
|
|
512
|
-
const
|
|
513
|
-
if (
|
|
488
|
+
const o = new g().dataset("drug").context("label").search(e).limit(10).build(), { data: a, error: p } = await h(o);
|
|
489
|
+
if (p)
|
|
514
490
|
return {
|
|
515
491
|
content: [
|
|
516
492
|
{
|
|
517
493
|
type: "text",
|
|
518
|
-
text: `Failed to retrieve drug data for NDC "${
|
|
494
|
+
text: `Failed to retrieve drug data for NDC "${n}": ${p.message}`
|
|
519
495
|
}
|
|
520
|
-
]
|
|
496
|
+
],
|
|
497
|
+
isError: !0
|
|
521
498
|
};
|
|
522
|
-
if (!a
|
|
499
|
+
if (!(a != null && a.results) || a.results.length === 0)
|
|
523
500
|
return {
|
|
524
501
|
content: [
|
|
525
502
|
{
|
|
526
503
|
type: "text",
|
|
527
|
-
text: `No drug found with NDC "${
|
|
504
|
+
text: `No drug found with NDC "${n}" (product: ${t}).
|
|
528
505
|
|
|
529
506
|
💡 Tips:
|
|
530
507
|
• Verify the NDC format
|
|
@@ -533,91 +510,90 @@ b.registerTool({
|
|
|
533
510
|
}
|
|
534
511
|
]
|
|
535
512
|
};
|
|
536
|
-
const
|
|
537
|
-
var
|
|
538
|
-
const
|
|
539
|
-
(_) => r ? _ === r : _.startsWith(
|
|
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(
|
|
516
|
+
(_) => r ? _ === r : _.startsWith(t)
|
|
540
517
|
)) || [];
|
|
541
518
|
return {
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
package_label_principal_display_panel: l.package_label_principal_display_panel || [],
|
|
557
|
-
active_ingredient: l.active_ingredient || [],
|
|
558
|
-
purpose: l.purpose || []
|
|
519
|
+
brand_name: u.openfda.brand_name || [],
|
|
520
|
+
generic_name: u.openfda.generic_name || [],
|
|
521
|
+
manufacturer_name: u.openfda.manufacturer_name || [],
|
|
522
|
+
product_type: u.openfda.product_type || [],
|
|
523
|
+
route: u.openfda.route || [],
|
|
524
|
+
substance_name: u.openfda.substance_name || [],
|
|
525
|
+
matching_product_ndc: f,
|
|
526
|
+
matching_package_ndc: m,
|
|
527
|
+
all_product_ndc: u.openfda.product_ndc || [],
|
|
528
|
+
all_package_ndc: u.openfda.package_ndc || [],
|
|
529
|
+
dosage_and_administration: u.dosage_and_administration || [],
|
|
530
|
+
package_label_principal_display_panel: u.package_label_principal_display_panel || [],
|
|
531
|
+
active_ingredient: u.active_ingredient || [],
|
|
532
|
+
purpose: u.purpose || []
|
|
559
533
|
};
|
|
560
|
-
}),
|
|
561
|
-
(
|
|
534
|
+
}), l = i.reduce(
|
|
535
|
+
(u, f) => u + f.matching_package_ndc.length,
|
|
562
536
|
0
|
|
563
|
-
),
|
|
537
|
+
), c = r ? `Searched for specific package NDC: ${r}` : `Searched for product NDC: ${t} (all packages)`;
|
|
564
538
|
return {
|
|
565
539
|
content: [
|
|
566
540
|
{
|
|
567
541
|
type: "text",
|
|
568
|
-
text: `✅ Found ${
|
|
542
|
+
text: `✅ Found ${i.length} drug(s) with ${l} package(s) for NDC "${n}"
|
|
569
543
|
|
|
570
|
-
${
|
|
544
|
+
${c}
|
|
571
545
|
|
|
572
|
-
${JSON.stringify(
|
|
546
|
+
${JSON.stringify(i, null, 2)}`
|
|
573
547
|
}
|
|
574
548
|
]
|
|
575
549
|
};
|
|
576
550
|
}
|
|
577
|
-
}
|
|
578
|
-
b.registerTool({
|
|
551
|
+
}, M = {
|
|
579
552
|
name: "get-drug-by-product-ndc",
|
|
580
553
|
description: "Get drug information by product NDC only (XXXXX-XXXX format). This ignores package variations and finds all packages for a product.",
|
|
581
|
-
|
|
582
|
-
productNDC:
|
|
554
|
+
inputSchema: d.object({
|
|
555
|
+
productNDC: d.string().describe("Product NDC in format XXXXX-XXXX")
|
|
583
556
|
}),
|
|
584
|
-
|
|
585
|
-
var
|
|
586
|
-
if (!/^\d{5}-\d{4}$/.test(
|
|
557
|
+
async handler({ productNDC: n }) {
|
|
558
|
+
var p;
|
|
559
|
+
if (!/^\d{5}-\d{4}$/.test(n.trim()))
|
|
587
560
|
return {
|
|
588
561
|
content: [
|
|
589
562
|
{
|
|
590
563
|
type: "text",
|
|
591
|
-
text: `Invalid product NDC format: "${
|
|
564
|
+
text: `Invalid product NDC format: "${n}"
|
|
592
565
|
|
|
593
566
|
✅ Required format: XXXXX-XXXX (e.g., 12345-1234)`
|
|
594
567
|
}
|
|
595
|
-
]
|
|
568
|
+
],
|
|
569
|
+
isError: !0
|
|
596
570
|
};
|
|
597
|
-
const
|
|
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);
|
|
598
572
|
if (s)
|
|
599
573
|
return {
|
|
600
574
|
content: [
|
|
601
575
|
{
|
|
602
576
|
type: "text",
|
|
603
|
-
text:
|
|
577
|
+
text: `${t}Failed to retrieve drug data for product NDC "${n}": ${s.message}`
|
|
604
578
|
}
|
|
605
|
-
]
|
|
579
|
+
],
|
|
580
|
+
isError: !0
|
|
606
581
|
};
|
|
607
|
-
if (!r
|
|
582
|
+
if (!(r != null && r.results) || r.results.length === 0)
|
|
608
583
|
return {
|
|
609
584
|
content: [
|
|
610
585
|
{
|
|
611
586
|
type: "text",
|
|
612
|
-
text: `No drug found with product NDC "${
|
|
587
|
+
text: `No drug found with product NDC "${n}".`
|
|
613
588
|
}
|
|
614
|
-
]
|
|
589
|
+
],
|
|
590
|
+
structuredContent: null
|
|
615
591
|
};
|
|
616
|
-
const e = r.results[0],
|
|
617
|
-
(
|
|
592
|
+
const e = r.results[0], o = ((p = e.openfda.package_ndc) == null ? void 0 : p.filter(
|
|
593
|
+
(i) => i.startsWith(n.trim())
|
|
618
594
|
)) || [], a = {
|
|
619
|
-
product_ndc:
|
|
620
|
-
available_packages:
|
|
595
|
+
product_ndc: n,
|
|
596
|
+
available_packages: o,
|
|
621
597
|
brand_name: e.openfda.brand_name || [],
|
|
622
598
|
generic_name: e.openfda.generic_name || [],
|
|
623
599
|
manufacturer_name: e.openfda.manufacturer_name || [],
|
|
@@ -632,18 +608,102 @@ b.registerTool({
|
|
|
632
608
|
content: [
|
|
633
609
|
{
|
|
634
610
|
type: "text",
|
|
635
|
-
text: `✅ Product NDC "${
|
|
611
|
+
text: `✅ Product NDC "${n}" found with ${o.length} package variation(s):
|
|
636
612
|
|
|
637
613
|
${JSON.stringify(a, null, 2)}`
|
|
638
614
|
}
|
|
639
615
|
]
|
|
640
616
|
};
|
|
641
617
|
}
|
|
642
|
-
}
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
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() {
|
|
704
|
+
const n = new C();
|
|
705
|
+
await X.connect(n), console.error("OpenFDA MCP Server running on stdio");
|
|
646
706
|
}
|
|
647
|
-
|
|
648
|
-
console.error("Fatal error in main():",
|
|
707
|
+
j().catch((n) => {
|
|
708
|
+
console.error("Fatal error in main():", n), process.exit(1);
|
|
649
709
|
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ythalorossy/openfda",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.19",
|
|
4
4
|
"description": "OpenFDA Model Context Protocol",
|
|
5
5
|
"repository": {
|
|
6
6
|
"type": "git",
|
|
@@ -36,6 +36,7 @@
|
|
|
36
36
|
"zod": "^3.25.0"
|
|
37
37
|
},
|
|
38
38
|
"devDependencies": {
|
|
39
|
+
"@types/node": "^25.5.2",
|
|
39
40
|
"@typescript-eslint/eslint-plugin": "^8.0.0",
|
|
40
41
|
"@typescript-eslint/parser": "^8.0.0",
|
|
41
42
|
"eslint": "^9.0.0",
|