Pepesto Oneshot (recipe → cart)
pepesto_oneshotConvert recipe URLs, plain text, or an image into a checkout-ready cart for a chosen European supermarket, returning a redirect URL for payment verification.
Instructions
One-shot: turn recipe URLs, free-form text, and/or an image into a ready-to-checkout cart for a chosen European supermarket. Returns a redirect_url that opens the Pepesto checkout UI for the user to verify and pay. Internally runs parse + products + session (not exposed to agents) with Pepesto's heuristics. Use this when you want the simplest end-to-end flow; use pepesto_parse + pepesto_products + session (not exposed to agents) for finer control.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| content_urls | No | Recipe URLs to parse and shop. | |
| content_text | No | Free-form shopping list or extra items to include. | |
| content_image | No | Base64-encoded recipe image. | |
| supermarket_domain | No | Supermarket domain or ID, e.g. 'coop.ch', 'tesco.com', 'ah.nl'. See README for the full list. |
Implementation Reference
- src/tools/oneshot.ts:35-36 (handler)The actual handler function for the pepesto_oneshot tool. It calls client.post('/oneshot', args) via the runTool helper, which sends the request to the Pepesto API and wraps the result in the standard ToolResult format.
async (args) => runTool(() => client.post("/oneshot", args)), - src/tools/oneshot.ts:19-33 (schema)Input schema for pepesto_oneshot: content_urls (optional array of URLs), content_text (optional free-form text), content_image (optional base64 image), and supermarket_domain (optional validated via SupermarketDomain schema).
inputSchema: { content_urls: z .array(z.string().url()) .optional() .describe("Recipe URLs to parse and shop."), content_text: z .string() .optional() .describe("Free-form shopping list or extra items to include."), content_image: z .string() .optional() .describe("Base64-encoded recipe image."), supermarket_domain: SupermarketDomain.optional(), }, - src/tools/oneshot.ts:7-38 (registration)Registration of the 'pepesto_oneshot' tool via server.registerTool() in the registerOneshotTool function, including its title, description, inputSchema, and handler.
export function registerOneshotTool(server: McpServer, client: PepestoClient): void { server.registerTool( "pepesto_oneshot", { title: "Pepesto Oneshot (recipe → cart)", description: "One-shot: turn recipe URLs, free-form text, and/or an image into a ready-to-checkout " + "cart for a chosen European supermarket. Returns a redirect_url that opens the Pepesto " + "checkout UI for the user to verify and pay. Internally runs parse + products + session " + "(not exposed to agents) with Pepesto's heuristics. Use this when you want the simplest " + "end-to-end flow; use pepesto_parse + pepesto_products + session (not exposed to agents) " + "for finer control.", inputSchema: { content_urls: z .array(z.string().url()) .optional() .describe("Recipe URLs to parse and shop."), content_text: z .string() .optional() .describe("Free-form shopping list or extra items to include."), content_image: z .string() .optional() .describe("Base64-encoded recipe image."), supermarket_domain: SupermarketDomain.optional(), }, }, async (args) => runTool(() => client.post("/oneshot", args)), ); } - src/server.ts:23-23 (registration)Import and invocation of registerOneshotTool(server, client) in createServer(), wiring the tool registration into the MCP server.
registerOneshotTool(server, client); - src/client.ts:33-67 (helper)The PepestoClient.post() method that the handler uses to make the actual HTTP POST request to the Pepesto API endpoint '/oneshot'.
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; } }