Skip to main content
Glama
caleb-conner

Open Food Facts MCP Server

by caleb-conner

search_products

Find food products using search terms and filters for categories, brands, countries, nutrition grades, or processing levels to make informed choices.

Instructions

Search for food products with various filters and criteria

Input Schema

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

Implementation Reference

  • Main handler function for search_products tool: calls client.searchProducts, handles empty results, formats summary and product list into text 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, }, ], }; }
  • Tool definition including name, description, and detailed input schema for search_products with optional parameters like search, categories, brands, etc.
    { 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)
    Registration in the main server request handler switch statement: dispatches search_products calls to handlers.handleSearchProducts.
    case 'search_products': return await handlers.handleSearchProducts(args);
  • Client method that performs the actual HTTP search request to OpenFoodFacts API, builds query params, handles rate limiting, and parses 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; } }

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