Skip to main content
Glama
Meal Planner MCP

Meal Planner MCP

by illinigirl

Meal Planner MCP

A self-contained MCP server that plans a week of meals from a local recipe library — optimizing for shared ingredients, reusing leftovers, and avoiding recent repeats — then generates a consolidated shopping list and a Markdown plan you can stick on the fridge.

No cloud, no API keys, no database. Clone it and it runs.

python3 -m venv .venv && source .venv/bin/activate    # isolate deps
pip install -e ".[test]" && pytest -q                 # 76 tests
python -m mealplanner.cli plan --days 7               # try the planner
python -m mealplanner.cli shopping                    # and the shopping list

Example

It ships with a seed library, so it plans the moment you clone it — no data entry. The planner optimizes for ingredient overlap across the week, then consolidates everything into one deduplicated shopping list:

$ python -m mealplanner.cli plan --days 5

Plan for 5 days (household 4):

  2026-06-05   Veggie Fried Rice  (serves 4)
  2026-06-06   Chicken Stir-Fry  (serves 4)
  2026-06-07   Sheet-Pan Chicken & Peppers  (serves 4)
  2026-06-08   Poached Eggs in Tomato Sauce  (serves 4)
  2026-06-09   Chickpea & Spinach Stew  (serves 4)

$ python -m mealplanner.cli shopping

Shopping list:

  [ ] 5  bell pepper
  [ ] 2 can  canned tomato
  [ ] 2 pound  chicken breast
  [ ] 11 clove  garlic
  [ ] 6 tablespoon  soy sauce
  …

The MCP tools run the same logic — plan_week then generate_shopping_list — so in Claude Desktop you just ask for it in plain language.

Related MCP server: yes_chef_mcp

In Claude Desktop

Wired in as a local MCP server, Claude discovers the tools and drives them from a plain-language ask — here it picks up plan_week, calls it with days: 5, then explains the result and offers next steps:

Claude discovering the meal-planner MCP tools and calling plan_week with days=5

The resulting 5-day plan, with Claude explaining the ingredient-overlap optimization and offering to swap a day or build the shopping list

Why an MCP (and not just asking Claude)?

A tool only earns its place if it does something the model can't. This one clears that bar on four counts — which is the whole reason it exists:

Ask

Plain Claude

This server

"Suggest a sci-fi… er, a pasta dish"

✅ fine on its own

(a tool adds nothing)

"Plan around my recipes"

❌ doesn't know them

✅ grounded in your local library

"Don't repeat what we ate last week"

❌ no memory across chats

✅ persistent history file

"Give me a plan + list I can keep"

❌ can't write files

✅ Markdown export

"Merge 1 + 2 + ½ onion across 4 recipes, scaled to 6"

❌ hand-waves the math

✅ exact, deterministic

The model does the creative part (which week feels good); the server supplies the private data, the memory, the persisted artifact, and the exact arithmetic.

What it does

  • plan_week — greedy optimizer: picks recipes that share the most ingredients with what's already chosen, skips anything cooked recently, and fills extra nights from serving-surplus leftovers (a batch of chili that serves 8 covers two dinners for a family of four). The overlap objective rewards similar recipes, so it clusters same-protein nights by design; diversity_weight (off by default) dials in variety vs. waste.

  • swap_meal / remove_meal — iterate per day: "put tacos on Tuesday," "skip Thursday." The plan, shopping list, and export all update with you. ("Make Friday quicker" needs no new tool — Claude calls suggest_recipes then swap_meal.)

  • generate_shopping_list — merges and scales ingredients across the plan's cook days, deduped, with no silent unit conversion.

  • export_plan — writes the week + shopping list and returns it inline (so a remote caller who can't read the server's disk still gets it). format="markdown" (table + checklist, renders in Claude and note apps) or "text" (plain text for pasting into Notes / Reminders). With no path it writes to a known location under the data dir (not the process cwd, which is unpredictable when Claude Desktop launches the server).

  • set_course — recategorize a recipe (mark a stray import as a Sauce so it stops landing in dinner slots). Curation; the planner relies on this normalized field, never on title guessing.

  • suggest_recipes / list_recipes / get_recipe — query the library.

  • record_cooked — log what you actually made; this is the memory that powers avoid-repeats.

  • add_recipe — save one recipe from free text. The everyday way to build your library — no file or format needed.

  • add_recipes — bulk-add a whole batch in one call: the fast way to build a starter library with no Plan to Eat export. Generate a batch from your tastes, review it, and save them all at once (Claude generates; the tool just persists).

  • import_recipes — optional bulk shortcut for an existing Plan to Eat export: by csv_path (a file on the server — local use) or csv_content (pasted CSV text — works for a remote caller with no server-disk access). Offline, no scraping.

Seeding your library

