<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Alyssa Pratt</title>
    <description>The latest articles on DEV Community by Alyssa Pratt (@alyssakpratt).</description>
    <link>https://dev.to/alyssakpratt</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F309322%2F0b19e603-1599-4d53-8397-937ad8f61768.jpg</url>
      <title>DEV Community: Alyssa Pratt</title>
      <link>https://dev.to/alyssakpratt</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/alyssakpratt"/>
    <language>en</language>
    <item>
      <title>Pantry &amp; Plate: An AI Kitchen Assistant That Actually Knows What's Expiring Tomorrow</title>
      <dc:creator>Alyssa Pratt</dc:creator>
      <pubDate>Mon, 30 Mar 2026 02:32:59 +0000</pubDate>
      <link>https://dev.to/alyssakpratt/pantry-plate-an-ai-kitchen-assistant-that-actually-knows-whats-expiring-tomorrow-80o</link>
      <guid>https://dev.to/alyssakpratt/pantry-plate-an-ai-kitchen-assistant-that-actually-knows-whats-expiring-tomorrow-80o</guid>
      <description>&lt;p&gt;&lt;em&gt;This is a submission for the &lt;a href="https://dev.to/challenges/notion-2026-03-04"&gt;Notion MCP Challenge&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Built
&lt;/h2&gt;

&lt;p&gt;I buy in bulk at Costco to save money. The problem: tracking 100+ pantry items, remembering what's expiring, and figuring out what to cook for a two-person household with different food preferences.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Pantry &amp;amp; Plate&lt;/strong&gt; is an AI-powered pantry tracker and meal planner that eliminates that cognitive load. It parses grocery receipts using Claude's vision, tracks expiry dates in Notion, and runs an agentic chat assistant that knows exactly what's in my kitchen, what needs to be used first, and what my partner won't eat (mushrooms, shrimp, brussels sprouts).&lt;/p&gt;

&lt;p&gt;Here's what makes it different: when I ask "What can I make tonight?", the agent doesn't guess. It queries my actual Notion databases — pantry items with real expiry dates, my household preferences, my planned meals for the week — then reasons over the results before suggesting anything.&lt;/p&gt;

&lt;p&gt;The agent might respond: "The Italian sausage expires in four days. How about a quick sausage pasta with the San Marzano tomatoes from your pantry? I'll add it to your meal agenda."&lt;/p&gt;

&lt;p&gt;That's not a canned response. The agent read &lt;code&gt;Expiry Date: March 30&lt;/code&gt; from my Notion Pantry database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Features
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Receipt parsing with human-in-the-loop review&lt;/strong&gt;: Upload a photo of a Costco receipt. Claude's vision parses "KS ORG STOCK" into "Kirkland Organic Chicken Stock" (it guesses). You review and correct before saving.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Compact pantry view&lt;/strong&gt;: 100+ items grouped by category, collapsible sections, inline editing, expiry date tracking.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;11-tool conversational agent&lt;/strong&gt;: Query pantry, shopping list, meal history, preferences, kitchen tools, and meal agenda — all via natural language.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Shopping list with purchase-to-pantry flow&lt;/strong&gt;: Check "purchased" → item moves to pantry automatically.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Preferences as silent context&lt;/strong&gt;: The agent knows my partner hates mushrooms. It never narrates this — just excludes them.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Video Demo
&lt;/h2&gt;


&lt;div&gt;
  &lt;iframe src="https://loom.com/embed/6239dde638834956aafb0b4265911295"&gt;
  &lt;/iframe&gt;
&lt;/div&gt;


&lt;h2&gt;
  
  
  Show us the code
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://github.com/Aprattcodes/pantry-tracker" rel="noopener noreferrer"&gt;https://github.com/Aprattcodes/pantry-tracker&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Stack
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Next.js 15, TypeScript, Tailwind v4, shadcn/ui&lt;/li&gt;
&lt;li&gt;Anthropic Claude API (vision for OCR, forced tool use for parsing, agentic loops)&lt;/li&gt;
&lt;li&gt;Notion as the persistent data layer (6 databases)&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;@notionhq/client&lt;/code&gt; v2&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How I Used Notion MCP
&lt;/h2&gt;

&lt;p&gt;We implemented the &lt;strong&gt;MCP tool-use pattern&lt;/strong&gt; — Claude decides which of 11 tools to call, queries live Notion data, and reasons over results in an agentic loop — using &lt;code&gt;@notionhq/client&lt;/code&gt; v2 with integration tokens.&lt;/p&gt;

&lt;p&gt;We initially attempted &lt;code&gt;mcp.notion.com&lt;/code&gt; but it requires OAuth authentication, which doesn't fit a server-side web application architecture where the backend needs persistent database access. The agentic pattern is structurally identical to an MCP client-server interaction: &lt;strong&gt;tool discovery, tool invocation, result handling, multi-turn reasoning&lt;/strong&gt;. The transport layer differs, but the intelligence pattern is the same.&lt;/p&gt;

&lt;h3&gt;
  
  
  The Agentic Loop in Action
&lt;/h3&gt;

&lt;p&gt;Here's how &lt;code&gt;chatAgent()&lt;/code&gt; works:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// 11 tools available to the agent&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;CHAT_TOOLS&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;query_pantry&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Get all pantry items with expiry dates&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;query_preferences&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Get household food preferences&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;query_meal_agenda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Get planned meals for the week&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;suggest_meals&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Generate meal suggestions&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;add_to_meal_agenda&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Add a meal to the weekly plan&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;log_meal&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Log a meal to history&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ... 5 more tools&lt;/span&gt;
&lt;span class="p"&gt;];&lt;/span&gt;

