Meal Planning AI Agent
Overview
I self-host Grocy for pantry tracking and Mealie for recipe management. This project bridges both through the Model Context Protocol (MCP), letting a single AI agent answer questions like "What can I cook this week with what I already have?"
The entire system runs on my local network using a local LLM served by Ollama.
Architecture
- Grocy MCP Server: wraps Grocy's REST API, exposes pantry stock queries with parent-product aggregation.
- Mealie MCP Server: wraps Mealie's REST API, exposes recipe lookup, meal plan writing, and shopping list management.
- LangGraph Agent: connects to both MCP servers via
langchain-mcp-adapters, discovers tools at startup, and uses a ReAct loop for reasoning. - Ollama: serves local LLMs (Gemma 3, Gemma 4, Qwen) on the home network.
Both MCP servers are built with FastMCP using the streamable-http transport, returning typed Pydantic models. They run as Docker containers on a Raspberry Pi.
Key Design Decisions
Parent-Product Aggregation
Grocy tracks products at the barcode level, so three brands of olive oil appear as three entries. The Grocy MCP server aggregates stock at the parent-product level, merging quantities across children before returning data. The agent only sees "Olive Oil: 2 bottles."
Tool Design for Small Models
Local LLMs (7–12B parameters) struggle with large tool catalogs. I consolidated multiple narrow tools into fewer, broader ones — for example, a single list_products tool with a filter parameter instead of separate tools per filter. Clear docstrings guide the model's filter selection.
Prompt-Based Behavioral Tuning
The system prompt encodes rules for tool-result trust, fuzzy ingredient matching, filter selection logic, and anti-hallucination guardrails. Small models typically need these rules spelled out explicitly.
Deployment
MCP servers are containerized with python:3.13-slim and uv. A GitLab CI pipeline builds Docker images and pushes them to a private registry. Watchtower on the Raspberry Pi polls for updates and rolls out new versions automatically.
Where It Stands
This project is still very much a work in progress. The core pipeline works: the agent can query both Grocy and Mealie, reason about ingredient availability, and produce meal plans. But there's a lot of room for improvement, and I keep iterating on it.
One area I'm actively experimenting with is the LLM itself. I've been testing different models (Gemma 3, Gemma 4, Qwen) to see how they handle tool selection and multi-step reasoning at different parameter sizes. I recently started running Gemma 4 on a Jetson Orin Nano to explore whether a small, always-on device could serve as a dedicated backend for this agent. The generation speed is solid for simple queries, but the accumulated latency from chained tool calls in the ReAct loop is still too high for a smooth interactive experience.
On the tool side, I'm working on trimming down the data returned by each MCP tool. Small models are sensitive to context window size, and sending back full product or recipe objects when the agent only needs a name and a quantity wastes tokens and degrades reasoning quality. I'm refining the Pydantic models to return leaner payloads, and considering composite server-side tools — things like a single check_recipe_feasibility call that handles the pantry lookup internally, instead of forcing the agent to make multiple round-trips.
I also plan to expand what the agent can do: more Grocy tools for managing open stock and searching by product name, better shopping list integration with Mealie, and eventually some form of verified-facts layer that gates the LLM's claims through deterministic checks before surfacing them to the user.