Add Ingredient to List
add_ingredient_to_listAdd recipe ingredients to your shopping list by matching them with existing items for proper categorization in AnyList.
Instructions
Add a specific ingredient from a recipe to a shopping list. Matches existing items or recent items by name for proper AnyList categorization.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| recipe_name | No | Recipe name (case-insensitive match) | |
| recipe_id | No | Recipe identifier | |
| ingredient_name | Yes | Name of the ingredient to add (matched against recipe ingredients) | |
| list_name | No | Target list name (defaults to "Groceries") | Groceries |
| event_id | No | Meal plan event identifier to link this ingredient to | |
| event_date | No | Meal plan event date in YYYY-MM-DD format |
Implementation Reference
- src/tools/lists.ts:133-216 (handler)Implementation of the 'add_ingredient_to_list' tool handler and schema.
server.registerTool( 'add_ingredient_to_list', { title: 'Add Ingredient to List', description: 'Add a specific ingredient from a recipe to a shopping list. Matches existing items or recent items by name for proper AnyList categorization.', inputSchema: z.object({ recipe_name: z.string().optional().describe('Recipe name (case-insensitive match)'), recipe_id: z.string().optional().describe('Recipe identifier'), ingredient_name: z.string().describe('Name of the ingredient to add (matched against recipe ingredients)'), list_name: z.string().default('Groceries').describe('Target list name (defaults to "Groceries")'), event_id: z.string().optional().describe('Meal plan event identifier to link this ingredient to'), event_date: z.string().optional().describe('Meal plan event date in YYYY-MM-DD format'), }), }, async ({ recipe_name, recipe_id, ingredient_name, list_name, event_id, event_date }) => { try { if (!recipe_name && !recipe_id) { return { content: [{ type: 'text', text: 'Error: provide either recipe_name or recipe_id' }], isError: true, }; } const client = AnyListClient.getInstance(); const recipes = await client.getRecipes(); let recipe; if (recipe_id) { recipe = recipes.find((r) => r.identifier === recipe_id); } else if (recipe_name) { const term = recipe_name.toLowerCase(); recipe = recipes.find((r) => r.name?.toLowerCase() === term) ?? recipes.find((r) => r.name?.toLowerCase().includes(term)); } if (!recipe) { return { content: [{ type: 'text', text: `Recipe not found: ${recipe_name ?? recipe_id}` }], isError: true, }; } const term = ingredient_name.toLowerCase(); const ingredient = recipe.ingredients.find((i) => i.name?.toLowerCase() === term) ?? recipe.ingredients.find((i) => i.name?.toLowerCase().includes(term)) ?? recipe.ingredients.find((i) => i.rawIngredient?.toLowerCase().includes(term)); if (!ingredient) { return { content: [{ type: 'text', text: `Ingredient "${ingredient_name}" not found in recipe "${recipe.name}"` }], isError: true, }; } await client.getLists(); const list = client.getListByName(list_name); if (!list) { return { content: [{ type: 'text', text: `List not found: "${list_name}"` }], isError: true, }; } const ingredientName = ingredient.name || ingredient.rawIngredient; await list.addIngredient(ingredient, { recipeId: recipe.identifier, recipeName: recipe.name, eventId: event_id, eventDate: event_date, }); return { content: [{ type: 'text', text: `Added ingredient "${ingredientName}"${ingredient.quantity ? ` (${ingredient.quantity})` : ''} from "${recipe.name}" to "${list_name}"` }], }; } catch (error) { return { content: [{ type: 'text', text: `Error adding ingredient: ${error instanceof Error ? error.message : String(error)}` }], isError: true, }; } }, );