npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@auckland-ai-collective/trundler-mcp

v0.1.10

Published

Local MCP server for grocery shopping providers (Countdown / Woolworths NZ) with browser-assisted login. Runs entirely on your own machine and residential connection. Extensible to other providers.

Readme

trundler-mcp

npm version npm downloads license

A local MCP server for grocery shopping. Runs entirely on your own machine and residential connection — no cloud services, no datacenter IPs, no bot-detection logistics.

Published on npm: @auckland-ai-collective/trundler-mcp (repo trundler-mcp). Install with npm install @auckland-ai-collective/trundler-mcp or run it straight away with npx @auckland-ai-collective/trundler-mcp.

The running server, its tools, and the on-disk session folder keep the shorter name trundler (the MCP server id is trundler, sessions live under …/trundler/).

Supported providers:

  • Countdown / Woolworths NZ — full account access (login + cart + order history)
  • New World (Foodstuffs) — anonymous price/product browsing
  • Pak'nSave (Foodstuffs) — anonymous price/product browsing

Providers at a glance

Different chains expose different things, so trundler's capabilities vary by provider.

| Provider | id | Login | Add to cart | Search / specials / browse | Store selection | |----------|-----|:-----:|:-----------:|:--------------------------:|-----------------| | Countdown / Woolworths NZ | countdown | Required (browser) | ✅ Yes | ✅ (after login) | Automatic (by fulfilment region) | | New World | newworld | Not required | ❌ No (read-only) | ✅ (anonymous) | Per-store — pick one with set_store | | Pak'nSave | paknsave | Not required | ❌ No (read-only) | ✅ (anonymous) | Per-store — pick one with set_store |

In short:

  • Countdown / Woolworths — you log in once in a real browser; after that you can search, view specials, and add items to a real cart and read your order history.
  • New World & Pak'nSaveno login needed to search and compare prices, but they are read-only: you cannot add to a cart or see order history (yet). Because Foodstuffs pricing is per-store, you must choose a store first with set_store.

