MCP App Store
by KeenEthics
Other
Peristyle Grocery Cart icon

Peristyle Grocery Cart

by Peristyle Labs LLC

Overview

Peristyle turns a recipe into a ready-to-checkout grocery cart. Search a recipe, and it pulls the ingredient list, matches each item to real products at Kroger or Walmart, and shows you the options — with size, price, and brand — before anything is added to a cart. Connect your Kroger account once to shop directly through the assistant, or use Walmart's catalog with no sign-in at all. Peristyle remembers your default store, pickup or delivery preference, dietary needs, and preferred brands, so repeat shopping gets faster over time. You always see and approve product matches before they're added — Peristyle fills the cart but never places the order or handles payment. Checkout happens on Kroger's or Walmart's own site.

Tools

amazon_household_options

ChatGPT
Use ONLY when the shopper asks to buy household essentials from Amazon (or asks for Amazon by name for such items). Never suggest Amazon unprompted, and never offer it for groceries or recipe ingredients — those go to Kroger or Walmart. items is what the shopper asked for, e.g. ["paper towels", "dish soap"]. Returns the matching product for each from Peristyle's short household list (paper towels, toilet paper, paper napkins, trash bags, dish soap, dishwasher detergent, laundry detergent, aluminum foil, plastic wrap, gallon storage bags) and lists anything not available. No prices: Amazon shows them on its own confirm page. Tell the shopper which product each item maps to (label and size) in plain terms — don't call any product "best" or "recommended" — then call amazon_build_household_cart_link with the product_ids they want.

confirm_purchase

ChatGPT
Close the loop on a cart after the user checked out in the store's app. Pass the confirmation_id from get_pantry's pending_confirmations (or the pantry_confirmation_id a cart-add returned). One light question — "did your order go through?" — has three answers: yes — `purchased=True`. The order went through as built. no — purchased=False. The cart was never bought. modified* — purchased=True, modified=True. It went through but was changed outside the chat: swaps, drops, store substitutions. Use this the moment they say something changed, without interrogating them for the list; nothing is stocked from the cart, because a cart known not to match the order is a set of guesses. When they do name the lines that didn't make it, pass those in removed_refs and the rest stocks as usual. A receipt settles everything at once: read the one they paste in chat (nothing is uploaded), pass removed_refs for carted lines it doesn't show, and put substitutions or extras it does show into update_pantry as "have". Pass its printed basket total as receipt_total — the only money figure in the system that isn't an estimate of a cart that may never have been bought. Only ever a number printed on a receipt: not a sum you compute, not the cart's own prices, and never a guess. Omit it if the total isn't legible. For a pantry user the purchased items land as fresh "have" (the response's stocked says which); without a pantry the answer is simply recorded — stocked comes back empty and nothing about their kitchen is stored. Confirmations are housekeeping: building or adding a new cart works the same whether or not any are pending, so this call can come after the cart task.

connect_kroger

ChatGPT
Start connecting the user's Kroger account. Returns a login URL and a link_token. Ask the user to open the URL in a browser, sign in to Kroger, and approve access. Then call finish_kroger_connection(link_token=...) with the link_token from this response — the user does not copy, paste, or read anything back; the connection is delivered over this tool's own channel. Passing link_token back explicitly (rather than relying on it being remembered here) is what makes the handshake survive the user's round trip through the browser, even if this client's connection to the server is re-established in between.

delete_account

ChatGPT
Permanently delete the user's Peristyle account and all data stored with it: store connections, saved preferences, the opt-in pantry and product feedback, purchase confirmations, and the API keys this assistant uses. This cannot be undone. Only call it after the user has explicitly asked to delete their account and repeated the confirmation phrase. Usage analytics are kept only in aggregate, no longer linked to the account. To stop shopping without deleting anything, use disconnect_kroger instead.

disable_pantry

ChatGPT
Turn the opt-in pantry off and delete everything it stored: kitchen inventory, product likes/dislikes, and the itemized cart records held as purchase confirmations. Works whether or not the pantry was ever on — those cart records are kept for every signed-in shopper, so this is the erasure control for them too. Confirm with the user first — there is no undo. Preferences and the store connection are untouched. Matching goes back to using only saved preferences. The user can enable_pantry again later, starting empty.

disconnect_kroger