Four ways, none requiring any particular app or format:

  1. Just start — 16 recipes ship in data/recipes.seed.json, so it plans a week the moment you clone it.

  2. Add as you go (the normal path) — paste or describe a recipe in chat; Claude structures it and calls add_recipe. "Save my chili: 2 lb ground beef, an onion, 2 cans tomatoes, kidney beans, chili powder — serves 8." No CSV, no schema.

  3. Generate a starter set (no export needed) — don't want to add them one by one? Ask Claude to generate a batch from your tastes — "25 quick weeknight dinners I'd like, mostly vegetarian" — review it, and it saves them all in one add_recipes call. The planner optimizes over recipes you'll actually cook, so keep the batch to food you'd really make rather than generic filler.

  4. Bulk migrate (optional) — already have a Plan to Eat export? import_recipes loads it in one offline pass. It's a convenience, not a requirement — and adding other formats (Paprika, Mealie, plain JSON) is a documented seam.

Architecture

Pure core + thin adapters. All the logic is I/O-free and unit-tested without a runtime; the MCP server and the CLI are two adapters over the same functions, and one module does all the file I/O.

src/mealplanner/
  models.py       Recipe · Ingredient · HistoryEntry · PlanDay
  ingredients.py  parse free text → {qty,unit,item} · canonicalize · aggregate   (pure)
  core.py         library search · overlap scoring · avoid-repeats               (pure)
  planner.py      greedy week optimizer (overlap + leftovers + avoid-repeats)    (pure)
  exports.py      shopping-list build · Markdown render                          (pure)
  store.py        JSON persistence · Plan to Eat CSV import          (the only I/O)
  server.py       MCP adapter (FastMCP)
  cli.py          CLI adapter
data/recipes.seed.json   bundled starter library (clones-and-runs)

The bundled seed ships in the repo; your mutable state (history, plans, imported recipes) lives in a gitignored state.json under ~/.meal-planner/ — so your real recipes never land in a commit.

Use it from Claude

The server runs over two transports from one codebase — stdio for a local Claude Desktop subprocess, or streamable-HTTP so it can be added as a remote custom connector by URL.

Local (stdio) — Claude Desktop. Clone, make a virtualenv, and install — the install puts a meal-planner console script inside .venv/bin:

git clone https://github.com/illinigirl/meal-planner-mcp
cd meal-planner-mcp
python3 -m venv .venv && source .venv/bin/activate
pip install -e .

Then point your claude_desktop_config.json at that script (absolute path), and restart Claude Desktop — the meal-planner tools will appear:

{
  "mcpServers": {
    "meal-planner": {
      "command": "/absolute/path/to/meal-planner-mcp/.venv/bin/meal-planner"
    }
  }
}

As a custom connector (HTTP). Run it as an HTTP server and point a connector at the URL:

meal-planner --http --port 8765          # or MEAL_PLANNER_HTTP=1
# then add http://localhost:8765/mcp as a custom connector

(For a remote connector — claude.ai / mobile — host it behind a public HTTPS URL with auth, the same way a production MCP deployment would.)

Then just talk: "Plan us 7 dinners this week, nothing we had recently, keep weeknights under 30 minutes — then give me the shopping list." — and iterate: "swap Tuesday for something vegetarian," "skip Thursday."

For reviewers — drive it with Claude Code

It's built to be worked in by an agent. Good first tasks, easiest first:

  1. Run the tests — pip install -e ".[test]" && python -m pytest -q (75; the pure-core subset runs on stdlib alone, the tool-layer tests use the MCP SDK).

  2. Improve the ingredient parser to handle 1 (14 oz) can tomatoes — see ingredients.parse_ingredient and add a test.

  3. Add leftover mode B (cook-once-eat-twice): give recipes produces/uses tags so roast chicken → chicken soup chains. The seed already has both recipes waiting.

  4. Add an explicit unit-conversion table (3 tsp → 1 tbsp) — but only convert when asked, never silently.

CLAUDE.md is the orientation file: architecture, conventions, design rationale, and every deliberate simplification (each one a place to extend).

License

MIT.

Available Tools

14 tools
add_recipeB

Save one recipe to your library — the everyday way to seed it.

No file or special format needed: paste or describe a recipe and let Claude fill these fields in. ingredients is a list of free-text lines ("1 cup flour", "2 cloves garlic", "salt to taste") — each is parsed into a structured amount so it can feed the shopping-list math.

Set course ("Dinner", "Sauce", "Side", "Dessert", …) so the planner knows whether this is a dinner anchor — you know a sauce from a main; pass it along. Omit it and it's treated as a main.

Inputs: title (required), ingredients (required), tags, course, +4 more.

add_recipesA

Bulk-add many recipes in one call — the fast way to build a starter library when you DON'T have a Plan to Eat export to import.

The intended flow: generate a batch tailored to the user's tastes (their cuisines, constraints, what they actually cook — don't just produce generic recipes they won't make), let them review it, then save the batch here. The planner only earns its keep over recipes the user genuinely likes.

Each item: {"title": str, "ingredients": [free-text lines], plus optional "servings", "tags", "total_time_min", "cuisine", "course", "directions"}. Ingredient lines are parsed like add_recipe so they feed the shopping-list math. Items missing a title or ingredients are skipped (and reported); ids are de-duplicated against the library and within the batch. One state write for the whole batch. Returns the saved recipes + counts.

