get-drug-by-name
Search drug details by brand name using OpenFDA. Retrieve comprehensive information including generic name, manufacturer, NDC, usage, warnings, and safety advice for accurate drug identification and usage.
Instructions
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.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| drugName | Yes | Drug name |
Implementation Reference
- src/index.ts:71-148 (registration)Full registration of the 'get-drug-by-name' tool with MCP server, including name, description, input schema (drugName: string), and inline async handler that queries OpenFDA drug label endpoint by brand name, handles errors, extracts key fields, and returns formatted JSON response.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.", { drugName: z.string().describe("Drug name"), }, async ({ drugName }) => { const url = new OpenFDABuilder() .context("label") .search(`openfda.brand_name:"${drugName}"`) .limit(1) .build(); const { data: drugData, error } = await makeOpenFDARequest<OpenFDAResponse>(url); if (error) { let errorMessage = `Failed to retrieve drug data for "${drugName}": ${error.message}`; // Provide helpful suggestions based on error type switch (error.type) { case 'http': if (error.status === 404) { errorMessage += `\n\nSuggestions:\n- Verify the exact brand name spelling\n- Try searching for the generic name instead\n- Check if the drug is FDA-approved`; } else if (error.status === 401 || error.status === 403) { errorMessage += `\n\nPlease check the API key configuration.`; } break; case 'network': errorMessage += `\n\nPlease check your internet connection and try again.`; break; case 'timeout': errorMessage += `\n\nThe request took too long. Please try again.`; break; } return { content: [{ type: "text", text: errorMessage, }], }; } if (!drugData || !drugData.results || drugData.results.length === 0) { return { content: [{ type: "text", text: `No drug information found for "${drugName}". Please verify the brand name spelling or try searching for the generic name.`, }], }; } const drug = drugData.results[0]; const drugInfo = { brand_name: drug?.openfda.brand_name, generic_name: drug?.openfda.generic_name, manufacturer_name: drug?.openfda.manufacturer_name, product_ndc: drug?.openfda.product_ndc, product_type: drug?.openfda.product_type, route: drug?.openfda.route, substance_name: drug?.openfda.substance_name, indications_and_usage: drug?.indications_and_usage, warnings: drug?.warnings, do_not_use: drug?.do_not_use, ask_doctor: drug?.ask_doctor, ask_doctor_or_pharmacist: drug?.ask_doctor_or_pharmacist, stop_use: drug?.stop_use, pregnancy_or_breast_feeding: drug?.pregnancy_or_breast_feeding, }; return { content: [{ type: "text", text: `Drug information retrieved successfully:\n\n${JSON.stringify(drugInfo, null, 2)}`, }], }; } );
- src/index.ts:77-147 (handler)The core handler function that implements the tool logic: constructs OpenFDA API URL for drug label search by brand name, fetches data using makeOpenFDARequest, processes response, handles various errors with user-friendly messages, extracts drug metadata, and returns structured text response.async ({ drugName }) => { const url = new OpenFDABuilder() .context("label") .search(`openfda.brand_name:"${drugName}"`) .limit(1) .build(); const { data: drugData, error } = await makeOpenFDARequest<OpenFDAResponse>(url); if (error) { let errorMessage = `Failed to retrieve drug data for "${drugName}": ${error.message}`; // Provide helpful suggestions based on error type switch (error.type) { case 'http': if (error.status === 404) { errorMessage += `\n\nSuggestions:\n- Verify the exact brand name spelling\n- Try searching for the generic name instead\n- Check if the drug is FDA-approved`; } else if (error.status === 401 || error.status === 403) { errorMessage += `\n\nPlease check the API key configuration.`; } break; case 'network': errorMessage += `\n\nPlease check your internet connection and try again.`; break; case 'timeout': errorMessage += `\n\nThe request took too long. Please try again.`; break; } return { content: [{ type: "text", text: errorMessage, }], }; } if (!drugData || !drugData.results || drugData.results.length === 0) { return { content: [{ type: "text", text: `No drug information found for "${drugName}". Please verify the brand name spelling or try searching for the generic name.`, }], }; } const drug = drugData.results[0]; const drugInfo = { brand_name: drug?.openfda.brand_name, generic_name: drug?.openfda.generic_name, manufacturer_name: drug?.openfda.manufacturer_name, product_ndc: drug?.openfda.product_ndc, product_type: drug?.openfda.product_type, route: drug?.openfda.route, substance_name: drug?.openfda.substance_name, indications_and_usage: drug?.indications_and_usage, warnings: drug?.warnings, do_not_use: drug?.do_not_use, ask_doctor: drug?.ask_doctor, ask_doctor_or_pharmacist: drug?.ask_doctor_or_pharmacist, stop_use: drug?.stop_use, pregnancy_or_breast_feeding: drug?.pregnancy_or_breast_feeding, }; return { content: [{ type: "text", text: `Drug information retrieved successfully:\n\n${JSON.stringify(drugInfo, null, 2)}`, }], }; }
- src/index.ts:75-76 (schema)Zod input schema for the tool, validating 'drugName' as a required string.drugName: z.string().describe("Drug name"), },
- src/OpenFDABuilder.ts:32-63 (helper)Fluent builder class for constructing OpenFDA API URLs, used in handler to set context='label', search='openfda.brand_name:"{drugName}"', limit=1.export class OpenFDABuilder { private url = "https://api.fda.gov/drug/"; private params = new Map<string, string | number>(); context(context: ContextType): this { this.params.set("context", context); return this; } search(query: string): this { this.params.set("search", query); return this; } limit(max: number = 1): this { this.params.set("limit", max); return this; } build(): string { const context = this.params.get("context"); const search = this.params.get("search"); const limit = this.params.get("limit"); const apiKey = process.env.OPENFDA_API_KEY; if (!context || !search || !limit) { throw new Error("Missing required parameters: context, search, or limit"); } return `${this.url}${context}.json?api_key=${apiKey}&search=${search}&limit=${limit}`; } }
- src/OpenFDAClient.ts:50-238 (helper)Robust HTTP client function for OpenFDA API requests with retry, timeout, error categorization, and logging, used to fetch the drug data in the handler.async function makeOpenFDARequest<T>( url: string, config: RequestConfig = {} ): Promise<{ data: T | null; error: OpenFDAError | null }> { const { maxRetries, retryDelay, timeout } = { ...DEFAULT_CONFIG, ...config }; const headers = { "User-Agent": "@ythalorossy/openfda", Accept: "application/json", }; let lastError: OpenFDAError | null = null; for (let attempt = 0; attempt <= maxRetries!; attempt++) { try { // Create abort controller for timeout handling const controller = new AbortController(); const timeoutId = setTimeout(() => controller.abort(), timeout); console.log( `Making OpenFDA request (attempt ${attempt + 1}/${ maxRetries! + 1 }): ${url}` ); const response = await fetch(url, { headers, signal: controller.signal, }); clearTimeout(timeoutId); // Handle HTTP errors with OpenFDA-specific context if (!response.ok) { const errorText = await response .text() .catch(() => "Unable to read error response"); const httpError: OpenFDAError = { type: "http", message: `HTTP ${response.status}: ${response.statusText}`, status: response.status, details: errorText, }; console.error(`OpenFDA HTTP Error (${response.status}):`, { url, status: response.status, statusText: response.statusText, errorText: errorText.substring(0, 200), // Truncate long error messages }); // OpenFDA-specific status code handling switch (response.status) { case 400: httpError.message = `Bad Request: Invalid search query or parameters`; break; case 401: httpError.message = `Unauthorized: Invalid or missing API key`; break; case 403: httpError.message = `Forbidden: API key may be invalid or quota exceeded`; break; case 404: httpError.message = `Not Found: No results found for the specified query`; break; case 429: httpError.message = `Rate Limited: Too many requests. Retrying...`; break; case 500: httpError.message = `Server Error: OpenFDA service is experiencing issues`; break; default: httpError.message = `HTTP Error ${response.status}: ${response.statusText}`; } lastError = httpError; // Don't retry client errors (4xx) except rate limiting if ( response.status >= 400 && response.status < 500 && response.status !== 429 ) { break; } // Retry server errors and rate limits if ( attempt < maxRetries! && isRetryableError({ status: response.status }) ) { const delay = retryDelay! * Math.pow(2, attempt); // Exponential backoff console.log(`Retrying in ${delay}ms...`); await sleep(delay); continue; } break; } // Parse JSON response let parsedData: any; try { parsedData = await response.json(); } catch (parseError) { const parsingError: OpenFDAError = { type: "parsing", message: `Failed to parse JSON response: ${ parseError instanceof Error ? parseError.message : "Unknown parsing error" }`, details: parseError, }; console.error("OpenFDA JSON Parsing Error:", { url, parseError: parseError instanceof Error ? parseError.message : parseError, }); lastError = parsingError; break; // Don't retry parsing errors } // Check for empty response if (!parsedData) { const emptyError: OpenFDAError = { type: "empty_response", message: "Received empty response from OpenFDA API", }; lastError = emptyError; break; } console.log(`OpenFDA request successful on attempt ${attempt + 1}`); return { data: parsedData as T, error: null }; } catch (error: any) { // Handle network errors, timeouts, and other fetch errors let networkError: OpenFDAError; if (error.name === "AbortError") { networkError = { type: "timeout", message: `Request timeout after ${timeout}ms`, details: error, }; } else if ( error instanceof TypeError && error.message.includes("fetch") ) { networkError = { type: "network", message: `Network error: Unable to connect to OpenFDA API`, details: error.message, }; } else { networkError = { type: "unknown", message: `Unexpected error: ${ error.message || "Unknown error occurred" }`, details: error, }; } console.error(`OpenFDA Request Error (attempt ${attempt + 1}):`, { url, error: error.message, type: error.name, }); lastError = networkError; // Retry network errors and timeouts if (attempt < maxRetries! && isRetryableError(error)) { const delay = retryDelay! * Math.pow(2, attempt); // Exponential backoff console.log(`Network error, retrying in ${delay}ms...`); await sleep(delay); continue; } break; } } return { data: null, error: lastError }; }