Skip to main content
Glama

get-drugs-by-manufacturer

Find drugs produced by a specific pharmaceutical company. Use this tool to identify manufacturer portfolios or locate alternative medications from the same source.

Instructions

Get all drugs manufactured by a specific company. Useful for finding alternatives or checking manufacturer portfolios.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
manufacturerNameYesManufacturer/company name
limitNoMaximum number of drugs to return

Implementation Reference

  • The handler function for the 'get-drugs-by-manufacturer' tool. It constructs an OpenFDA API query for drugs by manufacturer name, fetches the data, handles errors and empty results, maps the response to a simplified list of drugs (brand_name, generic_name, product_type, route, ndc), and returns formatted text content.
    async ({ manufacturerName, limit }) => {
      const url = new OpenFDABuilder()
        .context("label")
        .search(`openfda.manufacturer_name:"${manufacturerName}"`)
        .limit(limit)
        .build();
    
      const { data: drugData, error } = await makeOpenFDARequest<OpenFDAResponse>(url);
      
      if (error) {
        return {
          content: [{
            type: "text",
            text: `Failed to retrieve drugs for manufacturer "${manufacturerName}": ${error.message}`,
          }],
        };
      }
    
      if (!drugData || !drugData.results || drugData.results.length === 0) {
        return {
          content: [{
            type: "text",
            text: `No drugs found for manufacturer "${manufacturerName}".`,
          }],
        };
      }
    
      const drugs = drugData.results.map(drug => ({
        brand_name: drug?.openfda.brand_name?.[0] || 'Unknown',
        generic_name: drug?.openfda.generic_name?.[0] || 'Unknown',
        product_type: drug?.openfda.product_type?.[0] || 'Unknown',
        route: drug?.openfda.route || [],
        ndc: drug?.openfda.product_ndc?.[0] || 'Unknown'
      }));
    
      return {
        content: [{
          type: "text",
          text: `Found ${drugs.length} drug(s) from manufacturer "${manufacturerName}":\n\n${JSON.stringify(drugs, null, 2)}`,
        }],
      };
    }
  • Zod input schema for the tool defining parameters: manufacturerName (required string) and limit (optional number, default 20).
      manufacturerName: z.string().describe("Manufacturer/company name"),
      limit: z.number().optional().default(20).describe("Maximum number of drugs to return")
    },
  • src/index.ts:262-311 (registration)
    Registration of the 'get-drugs-by-manufacturer' tool using McpServer.tool() method, including name, description, schema, and handler function.
    server.tool(
      "get-drugs-by-manufacturer",
      "Get all drugs manufactured by a specific company. Useful for finding alternatives or checking manufacturer portfolios.",
      {
        manufacturerName: z.string().describe("Manufacturer/company name"),
        limit: z.number().optional().default(20).describe("Maximum number of drugs to return")
      },
      async ({ manufacturerName, limit }) => {
        const url = new OpenFDABuilder()
          .context("label")
          .search(`openfda.manufacturer_name:"${manufacturerName}"`)
          .limit(limit)
          .build();
    
        const { data: drugData, error } = await makeOpenFDARequest<OpenFDAResponse>(url);
        
        if (error) {
          return {
            content: [{
              type: "text",
              text: `Failed to retrieve drugs for manufacturer "${manufacturerName}": ${error.message}`,
            }],
          };
        }
    
        if (!drugData || !drugData.results || drugData.results.length === 0) {
          return {
            content: [{
              type: "text",
              text: `No drugs found for manufacturer "${manufacturerName}".`,
            }],
          };
        }
    
        const drugs = drugData.results.map(drug => ({
          brand_name: drug?.openfda.brand_name?.[0] || 'Unknown',
          generic_name: drug?.openfda.generic_name?.[0] || 'Unknown',
          product_type: drug?.openfda.product_type?.[0] || 'Unknown',
          route: drug?.openfda.route || [],
          ndc: drug?.openfda.product_ndc?.[0] || 'Unknown'
        }));
    
        return {
          content: [{
            type: "text",
            text: `Found ${drugs.length} drug(s) from manufacturer "${manufacturerName}":\n\n${JSON.stringify(drugs, null, 2)}`,
          }],
        };
      }
    );
  • OpenFDABuilder class used in the handler to construct the OpenFDA API URL with context='label', search='openfda.manufacturer_name:"{name}"', and limit.
    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 utility function called in the handler to perform the resilient HTTP fetch to the constructed OpenFDA URL, with comprehensive error handling and retries.
    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 };
    }
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries the full burden of behavioral disclosure. It mentions the tool 'Get all drugs' but does not specify behavioral traits like whether it returns a list, pagination details, error handling, or performance characteristics (e.g., rate limits). The description adds minimal context beyond the basic operation, leaving gaps in transparency for an agent to use it effectively.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core purpose in the first sentence and adds useful context in the second, with no wasted words. Both sentences earn their place by clarifying the tool's function and typical use cases, making it efficient and well-structured for quick understanding.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the tool's moderate complexity (a filtered list operation with 2 parameters), no annotations, and no output schema, the description is adequate but incomplete. It covers the purpose and usage context but lacks details on return values, error conditions, or behavioral nuances. This leaves the agent with gaps, especially since there's no output schema to clarify what the tool returns.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, with both parameters ('manufacturerName' and 'limit') well-documented in the schema. The description does not add any parameter-specific details beyond what the schema provides, such as format examples or constraints. Given the high schema coverage, the baseline score of 3 is appropriate, as the description does not compensate but also does not detract.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the tool's purpose with a specific verb ('Get') and resource ('all drugs manufactured by a specific company'), distinguishing it from siblings like 'get-drug-by-name' or 'get-drug-by-ndc' which focus on individual drug lookup rather than manufacturer-based filtering. It explicitly mentions the manufacturer scope, making the purpose distinct and unambiguous.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides clear usage context by stating it's 'Useful for finding alternatives or checking manufacturer portfolios,' which implicitly guides when to use this tool (e.g., for manufacturer-related queries). However, it does not explicitly mention when not to use it or name specific alternatives among sibling tools, such as preferring 'get-drug-by-name' for individual drug lookups, which prevents a score of 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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