Skip to main content
Glama

get-drug-safety-info

Retrieve comprehensive drug safety information including warnings, contraindications, drug interactions, and precautions from the OpenFDA database using brand names.

Instructions

Get comprehensive safety information for a drug including warnings, contraindications, drug interactions, and precautions. Use brand name.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
drugNameYesDrug brand name

Implementation Reference

  • The handler function fetches drug labeling data from OpenFDA API using the provided brand name, extracts safety-related fields (warnings, contraindications, interactions, etc.), and returns formatted JSON safety information.
    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) {
        return {
          content: [{
            type: "text",
            text: `Failed to retrieve safety information for "${drugName}": ${error.message}`,
          }],
        };
      }
    
      if (!drugData || !drugData.results || drugData.results.length === 0) {
        return {
          content: [{
            type: "text",
            text: `No safety information found for "${drugName}".`,
          }],
        };
      }
    
      const drug = drugData.results[0];
      const safetyInfo = {
        drug_name: drug?.openfda.brand_name?.[0] || drugName,
        generic_name: drug?.openfda.generic_name?.[0] || 'Unknown',
        warnings: drug?.warnings || [],
        contraindications: drug?.contraindications || [],
        drug_interactions: drug?.drug_interactions || [],
        precautions: drug?.precautions || [],
        adverse_reactions: drug?.adverse_reactions || [],
        overdosage: drug?.overdosage || [],
        do_not_use: drug?.do_not_use || [],
        ask_doctor: drug?.ask_doctor || [],
        stop_use: drug?.stop_use || [],
        pregnancy_or_breast_feeding: drug?.pregnancy_or_breast_feeding || []
      };
    
      return {
        content: [{
          type: "text",
          text: `Safety information for "${drugName}":\n\n${JSON.stringify(safetyInfo, null, 2)}`,
        }],
      };
    }
  • Input schema defined with Zod: requires 'drugName' as string.
    {
      drugName: z.string().describe("Drug brand name")
    },
  • src/index.ts:313-369 (registration)
    Registration of the 'get-drug-safety-info' tool using server.tool() with name, description, input schema, and handler reference.
    server.tool(
      "get-drug-safety-info",
      "Get comprehensive safety information for a drug including warnings, contraindications, drug interactions, and precautions. Use brand name.",
      {
        drugName: z.string().describe("Drug brand 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) {
          return {
            content: [{
              type: "text",
              text: `Failed to retrieve safety information for "${drugName}": ${error.message}`,
            }],
          };
        }
    
        if (!drugData || !drugData.results || drugData.results.length === 0) {
          return {
            content: [{
              type: "text",
              text: `No safety information found for "${drugName}".`,
            }],
          };
        }
    
        const drug = drugData.results[0];
        const safetyInfo = {
          drug_name: drug?.openfda.brand_name?.[0] || drugName,
          generic_name: drug?.openfda.generic_name?.[0] || 'Unknown',
          warnings: drug?.warnings || [],
          contraindications: drug?.contraindications || [],
          drug_interactions: drug?.drug_interactions || [],
          precautions: drug?.precautions || [],
          adverse_reactions: drug?.adverse_reactions || [],
          overdosage: drug?.overdosage || [],
          do_not_use: drug?.do_not_use || [],
          ask_doctor: drug?.ask_doctor || [],
          stop_use: drug?.stop_use || [],
          pregnancy_or_breast_feeding: drug?.pregnancy_or_breast_feeding || []
        };
    
        return {
          content: [{
            type: "text",
            text: `Safety information for "${drugName}":\n\n${JSON.stringify(safetyInfo, null, 2)}`,
          }],
        };
      }
    );
  • OpenFDABuilder class constructs the OpenFDA API URL with context='label', search by brand_name, and limit=1, as used in the handler.
    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}`;
      }
    }
  • makeOpenFDARequest function performs robust HTTP request to OpenFDA API with retry logic, timeout handling, and detailed error types, used to fetch the drug data.
    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 };
    }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/ythalorossy/openfda'

If you have feedback or need assistance with the MCP directory API, please join our Discord server