Skip to main content
Glama

search_products

Find beer, wine, spirits, and other alcoholic beverages on Drizly by searching product names, brands, or types, with filters for price, ABV, and delivery availability.

Instructions

Search for beer, wine, spirits, and other alcoholic beverages on Drizly by name, type, or brand

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query (product name, brand, or type)
categoryNoFilter by category
minPriceNoMinimum price filter
maxPriceNoMaximum price filter
minAbvNoMinimum ABV percentage
maxAbvNoMaximum ABV percentage
addressNoDelivery address to filter by availability

Implementation Reference

  • The core implementation of searchProducts method in DrizlyBrowser class. This async method uses Playwright to navigate to Drizly's search page, scrape product cards from the DOM, extract product details (name, price, brand, image, rating), and apply optional filters for price, category, and ABV. Returns an array of DrizlyProduct objects.
    async searchProducts(
      query: string,
      filters?: {
        category?: string;
        minPrice?: number;
        maxPrice?: number;
        minAbv?: number;
        maxAbv?: number;
        address?: string;
      }
    ): Promise<DrizlyProduct[]> {
      const params = new URLSearchParams({ q: query });
      if (filters?.category) params.append("category", filters.category);
    
      const searchUrl = `${this.baseUrl}/search?${params.toString()}`;
      await this.navigateTo(searchUrl);
    
      const page = await this.ensurePage();
    
      // Wait for search results
      try {
        await page.waitForSelector('[data-testid="product-card"], .product-card, [class*="ProductCard"]', {
          timeout: 10000,
        });
      } catch {
        return [];
      }
    
      const products = await page.evaluate(() => {
        const results: DrizlyProduct[] = [];
        const cards = document.querySelectorAll(
          '[data-testid="product-card"], .product-card, [class*="ProductCard"]'
        );
    
        cards.forEach((card) => {
          const nameEl = card.querySelector('[class*="name"], [class*="title"], h3, h4');
          const priceEl = card.querySelector('[class*="price"], [data-testid="price"]');
          const imgEl = card.querySelector("img");
          const linkEl = card.querySelector("a");
          const brandEl = card.querySelector('[class*="brand"]');
          const ratingEl = card.querySelector('[class*="rating"], [aria-label*="stars"]');
    
          if (nameEl && priceEl) {
            const priceText = priceEl.textContent?.replace(/[^0-9.]/g, "") || "0";
            results.push({
              id: linkEl?.href?.split("/").pop() || Math.random().toString(36).substr(2, 9),
              name: nameEl.textContent?.trim() || "",
              brand: brandEl?.textContent?.trim() || "",
              category: "",
              price: parseFloat(priceText) || 0,
              imageUrl: imgEl?.src || undefined,
              url: linkEl?.href || "",
              rating: ratingEl ? parseFloat(ratingEl.textContent?.match(/[\d.]+/)?.[0] || "0") : undefined,
              inStock: true,
            });
          }
        });
    
        return results;
      });
    
      // Apply price filters if provided
      return products.filter((p) => {
        if (filters?.minPrice && p.price < filters.minPrice) return false;
        if (filters?.maxPrice && p.price > filters.maxPrice) return false;
        return true;
      });
    }
  • The MCP tool handler for 'search_products'. This case block validates incoming arguments using SearchProductsSchema, calls drizly.searchProducts() with the parsed parameters and filters, and returns the results as formatted JSON content with query info, result count, and up to 20 products.
    case "search_products": {
      const params = SearchProductsSchema.parse(args);
      const products = await drizly.searchProducts(params.query, {
        category: params.category,
        minPrice: params.minPrice,
        maxPrice: params.maxPrice,
        minAbv: params.minAbv,
        maxAbv: params.maxAbv,
        address: params.address,
      });
    
      return {
        content: [
          {
            type: "text",
            text: JSON.stringify(
              {
                query: params.query,
                resultCount: products.length,
                products: products.slice(0, 20),
              },
              null,
              2
            ),
          },
        ],
      };
    }
  • Zod schema definition for search_products tool inputs. Defines validation for query string (required) and optional filters including category, minPrice, maxPrice, minAbv, maxAbv, and address. Each field includes descriptive metadata for the tool.
    const SearchProductsSchema = z.object({
      query: z.string().describe("Search query (product name, brand, or type)"),
      category: z.string().optional().describe("Filter by category (beer, wine, spirits, cider)"),
      minPrice: z.number().optional().describe("Minimum price filter"),
      maxPrice: z.number().optional().describe("Maximum price filter"),
      minAbv: z.number().optional().describe("Minimum ABV percentage"),
      maxAbv: z.number().optional().describe("Maximum ABV percentage"),
      address: z.string().optional().describe("Delivery address to filter by availability"),
    });
  • src/index.ts:97-121 (registration)
    Tool registration for 'search_products' in the ListToolsRequestSchema handler. Defines the tool name, description, and JSON Schema inputSchema with all parameters (query, category, price filters, ABV filters, address) mapped to JSON Schema types for MCP protocol compatibility.
    {
      name: "search_products",
      description:
        "Search for beer, wine, spirits, and other alcoholic beverages on Drizly by name, type, or brand",
      inputSchema: {
        type: "object",
        properties: {
          query: {
            type: "string",
            description: "Search query (product name, brand, or type)",
          },
          category: {
            type: "string",
            enum: ["beer", "wine", "spirits", "cider", "hard-seltzer"],
            description: "Filter by category",
          },
          minPrice: { type: "number", description: "Minimum price filter" },
          maxPrice: { type: "number", description: "Maximum price filter" },
          minAbv: { type: "number", description: "Minimum ABV percentage" },
          maxAbv: { type: "number", description: "Maximum ABV percentage" },
          address: { type: "string", description: "Delivery address to filter by availability" },
        },
        required: ["query"],
      },
    },

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/markswendsen-code/mcp-drizly'

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