Pepesto Catalog (full SKU dump)
pepesto_catalogRetrieve the full product catalog for a supermarket, including names, prices, images, and IDs. Use for market analysis or storefront builds; cache results to minimize API calls.
Instructions
Dump Pepesto's full indexed catalog for a supermarket (~1-2k SKUs of common cooking ingredients, with names, prices, images, IDs). Optionally pass a webhook_url to receive incremental updates on re-index. Use only when the user has explicitly asked for a catalog dump, market analysis, or storefront build; for normal recipe-to-cart flows use pepesto_oneshot or pepesto_products instead. Cache this query aggressively, no more than one call per day per supermarket is recommended. When presenting supermarket results the user, use the product key as (external) link to the supermarket product itself. Show image if available (json property image_url, don't search for external images, skip rendering the Pepesto image if the image has webp extesion)
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| supermarket_domain | Yes | Supermarket domain or ID, e.g. 'coop.ch', 'tesco.com', 'ah.nl'. See README for the full list. | |
| webhook_url | No | URL to POST incremental catalog updates to. |
Implementation Reference
- src/tools/catalog.ts:7-32 (handler)The registerCatalogTool function registers the pepesto_catalog tool. The handler calls client.post('/catalog', args) via the runTool helper, which sends a POST request to the Pepesto API /catalog endpoint and wraps the response in a ToolResult (JSON stringified).
export function registerCatalogTool(server: McpServer, client: PepestoClient): void { server.registerTool( "pepesto_catalog", { title: "Pepesto Catalog (full SKU dump)", description: "Dump Pepesto's full indexed catalog for a supermarket (~1-2k SKUs of common cooking " + "ingredients, with names, prices, images, IDs). Optionally pass a webhook_url to receive " + "incremental updates on re-index. Use only when the user has explicitly asked for a " + "catalog dump, market analysis, or storefront build; for normal recipe-to-cart flows " + "use pepesto_oneshot or pepesto_products instead. Cache this query aggressively, no more than " + "one call per day per supermarket is recommended. When presenting supermarket results " + "the user, use the product key as (external) link to the supermarket product itself. " + "Show image if available (json property `image_url`, don't search for external images, " + "skip rendering the Pepesto image if the image has webp extesion)", inputSchema: { supermarket_domain: SupermarketDomain, webhook_url: z .string() .url() .optional() .describe("URL to POST incremental catalog updates to."), }, }, async (args) => runTool(() => client.post("/catalog", args)), ); - src/schemas.ts:3-8 (schema)SupermarketDomain is a Zod schema used as the inputSchema for the supermarket_domain parameter of pepesto_catalog. It validates a non-empty string describing a supermarket domain like 'coop.ch', 'tesco.com'.
export const SupermarketDomain = z .string() .min(1) .describe( "Supermarket domain or ID, e.g. 'coop.ch', 'tesco.com', 'ah.nl'. See README for the full list.", ); - src/server.ts:27-28 (registration)The pepesto_catalog tool is registered by calling registerCatalogTool(server, client) in the server creation function.
registerCatalogTool(server, client); registerCreditsTool(server, client); - src/tools/_runner.ts:9-27 (helper)The runTool helper wraps the handler execution (client.post('/catalog', args)) in try/catch, formatting successful responses as JSON text and errors with descriptive messages.
export async function runTool(fn: () => Promise<unknown>): Promise<ToolResult> { try { const result = await fn(); return { content: [{ type: "text", text: JSON.stringify(result, null, 2) }], }; } catch (err) { const msg = err instanceof PepestoApiError ? err.message : err instanceof Error ? `Error: ${err.message}` : `Error: ${String(err)}`; return { content: [{ type: "text", text: msg }], isError: true, }; } } - src/client.ts:33-68 (helper)The PepestoClient.post method is the underlying HTTP client that sends the actual POST request to the Pepesto API at /catalog, handling auth, JSON serialization, and error wrapping.
async post<T = unknown>(endpoint: string, body: unknown): Promise<T> { if (!this.apiKey) { throw new Error( "PEPESTO_API_KEY is not set. See the README (\"Getting an API key\") for how to " + "obtain one.", ); } const path = endpoint.startsWith("/") ? endpoint : `/${endpoint}`; const url = `${this.baseUrl}${path}`; const headers: Record<string, string> = { "Content-Type": "application/json", Accept: "application/json", Authorization: `Bearer ${this.apiKey}`, }; const res = await this.fetchImpl(url, { method: "POST", headers, body: JSON.stringify(body ?? {}), }); const text = await res.text(); if (!res.ok) { throw new PepestoApiError(res.status, path, text); } if (!text) { return {} as T; } try { return JSON.parse(text) as T; } catch { return text as unknown as T; } } }