ChatGPT
Remove the user's Kroger connection from Peristyle: the stored OAuth tokens and the link between their Kroger login and this account. Confirm with the user before calling — after this, product matching and cart adds need connect_kroger() again. Recipes, preferences, and pantry are untouched. Kroger keeps its own record of the grant; tell the user they can remove Peristyle under connected apps in their Kroger account settings.

enable_pantry

ChatGPT
Turn on the user's pantry — server-side kitchen inventory that makes every future cart smarter. Opt-in only: ask the user first and explain that their kitchen inventory and product likes/dislikes will be stored with their Peristyle account, and that answering "did your order go through?" will stock what they bought (recipes viewed and preferences stay local). Don't describe the cart records themselves as something this turns on: those are kept for every signed-in shopper either way, and turning the pantry off erases them. Requires a connected account. Idempotent — safe to call if already enabled.

find_kroger_stores

ChatGPT
Find Kroger-family stores near a ZIP code so the user can pick one. No Kroger sign-in required. Returns stores with location_id, name/chain, and address. Show the user the nearby options and save their choice with set_preference("default_location_id", <location_id>) — matching and product search then use it automatically. If the user has no saved default_zip yet, this ZIP is saved as it, so store resolution works even before the user picks; an existing default_zip is left alone — if the user says they moved, update it with set_preference("default_zip", <zip>). Optional chain filters by banner (e.g. "KROGER", "HARRIS TEETER").

finish_kroger_connection

