Batch Add Ingredients to List
add_ingredients_to_listAdd ingredients from multiple recipes to a shopping list while automatically removing duplicates across recipes. Defaults to the Groceries list for efficient meal planning.
Instructions
Add ingredients from multiple recipes to a shopping list at once. Defaults to the "Groceries" list. Handles duplicates across recipes: each ingredient is only added once.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| recipe_names | No | Array of recipe names | |
| recipe_ids | No | Array of recipe identifiers | |
| list_name | No | Target list name (defaults to "Groceries") | Groceries |
Implementation Reference
- src/tools/groceries.ts:125-199 (handler)The handler function for 'add_ingredients_to_list' that resolves recipes and adds their ingredients to a specified list.
async ({ recipe_names, recipe_ids, list_name }) => { try { if (!recipe_names?.length && !recipe_ids?.length) { return { content: [{ type: 'text', text: 'Error: provide recipe_names or recipe_ids (non-empty array)' }], isError: true, }; } const client = AnyListClient.getInstance(); const allRecipes = await client.getRecipes(); await client.getLists(); const list = client.getListByName(list_name); if (!list) { return { content: [{ type: 'text', text: `List not found: "${list_name}"` }], isError: true, }; } const resolvedRecipes: typeof allRecipes = []; const notFound: string[] = []; // Resolve by IDs if (recipe_ids) { for (const id of recipe_ids) { const recipe = allRecipes.find((r) => r.identifier === id); if (recipe) resolvedRecipes.push(recipe); else notFound.push(id); } } // Resolve by names if (recipe_names) { for (const name of recipe_names) { const term = name.toLowerCase(); const recipe = allRecipes.find((r) => r.name?.toLowerCase() === term) ?? allRecipes.find((r) => r.name?.toLowerCase().includes(term)); if (recipe) resolvedRecipes.push(recipe); else notFound.push(name); } } const lines: string[] = []; let totalAdded = 0; let totalSkipped = 0; let totalUnchecked = 0; for (const recipe of resolvedRecipes) { const result = await addRecipeIngredientsToList(client, recipe, list); totalAdded += result.added.length; totalSkipped += result.skipped.length; totalUnchecked += result.unchecked.length; lines.push(`${recipe.name}: +${result.added.length} added, ${result.unchecked.length} unchecked, ${result.skipped.length} skipped`); } if (notFound.length) { lines.push(`\nNot found: ${notFound.join(', ')}`); } lines.unshift( `Batch add to "${list_name}": ${totalAdded} added, ${totalUnchecked} unchecked, ${totalSkipped} already on list`, ); return { content: [{ type: 'text', text: lines.join('\n') }], }; } catch (error) { return { content: [{ type: 'text', text: `Error adding ingredients: ${error instanceof Error ? error.message : String(error)}` }], isError: true, }; } }, ); - src/tools/groceries.ts:113-124 (registration)Tool registration for 'add_ingredients_to_list'.
server.registerTool( 'add_ingredients_to_list', { title: 'Batch Add Ingredients to List', description: 'Add ingredients from multiple recipes to a shopping list at once. Defaults to the "Groceries" list. Handles duplicates across recipes: each ingredient is only added once.', inputSchema: z.object({ recipe_names: z.array(z.string()).optional().describe('Array of recipe names'), recipe_ids: z.array(z.string()).optional().describe('Array of recipe identifiers'), list_name: z.string().default('Groceries').describe('Target list name (defaults to "Groceries")'), }), }, - src/tools/groceries.ts:119-123 (schema)Zod schema definition for the 'add_ingredients_to_list' tool inputs.
inputSchema: z.object({ recipe_names: z.array(z.string()).optional().describe('Array of recipe names'), recipe_ids: z.array(z.string()).optional().describe('Array of recipe identifiers'), list_name: z.string().default('Groceries').describe('Target list name (defaults to "Groceries")'), }),