Inputs: recipes (required).

export_planA

Write the current plan + shopping list AND return the rendered content inline.

format: "markdown" (default — renders as a table + checklist in Claude and note apps) or "text" (plain text for pasting into Notes / Reminders / a text message). With no path, writes to a known location under the data dir (MEAL_PLANNER_DATA_DIR/meal-plans/.{md,txt}) — not the process cwd, which is unpredictable when Claude Desktop launches the server. The content field is always returned, so a remote caller who can't read the server's disk still gets the result to display or save client-side.

Inputs: path, format.

generate_shopping_listA

Consolidated shopping list for the current plan — ingredients merged and scaled across cook days (leftover nights add nothing). Deterministic math, not an LLM estimate.

Inputs: no named parameters.

get_current_planC

The currently saved plan, if any.

Inputs: no named parameters.

get_recipeB

Full detail for one recipe, including its ingredient list.

Inputs: recipe_id (required).

import_recipesA

Optional bulk shortcut: import many recipes from a Plan to Eat CSV export. Most users seed with add_recipe instead.

csv_path reads a file on the SERVER's filesystem (local use). csv_content takes the CSV text directly — use this from a remote client that can't reach the server's disk (paste the export's contents).

Inputs: csv_path, csv_content.

list_recipesA

List recipes in the library (bundled seed + your imported/added recipes).

Args: tag: optional tag filter (e.g. "vegetarian", "quick"). max_time: optional max total time in minutes.

Inputs: tag, max_time.

plan_weekA

Build and save a meal plan, optimizing ingredient overlap, reusing serving-surplus leftovers, and avoiding recently-cooked recipes.

main_course_only (default true) keeps sauces/sides/desserts out of dinner slots. diversity_weight (default 0 = off) trades waste for variety: the overlap objective rewards similar recipes, so it clusters same-protein nights; a weight > 0 penalizes repeating a protein within the week. Saves as the current plan; tweak with swap_meal / remove_meal or re-call with new constraints. generate_shopping_list / export_plan use it.

Inputs: days, max_time, start_date, exclude_tags, +5 more.

record_cookedA

Log that you actually cooked a recipe (defaults to today). This is the cross-session memory that powers avoid-repeats — what plain Claude can't do.

Inputs: recipe_id (required), on_date.

remove_mealA

Clear one day of the current plan (eating out, skipping). The date stays as an unplanned slot.

Inputs: date (required).

set_courseA

Recategorize a recipe's course — curation for imports that came in uncategorized (e.g. mark a sauce as "Sauce" so it stops landing in dinner slots). Only your own/imported recipes are editable; seed recipes are read-only.

Inputs: course (required), recipe_id (required).

suggest_recipesA

Candidate recipes matching constraints — the grounding step before you decide a week. Returns recipes from YOUR library (the thing base Claude can't see), filtered by time/tags/ingredients.

Inputs: max_time, exclude_tags, include_tags, include_ingredients.

swap_mealA

Replace one day of the current plan with a specific recipe — "put tacos on Tuesday instead." A literal per-day override (clears any leftover marking on that day). For "make Friday quicker", call suggest_recipes first, then swap.

Inputs: date (required), recipe_id (required).

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.7/5.0

    Scored across 14 tools

    Disambiguation5/5

    Each tool has a clearly distinct purpose: adding recipes (single, bulk, CSV import), listing/getting recipes, planning (plan_week, swap_meal, remove_meal), generating shopping lists, exporting, and logging cooked meals. No two tools overlap in function.

    Naming Consistency5/5

    All tool names use a consistent snake_case verb_noun pattern (e.g., add_recipe, export_plan, record_cooked). The verbs are meaningful and predictably describe the action. No naming convention violations.

    Tool Count5/5

    14 tools cover the full meal planning workflow without being excessive. Each tool serves a specific need, from recipe management to weekly planning and shopping list generation.

    Completeness3/5

    Core planning operations are present, but there are gaps: no tool to update or delete user-added recipes (only add and read). This is a notable missing feature for a recipe library, though the planning cycle itself is complete.

    Maintenance

    ActivityInactive
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • F
      license
      B
      quality
      D
      maintenance
      Enables AI agents to generate budget-disciplined, allergy-safe weekly meal plans, shopping lists, and meal swaps using a fully local deterministic engine.
      20
      -
    • F
      license
      Not graded
      quality
      B
      maintenance
      Enables AI assistants to search recipes, compose nutritionally balanced meals, optimize weekly meal plans based on macro targets for family members, and generate consolidated grocery lists from a personal recipe database.
      -
    • A
      license
      Not graded
      quality
      C
      maintenance
      Enables AI-driven weekly meal planning with structured recipes, cooking steps, and grocery lists.
      1
      MIT
    • A
      license
      A
      quality
      B
      maintenance
      Family meal planning run by your own AI agent: it proposes ten dinners each week, the household votes and leaves feedback from personal links, the top picks win, and a grocery list is built minus what's already in the pantry. Remote MCP server at https://agentchef.net/mcp; connect with an API key and say "Run Agent Chef."
      39
      18 npm
      MIT