ChatGPT
Finish connecting Kroger after the user has signed in via connect_kroger(). Pass the link_token connect_kroger() returned — always do this if you still have it in context; it's what lets this call find the connection even if the server-side session doesn't remember starting it. Polls until the user completes Kroger sign-in (up to ~2 minutes), then saves the session. Running locally (stdio) it's written to the device; on a remote server the Kroger account attaches to the user's signed-in Peristyle account (the connector's own OAuth bearer) — the key is never shown. If it returns "waiting", give the user a moment to finish and call this again.

get_pantry

ChatGPT
The user's kitchen picture: pantry items with honest status ("have", "probably_out" once past shelf life, or "out"), product loves/hates, and any purchase confirmation worth asking about from an earlier cart. Without a pantry it answers enabled: false and still carries that confirmation — the question reaches every signed-in shopper. Do not call this before matching: every match result (shop_recipe, match_*) already folds in the pantry snapshot as pantry. Use it only when the user asks about their pantry directly, or to resolve a pending confirmation outside a cart flow. Returns {"enabled": false} if the user hasn't opted in — offer enable_pantry once, don't nag. Use it to: (1) skip ingredients the user already has (confirm before skipping anything marked probably_out); (2) bias product picks toward loves and away from hates; (3) resolve pending confirmations — a "did that order go through?" aside answered via confirm_purchase, which fits alongside or after the current cart task and never gates it.

get_recipe

ChatGPT
Return one recipe including steps and ingredient lines.

kroger_add_to_cart

ChatGPT
Add confirmed items to the user's Kroger cart (requires a connected account). items is a list of {"upc": "0001111041700", "quantity": 1}. Use the UPCs the user confirmed from match_recipe_to_kroger or match_items_to_kroger, and the quantity each matched line carried (a shopping list's "x3" or "2 cans" — quantity is how many of the package to add). Always include "price" per item (the store price you showed the user — promo price if on sale); it powers order-value analytics. If the user has pantry enabled, also include "description" (product name) and "ingredient_name" per item — the purchase confirmation and resulting pantry entries are built from them. modality is PICKUP or DELIVERY (defaults to the user's saved preference, then PICKUP). Pass recipe_id so the order is attributed to its source recipe and added to local history. The cart is filled but NOT checked out — the user completes checkout in Kroger. Only a success response with cart_status: "confirmed_in_cart" means items are in the cart — relay its items_added to the user as an explicit receipt (added / skipped / still unresolved). On an error, tell the user plainly that nothing was confirmed added; never describe matched or reviewed items as "added" on the strength of earlier calls. This is ADD-ONLY: the Kroger API cannot remove items, change quantities, or clip coupons. If the user wants something removed or resized, tell them to do it in the Kroger app/site — never promise a rebuild or removal you can't do. If the response includes pantry_confirmation_id, keep the id internal (never show it) and tell the user to come back after checkout to confirm the purchase (then call confirm_purchase) so their pantry stays current.

kroger_auth_status

ChatGPT
Check whether the user's Kroger account is connected and ready to shop. You rarely need this: shop_recipe picks the store itself (Kroger when this account has a Kroger link, otherwise Walmart). Call it when the user asks for Kroger by name or about their Kroger connection. Trust the active field: when it's true the account is connected and usable right now — do NOT call connect_kroger(). A short-lived access token that lapsed between sessions is refreshed automatically, so a past connection stays valid; only reconnect when needs_reauth is true. A 401 here means this client has no API key yet — NOT that a Kroger session expired. If a connect is mid-flight (the user just signed in), the fix is to call finish_kroger_connection() to pull the key, not to reconnect — and if you still have the link_token connect_kroger() returned earlier in this conversation, pass it to finish_kroger_connection(link_token=...) even if this tool reports "No Kroger account connected": that message only reflects what the server session currently remembers, which can lag what you know.

kroger_get_product

ChatGPT
Look up ONE product directly by its UPC or a kroger.com product URL. The authoritative check when keyword search can't find something: if the user pastes a kroger.com link or product number ("I see it right here"), call this instead of re-searching or telling them it doesn't exist. Returns the product with store price, on_sale, and stock (pass/omit location_id same as search). A 404 here — not an empty keyword search — is what "Kroger doesn't have it" actually looks like.

kroger_search_products

ChatGPT
Search the Kroger catalog by keyword for a specific product — independent of any recipe. Use this for freeform lookups the recipe matcher can't do: a particular brand, a specific size (include it in the query, e.g. "olive oil 1 liter" or "olive oil 50.7 oz"), pantry staples, garnishes, or anything the user wants to add directly. Keep query to 8 words or fewer — Kroger rejects longer search terms, so anything past the 8th word is dropped before the search (the result then carries query_truncated: true and the query_searched actually used). Prefer a short product phrase plus size over a sentence. Write a size the way the catalog writes it — a pack count is "12 count" or "12 ct", never a word like "dozen": "eggs 12 count" returns five cartons where "large eggs dozen" returns nothing at all (live 2026-09-10). When a sized query comes back empty, drop the size and search the product alone before telling the user anything is unavailable. When the user wants a specific brand, pass brand (e.g. "Fage") with a generic query — that surfaces the brand's full size range instead of burying it under other products. Raise limit (up to 50) to see more sizes/pack options. If a specific product still doesn't show up but the user can see it on kroger.com, use kroger_get_product with the UPC or URL — never conclude the store doesn't carry it from keyword search alone. To find SALES, search the product category ("ribeye steak" — never words like "steak sale", which just keyword-match product names) and check each result's on_sale flag / compare price_promo to price_regular. Skip products whose stock is "Not available" — that store doesn't carry them right now. Returns products with description, brand, size, price, on_sale, stock, and upc; pass the chosen UPCs straight to kroger_add_to_cart (after the user confirms). Requires a connected Kroger account. Omit location_id to use the saved default store (auto-resolved from default_zip when needed), since prices, sizes, and availability vary by store.

match_items_to_kroger

ChatGPT
Propose Kroger products for a freeform shopping list — no recipe needed. THE main path for a pasted grocery list or a week's meal plan: pass the whole list as plain phrases, one per item, exactly as written ("fage 2% greek yogurt 32 oz", "limes 2", "black beans 2 cans", "bubly 8 pack x3"). Any length — long lists are matched in batches of 50 and returned as one result. Every line comes back with a suggested product plus alternatives, and with quantity (packages to add, parsed from the line's "x3" / "2 cans" / trailing count) and size (the pack size of one, e.g. "12 oz") — pass quantity through to kroger_add_to_cart and check the pick's size against size. Nothing is added to the cart; show the user the picks and pass confirmed UPCs to kroger_add_to_cart. Items where matched is false or stock is "Not available" need a swap — try kroger_search_products with different words, or ask the user. Omit location_id to use the saved default store.

match_items_to_walmart