&lt;span class="c1"&gt;// The loop: Claude calls tools, we execute, Claude reasons over results&lt;/span&gt;
&lt;span class="k"&gt;while &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;stop_reason&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tool_use&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nx"&gt;iterations&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="mi"&gt;8&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;toolUse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;content&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;c&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="kd"&gt;type&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tool_use&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Execute against real Notion databases&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;executeNotionTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;toolUse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;toolUse&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;input&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Feed result back to Claude for reasoning&lt;/span&gt;
  &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;user&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tool_result&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="p"&gt;}]&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
  &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;model&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;CHAT_TOOLS&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the user says "What can I make tonight?", Claude decides to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Call &lt;code&gt;query_preferences&lt;/code&gt; → learns one of us hates mushrooms, we both love Mexican food&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;query_pantry&lt;/code&gt; → sees Italian sausage expires in four days&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;query_meal_agenda&lt;/code&gt; → checks what's already planned&lt;/li&gt;
&lt;li&gt;Call &lt;code&gt;suggest_meals&lt;/code&gt; → generates contextual suggestions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The agent makes multiple Notion queries in a single conversational turn, reasoning over real data — not summaries.&lt;/p&gt;

&lt;h3&gt;
  
  
  Notion as the Data Layer
&lt;/h3&gt;

&lt;p&gt;Six databases power the entire system:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Database&lt;/th&gt;
&lt;th&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pantry&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Items with category, quantity, expiry date, store&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Shopping List&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Items grouped by store with purchase status&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Meals Log&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Meal history with date, category, effort level&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Preferences&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Likes, hard-passes, cuisine preferences per person&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Kitchen Tools&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Equipment with effort levels (sous vide = High)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Meal Agenda&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Currently planned meals for the week&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The agent can query any of these, cross-reference them, and write back. When I say "Add Italian sausage pasta to my meal plan," it:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Calls &lt;code&gt;add_to_meal_agenda&lt;/code&gt; → writes to Meal Agenda DB&lt;/li&gt;
&lt;li&gt;Auto-triggers &lt;code&gt;log_meal&lt;/code&gt; → writes to Meals Log DB&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Two Notion writes from a single conversational command.&lt;/p&gt;

&lt;h3&gt;
  
  
  Human-in-the-Loop Receipt Parsing
&lt;/h3&gt;

&lt;p&gt;Costco receipts are cryptic. "KS ORG STOCK" means Kirkland Signature Organic Chicken Stock. We use Claude's vision with &lt;strong&gt;forced tool use&lt;/strong&gt; to guarantee structured output:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;anthropic&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;messages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;claude-sonnet-4-20250514&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;max_tokens&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Required for 27+ item receipts&lt;/span&gt;
  &lt;span class="na"&gt;tool_choice&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;tool&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;record_pantry_items&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The parsed items appear in a review table — original receipt text on the left, Claude's interpretation on the right. The human corrects mistakes, picks expiry dates, then saves. The review step is critical: Claude makes educated guesses, but a human confirms before anything hits Notion.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key Technical Decisions
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Forced tool use for structured output&lt;/strong&gt;: &lt;code&gt;tool_choice: { type: "tool", name: "record_pantry_items" }&lt;/code&gt; guarantees JSON output. Prompt engineering alone was unreliable for 27+ item receipts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;max_tokens: 4096 for long receipts&lt;/strong&gt;: Below this threshold, Claude silently truncates. Discovered this the hard way with a Costco run.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Preferences as silent context&lt;/strong&gt;: Early versions narrated preferences ("I see you don't like mushrooms..."). Now the agent applies them without explanation — like a real kitchen assistant would.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Store inference from preferences&lt;/strong&gt;: When the user says "add ground beef to my shopping list," the agent queries preferences, finds "household buys ground beef at Costco," and auto-sets store=Costco, quantity=3 lbs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purchase-to-pantry flow&lt;/strong&gt;: Checking "purchased" on a shopping list item creates a pantry entry with the same name/store/quantity. One checkbox replaces a manual two-step process.&lt;/p&gt;




&lt;h2&gt;
  
  
  Reflections
&lt;/h2&gt;

&lt;p&gt;Building this taught me that the MCP pattern isn't about the transport layer — it's about giving an AI agent &lt;strong&gt;live data access and the autonomy to query what it needs&lt;/strong&gt;. Whether that's via a remote MCP server or a custom tool wrapper around &lt;code&gt;@notionhq/client&lt;/code&gt;, the intelligence pattern is the same: tool discovery, invocation, result handling, multi-turn reasoning.&lt;/p&gt;

&lt;p&gt;The hardest part wasn't the agentic loop — it was the UX around it. Making tool calls visible (we show "tool pills" in the chat), handling the &lt;code&gt;max_tokens&lt;/code&gt; stop reason gracefully, and ensuring the agent doesn't narrate its reasoning when it should just act.&lt;/p&gt;

&lt;p&gt;Notion as a data layer worked surprisingly well. The real-time queries mean the agent always has accurate state. No stale caches, no sync issues. When I buy groceries and check them off, the next "What can I make?" query sees the updated pantry.&lt;/p&gt;

&lt;p&gt;For a two-person household that meal plans around Costco runs and expiring produce, this is the tool I actually wanted to exist.&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Built by a developer who got tired of throwing away forgotten produce.&lt;/strong&gt;&lt;/p&gt;

</description>
      <category>devchallenge</category>
      <category>notionchallenge</category>
      <category>mcp</category>
      <category>ai</category>
    </item>
  </channel>
</rss>
