Skip to main content
Glama
caleb-conner

Open Food Facts MCP Server

by caleb-conner

search_products

Find food products using customizable filters like categories, brands, countries, or nutrition grades. Sort results by popularity, name, or date to access detailed product information efficiently.

Instructions

Search for food products with various filters and criteria

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
brandsNoFilter by brand names
categoriesNoFilter by categories (e.g., 'beverages', 'dairy')
countriesNoFilter by countries (e.g., 'france', 'united-states')
nova_groupsNoFilter by NOVA processing groups (1, 2, 3, 4)
nutrition_gradesNoFilter by Nutri-Score grades (a, b, c, d, e)
pageNoPage number for pagination (default: 1)
page_sizeNoNumber of results per page (default: 20, max: 100)
searchNoSearch terms for product names, brands, or ingredients
sort_byNoSort results by: popularity, product_name, created_datetime, last_modified_datetime

Implementation Reference

  • The primary handler function for the 'search_products' tool. It invokes the client's searchProducts method, handles empty results, formats the search summary and product list, and returns the MCP-formatted response.
    async handleSearchProducts(params: any) { const response = await this.client.searchProducts(params); if (response.products.length === 0) { return { content: [ { type: "text" as const, text: "No products found matching your search criteria.", }, ], }; } const summary = `Found ${response.count} products (showing page ${response.page} of ${response.page_count}):\n\n`; const productList = response.products .map((product, index) => `${index + 1}. ${this.formatProductSummary(product)}`) .join('\n\n'); return { content: [ { type: "text" as const, text: summary + productList, }, ], }; }
  • The tool schema definition including name, description, and detailed inputSchema with all parameters for search_products.
    { name: "search_products", description: "Search for food products with various filters and criteria", inputSchema: { type: "object", properties: { search: { type: "string", description: "Search terms for product names, brands, or ingredients", }, categories: { type: "string", description: "Filter by categories (e.g., 'beverages', 'dairy')", }, brands: { type: "string", description: "Filter by brand names", }, countries: { type: "string", description: "Filter by countries (e.g., 'france', 'united-states')", }, nutrition_grades: { type: "string", description: "Filter by Nutri-Score grades (a, b, c, d, e)", }, nova_groups: { type: "string", description: "Filter by NOVA processing groups (1, 2, 3, 4)", }, sort_by: { type: "string", description: "Sort results by: popularity, product_name, created_datetime, last_modified_datetime", enum: ["popularity", "product_name", "created_datetime", "last_modified_datetime"], }, page: { type: "number", description: "Page number for pagination (default: 1)", minimum: 1, }, page_size: { type: "number", description: "Number of results per page (default: 20, max: 100)", minimum: 1, maximum: 100, }, }, required: [], }, },
  • src/index.ts:48-49 (registration)
    The registration/dispatch case in the server's CallToolRequestHandler switch statement that routes 'search_products' calls to the handler.
    case 'search_products': return await handlers.handleSearchProducts(args);
  • Core helper method in the OpenFoodFactsClient that performs the actual HTTP search request to the OpenFoodFacts API, applies rate limiting, constructs query parameters, and parses the response.
    async searchProducts(params: { search?: string; categories?: string; brands?: string; countries?: string; page?: number; page_size?: number; sort_by?: string; nutrition_grades?: string; nova_groups?: string; } = {}): Promise<SearchResponse> { await this.checkRateLimit('search'); const searchParams = new URLSearchParams(); if (params.search) searchParams.append('search_terms', params.search); if (params.categories) searchParams.append('categories_tags', params.categories); if (params.brands) searchParams.append('brands_tags', params.brands); if (params.countries) searchParams.append('countries_tags', params.countries); if (params.nutrition_grades) searchParams.append('nutrition_grades_tags', params.nutrition_grades); if (params.nova_groups) searchParams.append('nova_groups_tags', params.nova_groups); if (params.sort_by) searchParams.append('sort_by', params.sort_by); searchParams.append('page', String(params.page || 1)); searchParams.append('page_size', String(Math.min(params.page_size || 20, 100))); searchParams.append('json', '1'); try { const response = await this.client.get(`/cgi/search.pl?${searchParams.toString()}`); return SearchResponseSchema.parse(response.data); } catch (error) { if (axios.isAxiosError(error)) { throw new Error(`Search failed: ${error.response?.status} ${error.message}`); } throw error; } }

Other Tools

Related 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/caleb-conner/open-food-facts-mcp'

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