Why the difference? Countdown authenticates a real user session, which unlocks the cart. The Foodstuffs (New World / Pak'nSave) read APIs serve anonymous guests, so browsing needs no login — but the cart requires an authenticated session that isn't wired up yet (see Roadmap).

How it works

Everything lives in one local process over stdio — the agent launches trundler as a subprocess. No ports, no CORS, no session server. There are two auth models depending on the provider:

Countdown / Woolworths — browser-assisted login

  • login opens a real browser window; you sign in yourself (handling any MFA/captcha), and trundler captures the session. No password is stored. Because the login happens in a real browser on your home connection, it's the most bot-resistant approach.
  • After the session is captured the window stays open so you can accept Chrome's "Save password?" prompt, then close it yourself to finish (a 2-minute fallback closes it if you walk away). Set TRUNDLER_LOGIN_AUTOCLOSE=1 to close immediately on capture instead, or TRUNDLER_LOGIN_KEEP_OPEN_MS to change the fallback timeout.
  • Everything after that is authenticated fetch() using the captured cookies + XSRF token — no browser needed.
  • Silent refresh renews short-lived tokens by briefly relaunching a headless browser with the saved session. If it has fully expired, tools tell the agent to run login again.

New World / Pak'nSave — anonymous guest token

  • No login. trundler mints an anonymous guest token by loading the store homepage and reading the session cookie it hands out, then calls the read API with plain fetch(). The token is cached and refreshed automatically (~30-minute life).
  • The homepage sits behind Cloudflare bot-management that rejects Node's fetch, so the token mint shells out to curl (which passes). curl ships with Windows 10 1803+, macOS, and Linux — no extra install needed on a normal machine.
  • Pricing is per-store: use list_stores to find one and set_store to select it. Your choice is persisted per provider.

Session/config data is stored per provider outside the repo:

  • Windows: %LOCALAPPDATA%\trundler\<provider>\
  • macOS/Linux: ~/.config/trundler/<provider>/

Install

From npm (no build step needed — ships compiled):

npm install @auckland-ai-collective/trundler-mcp

Or run the server directly without installing:

npx @auckland-ai-collective/trundler-mcp

Chromium (used only for the Countdown login) is not downloaded at install time. The first time you run login, trundler fetches it once (~150 MB) if it's missing — so merely depending on the package stays lightweight, and New World / Pak'nSave (which never need a browser) pull nothing extra. To pre-fetch it yourself: npx playwright install chromium.

Building from source instead:

npm install
npm run build

Register with your agent

Add to your MCP config (e.g. .mcp.json). The simplest form runs the published server straight from npm — no clone, no build:

{
  "mcpServers": {
    "trundler": {
      "command": "npx",
      "args": ["-y", "@auckland-ai-collective/trundler-mcp"]
    }
  }
}

Or point at a local build:

{
  "mcpServers": {
    "trundler": {
      "command": "node",
      "args": ["D:/Projects/MCP/trundler-mcp/dist/index.js"]
    }
  }
}

During development you can point it at the TypeScript source instead:

{
  "mcpServers": {
    "trundler": {
      "command": "npx",
      "args": ["tsx", "D:/Projects/MCP/trundler-mcp/src/index.ts"]
    }
  }
}

After changing server-level code (including the presentation instructions), rebuild (npm run build) and reconnect the MCP — instructions and tool lists are sent once at connection time.

Use as a library

If you're embedding trundler in your own app (e.g. a shell that mounts the MCP server in-process rather than spawning it), import from the package root. This entry point has no side effects — importing it starts nothing:

import {
  buildServer,        // -> McpServer, ready to .connect(transport)
  buildRegistry,      // -> ProviderRegistry of all providers
  DEFAULT_PROVIDER,   // -> "countdown"
} from '@auckland-ai-collective/trundler-mcp';

// Mount on your own transport:
const server = buildServer();
await server.connect(myTransport);

// …or drive a provider directly, bypassing MCP entirely:
const cart = await buildRegistry().get('countdown').cartGet();

Types (ShoppingProvider, Cart, Product, …) are exported too. The package ships its own .d.ts declarations. Prefer spawning the process instead? The published trundler-mcp bin is the stdio server; trundler is the setup CLI (below).

Setup per provider

Countdown / Woolworths — log in once:

trundler login             # installed package (bin)
# or, from a source checkout:
npm run cli login          # or: node dist/cli.js login   (after build)

A browser window opens — sign in to Woolworths. Once the session is captured the window stays open so you can save your password if prompted; close it to finish. Verify any time with trundler check (or npm run cli check). The first login also downloads Chromium once if it isn't already present.

New World / Pak'nSave — no login; just pick a store. Via your agent:

list_stores  { "provider": "newworld", "query": "auckland" }
set_store    { "provider": "newworld", "storeId": "<id from list_stores>" }

Do the same with "provider": "paknsave" for Pak'nSave. Until a store is set, the read tools return a "no store selected" error.

For local testing you can pre-seed a store via env var instead of set_store: TRUNDLER_NEWWORLD_STORE_ID / TRUNDLER_PAKNSAVE_STORE_ID. These are test overrides only — never a shipped default.

Tools

Every tool takes an optional provider argument (default: countdown).

| Tool | Purpose | Providers | |------|---------|-----------| | search_products | Search by keyword | all | | get_specials | Current specials (paginated) | all | | browse_products | Browse by department / category | all | | list_stores | List a provider's stores (per-store-pricing providers) | newworld, paknsave | | set_store | Select the active store (persisted) | newworld, paknsave | | login | Open a browser to sign in | countdown | | check_login | Verify the stored session | countdown | | logout | End the session (clears in-memory cache + on-disk tokens) | countdown | | cart_get / cart_add / cart_update / cart_remove | Manage the cart | countdown | | list_past_orders / list_past_order_items / get_order_items | Order history | countdown |

Calling a login/cart/order tool on New World or Pak'nSave returns a clear "requires login — not yet supported" error rather than failing silently.

Product listings

trundler ships server-level instructions telling the agent how to present product lists: label each item with a capital letter (A, B, C…) for easy quantity-picking, show price per unit and sort cheapest-per-unit first, and include a link to open each product's photo/detail page. This makes cross-product and cross-chain price comparison straightforward.

Adding a provider

Implement ShoppingProvider (see src/core/provider.ts) in a new src/providers/<name>/ folder and register it in src/providers/index.ts. The MCP tools are provider-agnostic and dispatch automatically. Foodstuffs banners (New World, Pak'nSave) share one FoodstuffsProvider parameterised by a banner config — adding another Foodstuffs banner is a few lines in src/providers/foodstuffs/banners.ts.

Capabilities a provider doesn't support (e.g. cart on a read-only provider) simply throw an error, which surfaces to the agent as a tool error.

Roadmap

  • Foodstuffs cart & orders (Tier 2). New World / Pak'nSave cart and order history need an authenticated session. Their login exchange is Cloudflare-protected against automated browsers, so it must be captured from a genuine browser (connect to your real Chrome), not Playwright's bundled Chromium. Not yet implemented.

Trade-off

trundler refreshes on demand, not on a schedule — for Countdown it can't renew tokens while your machine is off, and an expired session needs a quick manual login. That's the cost of staying local and on a residential IP. If you later need unattended scheduled runs, host it on an always-on machine at home (not a datacenter, or you reintroduce the bot-detection problem).