ChatGPT
Propose Walmart products for a freeform shopping list — no recipe needed. THE main path for a pasted grocery list or a week's meal plan: pass the whole list as plain phrases, one per item, exactly as written ("fage 2% greek yogurt 32 oz", "limes 2", "black beans 2 cans", "frozen corn 12 oz x2"). Any length — long lists are matched in batches of 50 and returned as one result. Every line comes back with a suggested product plus alternatives, and with quantity (packages to add, parsed from the line's "x2" / "2 cans" / trailing count) and size (the pack size of one, e.g. "12 oz") — pass quantity through to walmart_build_cart_link and check the pick's size against size. Nothing is added to the cart; show the user the picks and pass confirmed product_ids to walmart_build_cart_link. Items where matched is false need a swap — try walmart_search_products with different words, or ask the user. offer_type: STORE_ONLY and sold-by-weight picks add fine for pickup/delivery — don't warn about them. No Walmart sign-in is required.

match_recipe_to_kroger

ChatGPT
Propose Kroger products for each ingredient of a recipe at a store. Nothing is added to the cart. Returns suggested products (name, size, price, upc, stock) plus alternatives per ingredient so the user can confirm before adding — treat stock: "Not available" candidates as not carried at this store and pick an alternative. Ingredients listed in unmatched just need a follow-up search (kroger_search_products or match_items_to_kroger with different wording) — they never mean the connector can't search or add to cart. Each item carries BOTH numbers: quantity/unit are what the dish needs ("2 lb"), and cart_quantity is how many packages to add — pass cart_quantity to kroger_add_to_cart, never quantity. Pass servings to shop for a different number of people; the amounts and cart_quantity are scaled for you and the scaling block has the math to show. Omit location_id to use the user's saved default store (set via set_preference). If no default_location_id is saved but default_zip is, the nearest Kroger is used automatically (not saved — save the user's pick with set_preference).

match_recipe_to_walmart

ChatGPT
Propose Walmart products for each ingredient of a recipe. Nothing is added to the cart. Returns suggested products (name, size, price, product_id) plus alternatives per ingredient so the user can confirm before adding. No Walmart sign-in is required. Each item carries BOTH numbers: quantity/unit are what the dish needs ("2 lb"), and cart_quantity is how many packages to add — pass cart_quantity to walmart_build_cart_link, never quantity. Pass servings to shop for a different number of people; amounts and cart_quantity are scaled from the recipe's own yield and the scaling block has the math. Each product also carries stock ("Available"/"Not available"), available_online, and offer_type ("ONLINE_ONLY"/"ONLINE_AND_STORE"/ "STORE_ONLY") — catalog-level signals from Walmart, not live inventory at any one store (the affiliate API has no per-store stock lookup). The suggested pick already skips "Not available" candidates when a better one exists. If the user wants pickup, flag any offer_type: ONLINE_ONLY item before adding it — it won't be on a physical shelf. offer_type: STORE_ONLY does NOT mean the item can't be carted: store-only and sold-by-weight items add fine for pickup or delivery through the cart link. Never describe such an item as unavailable or "store-only" to the user; the only thing that blocks an add is the item being out of stock at their store, which Walmart reports when the link opens.

record_product_feedback

ChatGPT
Remember that the user loves or hates a product or ingredient, so future matches get better without re-asking. sentiment: "love" or "hate". kind: "product" (a specific store item — pass ref=UPC/product_id and store="kroger"/"walmart") or "ingredient" (e.g. hates cilantro — ref defaults to the label). Capture these opportunistically: when the user swaps a suggested product ("not that brand"), rejects an ingredient, or praises something after cooking. One row per subject — restating updates it, so it's safe to record a changed mind. Requires pantry to be enabled. Both kinds pay off on the next cart without the user repeating themselves. A loved product wins the pick whenever it appears in a search. A loved ingredient phrased as the version they want — "Minute Rice", "jarred minced garlic", "Honeycrisp apples" — becomes the store search for that ingredient (search_term_feedback on the line), so record it as the specific label, not a note. A hated ingredient flags the line (ingredient_feedback: "hate") so you ask about a swap. Meal-level preferences ("loves crockpot meals") don't fit here; keep those in chat. Never ask the user to fill in likes/dislikes as a survey — one signal at the moment it's said is the whole job.

review_shopping_list

ChatGPT
Present the FINAL shopping list — the last step before add-to-cart. Call this once per cart, AFTER the triage conversation is done: pantry check relayed, staples skipped, swaps settled. Pass only what will actually be bought. Every item is re-checked against the store for current price and stock, so the total the user sees equals the cart they'll get. Nothing is added to the cart by this tool. On hosts that support it the result MAY render as an interactive final list with an add-to-cart button, but rendering can fail silently and the server cannot tell. Never tell the user a list or card is displayed. Relay the returned list compactly in text (product, size, price, quantity) unless the user confirms they can see the interactive list.

search_recipes

ChatGPT
Find recipes by dish, ingredient, creator — or by URL. query may be a recipe page's address (https://...): the recipe is resolved directly, indexed first if we've never seen it. Otherwise it's a ranked full-text search over title, description, creator and ingredient lines, with fuzzy fallbacks. Check match_kind: exact/url hits are the answer; ingredient hits are fuzzy candidates found via ingredient names because nothing matched directly — confirm with the user before shopping one. When a URL yields nothing, url_error says why (the site blocked the fetch, the address 404s, the page has no recipe data, sign-in needed) — pass that reason on to the user rather than "nothing found". A single recipe rarely covers a multi-part ask (a main plus specific sides or a named ingredient). Before treating any hit — exact or fuzzy — as settling the request, check it covers every part the user named; a match on the main dish alone isn't a match on the whole ask.

set_preference

ChatGPT
Save a user preference with the connected account, so it persists across sessions and devices. Common keys: dietary, default_location_id (Kroger), default_walmart_store_id, default_modality (PICKUP/DELIVERY), preferred_brands, default_zip (ZIP code used to auto-resolve the nearest store for whichever of Kroger/Walmart doesn't have a saved store id yet — shared between both). Pass an empty value to clear a preference.

shop_recipe

ChatGPT
FASTEST path from a dish idea to a reviewable cart: one call that finds the recipe AND proposes Kroger products for every ingredient at the user's store. Prefer this over separate search_recipes → get_recipe → match_recipe_to_kroger calls whenever the goal is a grocery cart. Pass a recipe URL when the user has one — most people arrive from a blog post — and it is looked up (indexed first, if new) instead of searched. Nothing is added to the cart. Returns the recipe (title + ingredients; call get_recipe for cooking steps), the matched products with alternatives, the user's folded-in preferences/pantry, and up to two other recipe candidates in case the top hit isn't what the user meant. Show the user the picks, then call the store's add-to-cart tool once with every confirmed item. A resolved recipe rarely covers a multi-part ask (a main plus specific sides, a named ingredient, "healthy"). Check the recipe actually covers everything the user named before presenting it as done — if part of the ask is missing, say what's missing and add it as a plain ingredient list (match_items_to_walmart / match_items_to_kroger) alongside the recipe rather than dropping it. Store choice is automatic: a signed-in account with a linked Kroger gets Kroger picks (match, then kroger_add_to_cart). An account with NO Kroger link — e.g. someone who signed in with the email magic link — gets Walmart picks instead (walmart_match, then walmart_build_cart_link; no store sign-in needed), so never answer "connect Kroger first" unless the user asks for Kroger by name. Pass location_id to force Kroger at that store. Omit it to use the saved default store.

update_pantry

ChatGPT
Update the user's pantry with one-tap effort — no quantities, ever. items is a list of {"name": "whole milk", "state": "have"|"out"|"remove", "staple": true|false (optional)}. Marking "have" restarts the item's freshness clock (shelf life is inferred from the name — milk decays in days, flour in months). Use "staple": true for things the user always keeps on hand. Use this whenever the user mentions their kitchen in passing ("we're out of eggs", "I picked up basil at the farmers market") — low-friction capture is what keeps the pantry alive. Requires pantry to be enabled.

walmart_search_products

ChatGPT
Search the Walmart.com catalog by keyword, or look up one exact item. If the user shares a walmart.com product link (any URL containing /ip/.../<itemId>) or a bare numeric Walmart item id, pass it as query verbatim: the tool resolves that exact listing instead of keyword-searching, so the product_id you add is the one the user picked. Use for freeform lookups: a particular brand, size, pantry staples, or anything the user wants to add directly. Returns products with description, brand, size, price, product_id, and availability signals (stock, offer_type, available_online); pass chosen ids to walmart_build_cart_link after the user confirms. offer_type: STORE_ONLY items add fine for pickup/delivery — never present one as unavailable. An exact lookup that returns no products means Walmart's items catalog can't resolve that id; next_steps then says what to search for. No Walmart sign-in is required.

Capabilities

WritesInteractive

Example Prompts

Click any prompt to copy it.

App Stats

28

Tools

3

Prompts

ChatGPT

Platforms

Works with

ChatGPT

Data refreshed daily