trundler
The Trundler server enables agent-driven grocery shopping across multiple New Zealand providers (Countdown, New World, Pak'nSave), running locally on your machine to avoid bot detection.
Authentication
Log in via browser to capture a session for a shopping provider
Check whether a stored session is still authenticated
Product Discovery
Search products by keyword, with filters for in-stock, specials, and max results
Browse products by department (e.g. fruit-veg, pantry, frozen) with optional aisle/specials filters
Retrieve current specials/deals with automatic pagination
Store Management
List available stores for providers with per-store pricing (e.g. New World)
Select and persist the active store for a provider
Cart Management
View current cart contents and totals
Add, update quantity, or remove items by SKU
Note: cart mutations require user approval
Order History (requires login)
List past orders with dates, totals, and status (filterable by time range)
Browse past order items sorted by purchase frequency, name, or price
Retrieve all items from a specific past order by order ID
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@trundlersearch for milk at countdown"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
A desktop app that lets you have a dialogue with an agent while it shops for you.
The agent's brain runs either locally (Ollama) or in the cloud (Claude); either
way, all the actual grocery I/O happens on your own machine and residential connection
via trundler-mcp
(source), so there's no
bot-detection or hosting problem to solve. It's a normal npm dependency of this app —
you don't install it separately.
Cloud brain, local hands. Bot detection only cares about the requests hitting the grocery sites — those are made by trundler-mcp on your machine. The model that decides what to fetch can run wherever you like.
Architecture
Electron main (Node) Renderer (React)
├── TrundlerMcp ──stdio──► trundler-mcp ──► grocery sites (residential IP)
├── Agent loop (shared) ├── chat + streamed tokens
│ ├── OllamaBackend (local) ├── product grid (from tool results)
│ └── AnthropicBackend (cloud) ├── live cart panel
└── IPC + approval gate ◄──── approve/deny ──┤ approval modal (cart mutations)One shared agent loop (
src/main/agent/loop.ts) drives the conversation. It's parameterised by aBackend, so switching Ollama ↔ Claude is a dropdown, not a rewrite.Tools come from MCP, so both brains inherit trundler's own product-listing instructions (letter labels, price-per-unit, cheapest-first).
Cart mutations require approval —
cart_add/cart_update/cart_removepop an approval modal before they run.Structured tool results become UI: product results render as a card grid; cart tools refresh the live cart panel.
Auth is first-class: a status chip shows whether you're signed in to Countdown, with Log in / Log out buttons in the top bar (no need to discover it via an error).
Related MCP server: Swissgroceries MCP
Prerequisites
Node ≥ 20 (dev has 22).
Ollama running locally with a tool-capable model:
ollama pull llama3.1:8b # fast, good enough for dev ollama pull qwen3:14b # stronger tool use, slower
That's it — the grocery data layer (@auckland-ai-collective/trundler-mcp) is a
dependency and installs automatically. No second repo to clone or build.
Setup
npm install # also pulls trundler-mcp (no browser download; that's lazy — see below)Verify the plumbing (no GUI)
npm run smoke -- "find jasmine rice on special" # stdio round-trip via the MCP + Ollama
npm run libcheck # in-process (buildServer) round-tripBoth resolve the MCP from the installed package, run a real tool call, and print the result — use them to confirm your model works before launching the app.
Run the app
npm run dev # launches the Electron app with HMRBuild a distributable:
npm run build # compile main/preload/renderer into out/
npm run dist # + package a Windows installer (electron-builder)Signing in (Countdown)
Countdown/Woolworths needs a login for cart and order history. Two ways:
In the app: click Log in in the top bar — a real browser window opens; sign in there and the app captures the session. The first sign-in downloads a browser (~150 MB, one-time) — the app shows a banner while that happens.
From the CLI:
npx trundler login(the package ships atrundlerbin).
Log out (in the app) clears the stored session and forces re-authentication. New World and Pak'nSave need no login (anonymous, read-only).
Configuration
Brain (Ollama/Claude) and provider are quick switches in the top bar. The ⚙︎ drawer
holds the rest — model, Ollama host, Claude API key, MCP server path, and the
cart-approval and debug-logging toggles — and edits there apply only when you press
Save (Cancel discards). Defaults can also come from env vars — see
.env.example. Settings persist to config.json in the app's userData
directory.
MCP path: by default the app resolves the server from the installed
@auckland-ai-collective/trundler-mcp package automatically — no path to set. Override
with TRUNDLER_MCP_PATH (or the ⚙︎ field) only if you're pointing at a local checkout.
Providers
Provider | id | Cart | Notes |
Countdown |
| ✅ | Needs login — use the Log in button. |
New World |
| ❌ | Read-only; pick a store first (agent does this). |
Pak'nSave |
| ❌ | Read-only; per-store pricing. |
Debug logging / telemetry
Trundler writes a structured JSONL session log capturing the whole interaction:
the user's prompt, the model/backend in use, every MCP tool call and its result,
cart state, approvals, and errors. One file per app run in the app's
userData/logs/ directory (use the open logs button in the debug footer, or
shell reveal).
Off by default. Turn it on with the Debug logging toggle in ⚙︎ Settings; the footer line (with an open logs button) appears only while it's on.
--debugorTRUNDLER_DEBUG=1force it on regardless of the setting, so a user can capture and send you logs without touching Settings:Trundler.exe --debug
Each line is one JSON event, e.g.:
{"t":"2026-07-05T…","type":"user-message","text":"add A to cart","backend":"ollama","model":"llama3.1:8b","provider":"countdown"}
{"t":"2026-07-05T…","type":"mcp-call","name":"cart_add","args":{"sku":"601342","quantity":1}}
{"t":"2026-07-05T…","type":"mcp-result","name":"cart_add","ok":true,"provider":"countdown","data":{…}}
{"t":"2026-07-05T…","type":"cart-state","provider":"countdown","itemCount":1,"detailedItems":0,"total":null}The debug log is what let us pin down real bugs — e.g. detailedItems: 0 with a
non-zero itemCount was the fingerprint of a cart-detail mapping bug in trundler-mcp
(#1, now fixed).
The cart panel still tolerates sparse data defensively in case a provider returns it.
Project layout
src/
shared/types.ts shared types (domain types re-exported from the MCP package)
main/
index.ts window, IPC, orchestration, approval + auth gate
config.ts config + MCP path resolution (from the installed package)
mcpClient.ts trundler-mcp stdio client (spawn + reconnect)
logger.ts JSONL session logger
agent/
loop.ts shared tool loop
ollamaBackend.ts local model (streaming + tools)
anthropicBackend.ts Claude (streaming SSE + tools)
system.ts system prompt (+ MCP instructions)
preload/index.ts contextBridge API
renderer/ React chat UI
scripts/smoke.mjs headless stdio MCP + Ollama check
scripts/lib-check.mjs headless in-process (buildServer) checkNotes / next steps
Only the Ollama path is exercised by the smoke test; the Claude path shares the same loop and is wired but needs an API key to try.
The app spawns the MCP as a subprocess with Electron's bundled Node (
ELECTRON_RUN_AS_NODE). The package also exposes a library entry (buildServer), so a packaged build can instead mount the MCP in-process (in-memory transport) to avoid subprocess/path issues — validated bynpm run libcheck.
License
MIT © 2026 Michael Wells <mike@aaic.nz> — see LICENSE.
An open-source project. Contributions welcome.
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Latest Blog Posts
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/auckland-ai-collective/trundler'
If you have feedback or need assistance with the MCP directory API, please join our Discord server