@ythalorossy/openfda 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The OpenFDABuilder class helps construct URLs for the OpenFDA API.
3
+ *
4
+ * Usage:
5
+ * - Set the context (such as 'label', 'ndc', or 'event') using the context() method.
6
+ * - Set the search query using the search() method.
7
+ * - Optionally set the result limit using the limit() method (default is 1).
8
+ * - Call build() to assemble and return the final API URL.
9
+ *
10
+ * Example:
11
+ * const url = new OpenFDABuilder()
12
+ * .context('label')
13
+ * .search('openfda.brand_name:"Advil"')
14
+ * .limit(1)
15
+ * .build();
16
+ *
17
+ * The build() method will throw an error if any required parameter is missing.
18
+ * The API key is read from the OPENFDA_API_KEY environment variable.
19
+ */
20
+ export class OpenFDABuilder {
21
+ url = "https://api.fda.gov/drug/";
22
+ params = new Map();
23
+ context(context) {
24
+ this.params.set("context", context);
25
+ return this;
26
+ }
27
+ search(query) {
28
+ this.params.set("search", query);
29
+ return this;
30
+ }
31
+ limit(max = 1) {
32
+ this.params.set("limit", max);
33
+ return this;
34
+ }
35
+ build() {
36
+ const context = this.params.get("context");
37
+ const search = this.params.get("search");
38
+ const limit = this.params.get("limit");
39
+ const apiKey = process.env.OPENFDA_API_KEY;
40
+ if (!context || !search || !limit) {
41
+ throw new Error("Missing required parameters: context, search, or limit");
42
+ }
43
+ return `${this.url}${context}.json?api_key=${apiKey}&search=${search}&limit=${limit}`;
44
+ }
45
+ }
package/bin/index.js ADDED
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import dotenv from "dotenv";
5
+ import z from "zod";
6
+ import { OpenFDABuilder } from "./OpenFDABuilder.js";
7
+ dotenv.config();
8
+ const USER_AGENT = "openfda-mcp/1.0";
9
+ const server = new McpServer({
10
+ name: "openfda",
11
+ version: "1.0.0",
12
+ description: "OpenFDA Model Context Protocol",
13
+ capabilities: {
14
+ resources: {},
15
+ tools: {},
16
+ },
17
+ });
18
+ // Helper function for making OpenFDA API requests
19
+ async function makeOpenFDARequest(url) {
20
+ const headers = {
21
+ "User-Agent": USER_AGENT,
22
+ Accept: "application/json",
23
+ };
24
+ try {
25
+ const response = await fetch(url, { headers });
26
+ if (!response.ok) {
27
+ throw new Error(`HTTP error! status: ${response.status}`);
28
+ }
29
+ return (await response.json());
30
+ }
31
+ catch (error) {
32
+ console.error("Error making NWS request:", error);
33
+ return null;
34
+ }
35
+ }
36
+ // Tool: get-drug-by-name
37
+ // Description: Retrieves drug information from the OpenFDA API by brand name.
38
+ // Input: drugName (string) - The brand name of the drug to search for.
39
+ // Output: Returns key drug information fields such as brand name, generic name, manufacturer, NDC, product type, route, substance name, indications and usage, warnings, and other safety information.
40
+ // Usage: Use this tool to look up detailed drug label data for a given brand name.
41
+ server.tool("get-drug-by-name", "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.", {
42
+ drugName: z.string().describe("Drug name"),
43
+ }, async ({ drugName }) => {
44
+ const url = new OpenFDABuilder()
45
+ .context("label")
46
+ .search(`openfda.brand_name:"${drugName}"`)
47
+ .limit(1)
48
+ .build();
49
+ const drugData = await makeOpenFDARequest(url);
50
+ if (!drugData) {
51
+ return {
52
+ content: [
53
+ {
54
+ type: "text",
55
+ text: `Failed to retrieve drug data for ${drugName}`,
56
+ },
57
+ ],
58
+ };
59
+ }
60
+ const drug = drugData.results.at(0);
61
+ const drugInfo = {
62
+ brand_name: drug?.openfda.brand_name,
63
+ generic_name: drug?.openfda.generic_name,
64
+ manufacturer_name: drug?.openfda.manufacturer_name,
65
+ product_ndc: drug?.openfda.product_ndc,
66
+ product_type: drug?.openfda.product_type,
67
+ route: drug?.openfda.route,
68
+ substance_name: drug?.openfda.substance_name,
69
+ indications_and_usage: drug?.indications_and_usage,
70
+ warnings: drug?.warnings,
71
+ do_not_use: drug?.do_not_use,
72
+ ask_doctor: drug?.ask_doctor,
73
+ ask_doctor_or_pharmacist: drug?.ask_doctor_or_pharmacist,
74
+ stop_use: drug?.stop_use,
75
+ pregnancy_or_breast_feeding: drug?.pregnancy_or_breast_feeding,
76
+ };
77
+ return {
78
+ content: [
79
+ {
80
+ type: "text",
81
+ text: `drug: ${JSON.stringify(drugInfo)}`,
82
+ },
83
+ ],
84
+ };
85
+ });
86
+ // The above code registers a tool named "get-drug-by-name" with the MCP server.
87
+ // This tool allows users to retrieve detailed drug label information from the OpenFDA API
88
+ // by providing a brand name. It constructs the appropriate API request, fetches the data,
89
+ // and returns key drug information fields in a structured text response.
90
+ async function main() {
91
+ const transport = new StdioServerTransport();
92
+ await server.connect(transport);
93
+ console.error("OpenFDA MCP Server running on stdio");
94
+ }
95
+ main().catch((error) => {
96
+ console.error("Fatal error in main():", error);
97
+ process.exit(1);
98
+ });
package/bin/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,45 @@
1
+ /**
2
+ * The OpenFDABuilder class helps construct URLs for the OpenFDA API.
3
+ *
4
+ * Usage:
5
+ * - Set the context (such as 'label', 'ndc', or 'event') using the context() method.
6
+ * - Set the search query using the search() method.
7
+ * - Optionally set the result limit using the limit() method (default is 1).
8
+ * - Call build() to assemble and return the final API URL.
9
+ *
10
+ * Example:
11
+ * const url = new OpenFDABuilder()
12
+ * .context('label')
13
+ * .search('openfda.brand_name:"Advil"')
14
+ * .limit(1)
15
+ * .build();
16
+ *
17
+ * The build() method will throw an error if any required parameter is missing.
18
+ * The API key is read from the OPENFDA_API_KEY environment variable.
19
+ */
20
+ export class OpenFDABuilder {
21
+ url = "https://api.fda.gov/drug/";
22
+ params = new Map();
23
+ context(context) {
24
+ this.params.set("context", context);
25
+ return this;
26
+ }
27
+ search(query) {
28
+ this.params.set("search", query);
29
+ return this;
30
+ }
31
+ limit(max = 1) {
32
+ this.params.set("limit", max);
33
+ return this;
34
+ }
35
+ build() {
36
+ const context = this.params.get("context");
37
+ const search = this.params.get("search");
38
+ const limit = this.params.get("limit");
39
+ const apiKey = process.env.OPENFDA_API_KEY;
40
+ if (!context || !search || !limit) {
41
+ throw new Error("Missing required parameters: context, search, or limit");
42
+ }
43
+ return `${this.url}${context}.json?api_key=${apiKey}&search=${search}&limit=${limit}`;
44
+ }
45
+ }
package/build/index.js ADDED
@@ -0,0 +1,98 @@
1
+ #!/usr/bin/env node
2
+ import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
3
+ import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
4
+ import dotenv from "dotenv";
5
+ import z from "zod";
6
+ import { OpenFDABuilder } from "./OpenFDABuilder.js";
7
+ dotenv.config();
8
+ const USER_AGENT = "openfda-mcp/1.0";
9
+ const server = new McpServer({
10
+ name: "openfda",
11
+ version: "1.0.0",
12
+ description: "OpenFDA Model Context Protocol",
13
+ capabilities: {
14
+ resources: {},
15
+ tools: {},
16
+ },
17
+ });
18
+ // Helper function for making OpenFDA API requests
19
+ async function makeOpenFDARequest(url) {
20
+ const headers = {
21
+ "User-Agent": USER_AGENT,
22
+ Accept: "application/json",
23
+ };
24
+ try {
25
+ const response = await fetch(url, { headers });
26
+ if (!response.ok) {
27
+ throw new Error(`HTTP error! status: ${response.status}`);
28
+ }
29
+ return (await response.json());
30
+ }
31
+ catch (error) {
32
+ console.error("Error making NWS request:", error);
33
+ return null;
34
+ }
35
+ }
36
+ // Tool: get-drug-by-name
37
+ // Description: Retrieves drug information from the OpenFDA API by brand name.
38
+ // Input: drugName (string) - The brand name of the drug to search for.
39
+ // Output: Returns key drug information fields such as brand name, generic name, manufacturer, NDC, product type, route, substance name, indications and usage, warnings, and other safety information.
40
+ // Usage: Use this tool to look up detailed drug label data for a given brand name.
41
+ server.tool("get-drug-by-name", "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.", {
42
+ drugName: z.string().describe("Drug name"),
43
+ }, async ({ drugName }) => {
44
+ const url = new OpenFDABuilder()
45
+ .context("label")
46
+ .search(`openfda.brand_name:"${drugName}"`)
47
+ .limit(1)
48
+ .build();
49
+ const drugData = await makeOpenFDARequest(url);
50
+ if (!drugData) {
51
+ return {
52
+ content: [
53
+ {
54
+ type: "text",
55
+ text: `Failed to retrieve drug data for ${drugName}`,
56
+ },
57
+ ],
58
+ };
59
+ }
60
+ const drug = drugData.results.at(0);
61
+ const drugInfo = {
62
+ brand_name: drug?.openfda.brand_name,
63
+ generic_name: drug?.openfda.generic_name,
64
+ manufacturer_name: drug?.openfda.manufacturer_name,
65
+ product_ndc: drug?.openfda.product_ndc,
66
+ product_type: drug?.openfda.product_type,
67
+ route: drug?.openfda.route,
68
+ substance_name: drug?.openfda.substance_name,
69
+ indications_and_usage: drug?.indications_and_usage,
70
+ warnings: drug?.warnings,
71
+ do_not_use: drug?.do_not_use,
72
+ ask_doctor: drug?.ask_doctor,
73
+ ask_doctor_or_pharmacist: drug?.ask_doctor_or_pharmacist,
74
+ stop_use: drug?.stop_use,
75
+ pregnancy_or_breast_feeding: drug?.pregnancy_or_breast_feeding,
76
+ };
77
+ return {
78
+ content: [
79
+ {
80
+ type: "text",
81
+ text: `drug: ${JSON.stringify(drugInfo)}`,
82
+ },
83
+ ],
84
+ };
85
+ });
86
+ // The above code registers a tool named "get-drug-by-name" with the MCP server.
87
+ // This tool allows users to retrieve detailed drug label information from the OpenFDA API
88
+ // by providing a brand name. It constructs the appropriate API request, fetches the data,
89
+ // and returns key drug information fields in a structured text response.
90
+ async function main() {
91
+ const transport = new StdioServerTransport();
92
+ await server.connect(transport);
93
+ console.error("OpenFDA MCP Server running on stdio");
94
+ }
95
+ main().catch((error) => {
96
+ console.error("Fatal error in main():", error);
97
+ process.exit(1);
98
+ });
package/build/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@ythalorossy/openfda",
3
+ "version": "1.0.0",
4
+ "description": "OpenFDA Model Context Protocol",
5
+ "bin": {
6
+ "openfda": "./bin/index.js"
7
+ },
8
+ "main": "index.js",
9
+ "scripts": {
10
+ "build": "tsc && chmod 755 build/index.js",
11
+ "build:cli": "npm run build && node scripts/add-shebang.cjs && shx cp -r build/* bin/",
12
+ "test": "echo \"Error: no test specified\" && exit 1"
13
+ },
14
+ "keywords": [],
15
+ "author": "Ythalo Saldanha",
16
+ "license": "ISC",
17
+ "type": "module",
18
+ "files": [
19
+ "build",
20
+ "bin"
21
+ ],
22
+ "dependencies": {
23
+ "@modelcontextprotocol/sdk": "^1.15.1",
24
+ "dotenv": "^17.2.0",
25
+ "zod": "^3.25.76"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^24.0.14",
29
+ "typescript": "^5.8.3",
30
+ "shx": "^0.3.4"
31
+ }
32
+ }