comparebasket
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., "@comparebasketcompare prices for my basket: 2x amul butter 500g, 6 eggs"
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.
Basket
Give it a grocery list. It checks Blinkit, Zepto, BigBasket and Amazon Now with live prices, normalizes pack sizes, and tells you which platform is cheapest for the whole basket — in your terminal, at a URL, or over MCP.
Built on webcmd: each platform is a real compiled webcmd command, not a screen-scraper bolted to the side.
BASKET pincode 110048 · 31.9s · 3 platforms · via webcmd
╭──────────────────────────────────────────────────────────────────────╮
│ITEM BIGBASKET ZEPTO BLINKIT│
├──────────────────────────────────────────────────────────────────────┤
│amul butter 500g ₹230.00 ₹310.00 ₹310.00│
│ 500g · 46.00 / 100g 500g · 62.00/100g 500g · 62.00│
│tata salt 1kg ₹21.00 ₹22.00 ₹29.00│
├──────────────────────────────────────────────────────────────────────┤
│delivery — — —│
│handling — — —│
├──────────────────────────────────────────────────────────────────────┤
│GOODS TOTAL ₹251.00 ₹332.00 ₹339.00│
│items found 2/2 2/2 2/2│
╰──────────────────────────────────────────────────────────────────────╯
╭─ VERDICT ──────────────────────────────────────────────────────────────╮
│ BigBasket is cheapest — ₹251.00 │
│ You save ₹81.00 vs Zepto at ₹332.00 │
╰────────────────────────────────────────────────────────────────────────╯
⚠ Goods only — delivery and handling are NOT included
● Web view http://localhost:7777Why baskets, not items. Cheapest-per-item is a lookup anyone can do. Cheapest-basket is arithmetic nobody does by hand, and it regularly flips the answer — a platform wins on two items and loses on the other ten, or wins only because it quietly didn't stock half your list.
Everything in the output is read live. No prices, packs or fees are baked into this repo. If a number isn't on the page, the tool says it doesn't know it rather than filling in a plausible one — see Fees.
Install
npm install -g comparebasket
basket setupbasket setup is a wizard: it checks webcmd, clears the stale browser lock that
otherwise blocks the bridge, generates the adapters, and walks you through
setting a delivery location on each platform. It exists because every one of
those steps cost real debugging time once.
Prerequisite: webcmd —
npm install -g @agentrhq/webcmd. Node ≥ 20.
Check anytime:
basket doctor ✔ Node 22.15.0
✔ webcmd 0.5.3
✔ webcmd browser bridge connected
✔ adapters installed: blinkit, zepto, bigbasket, amazon
✔ data directory writable (C:\Users\HP\.basket)Related MCP server: grocery-mcp
Use
basket list.txt # terminal table
basket list.txt --ui # rich boxed terminal view
basket list.txt --web # terminal view + http://localhost:7777
basket "tata salt 1kg" # one-line basket, no file needed
cat list.txt | basket --ui # stdinCommand | Does |
| Compare a basket (the default) |
| Price one product everywhere — seconds, not minutes |
| Show / set delivery + handling (see Fees) |
| Web view only, paste a basket in the browser |
| First-run wizard |
| Environment check |
Flag | Effect |
| Serve the interactive page, print its URL, stay running (Ctrl+C stops) |
| Rich boxed terminal view |
| Machine-readable output, nothing else |
| Default |
| Display only — the browser profile is the real source |
| Port for |
| Don't launch a browser |
Basket format
One item per line, optional leading quantity. # comments and blanks ignored.
2x amul taaza toned milk 500ml
amul butter 500g
6 eggs
tata salt 1kg2x foo and 3 foo are quantities. 500 ml milk is not — a leading number
followed by a unit reads as a pack size, and bare numbers above 20 are never
quantities.
Fees
Totals are goods-only by default, and the output says so.
Delivery and handling are only revealed at checkout. The search and listing pages
this tool reads carry nothing usable — Blinkit's own search state ships
chargeableDeliveryCost: 0 and additional_charges_config: null, because no
cart exists yet. Reading real fees would mean adding items to a real cart, which
v1 deliberately doesn't do.
An earlier version shipped hand-written fee tables marked verified: false. They
rendered as authoritative rupee amounts and were fiction. They're gone. Nothing
in this repo knows what Blinkit charges for delivery.
If you know your actual fees, supply them once:
basket fees # what's set
basket fees --set blinkit --delivery 25 --handling 9 --free-above 199
basket fees --clear blinkitStored in ~/.basket/fees.json. Any platform with fees set gets them folded into
its total and free-delivery threshold applied; any platform without stays
goods-only. The header switches from GOODS TOTAL to TOTAL only when every
platform in the run has fees configured — a mixed row would compare a
fees-inclusive total against a goods-only one and call it a saving.
Calling it from an agent
Every command takes --json and returns one envelope shape, so nothing has to
parse prose or ANSI boxes.
basket search "amul butter 500g" --platforms=blinkit,bigbasket --json{
"ok": true,
"query": "amul butter 500g",
"cheapest": {
"platform": "bigbasket", "found": true, "confident": true, "price": 230,
"name": "Amul Butter Pasteurised",
"pack": "500g", "pricePerUnit": "₹46.00 / 100g",
"confidence": 0.95, "confidenceReason": null,
"url": "https://www.bigbasket.com/pd/104864/...", "error": null
},
"results": [ ... ],
"feesKnown": false
}Three states per platform, and they mean different things:
Row | Means |
| A real match. Only these are eligible to be |
| Something came back, but it isn't this product — |
|
|
A query with only low-confidence rows returns cheapest: null and exit 3. The
tool would rather say "no confident match" than hand you a ₹208 pack of Cadbury
Gems as the price of something it doesn't stock.
Failures use the same envelope — {"ok": false, "error": "..."} — and the exit
code tells you which kind without reading the message:
Exit | Meaning |
| Success |
| Runtime failure (backend down, browser bridge dead) |
| Usage error (bad flag, unknown platform, empty query) |
| Ran fine, found nothing |
basket setup refuses to run when stdin isn't a TTY rather than hanging on a
prompt inside a pipeline.
The web view
--web (or serve) starts a local server on 127.0.0.1 and prints a URL. The
page shows the same comparison as the terminal, plus a basket editor — edit the
list, tick platforms, press Compare, and it re-runs without going back to
the shell. A terminal run refreshes any open tab within a few seconds.
It binds to loopback only, deliberately: POST /api/compare drives a real
browser with whatever basket it's handed, and that should not be reachable from
whatever Wi-Fi you're on.
Route | Method | Does |
| GET | The page |
| GET | Last comparison as JSON ( |
| GET | Available platforms, defaults, threshold |
| POST |
|
| GET | Liveness + whether a run is in flight |
curl -s localhost:7777/api/result | jq .winner
curl -s -X POST localhost:7777/api/compare \
-H 'content-type: application/json' \
-d '{"items":"tata salt 1kg","platforms":["blinkit","bigbasket"]}'Only one comparison runs at a time — a second returns 409 rather than two runs
fighting over a single browser session.
Cheapest ≠ best
The most dangerous failure for a price comparator is rewarding the platform that stocked the least — an empty basket is always the cheapest basket. Three guards:
1. Complete baskets win. If any platform stocks everything, only complete baskets compete.
2. Otherwise, compare the common subset — only lines every platform actually priced. The output says so: "cheapest on what everyone stocks — compares 8 of 12 items available everywhere".
3. Coverage sits next to price. If the winner covers less than someone else:
⚠ Zepto only stocked 8/12 of your basket.
→ Best coverage: Blinkit 11/12 at ₹1,679.00 — one trip instead of two.
Cheapest is only cheapest if you don't mind sourcing 4 items elsewhere.Repeated
no-resultsfor staples (milk, bread, eggs) usually means a scrape failure, not genuine absence. Searches retry once on empty; if a platform still returns zeros across common items, treat its total as suspect, not cheap.
Matching: what it refuses, and why
Candidates score 0–1. Below 0.55 they're flagged and shown, never silently totalled. Four conditions refuse outright:
Refusal | Example |
Unit family mismatch | 500g butter vs 500ml oil — ₹/100g and ₹/100ml share no axis |
Brand mismatch | Query says Amul, product is Mother Dairy |
Product type mismatch | Query says butter, name has no "butter" |
Different category |
|
The last is the subtle one, and a real bug this codebase hit: matching on "is the word present" cheerfully bought sixteen packs of butter cookies. Comparing category sets catches it.
Pack normalization
2 x 250ml → 500ml · 0.5 L → 500ml · 1kg → 1000g · 1 dozen → 12
The scorer buys the packs you'd actually need. Ask for 500g, find only 200g
packs, and it charges for three — not 2.5, and not pretending a 200g pack
competes with a 500g one. The table prints 3× 200g so you can check the maths.
webcmd is the engine
Every search is a real webcmd command:
webcmd blinkit search --query "amul butter 500g" -f jsonAdapters live at ~/.webcmd/clis/<site>/search.js — Strategy.UI,
browser: true, siteSession: 'persistent' (so the delivery location survives
across commands), typed errors, and a shared 7-column envelope:
{ name, packSize, packUnit, price, mrp, inStock, url }They are generated by scripts/build-adapters.js from src/extract/*.js.
Adapters may only import from @agentrhq/webcmd/*, so they can't require this
project's source — generating them beats maintaining the same selectors twice.
npm run build:adapters # all sites
node scripts/build-adapters.js zeptosrc/platforms.js picks a backend once per run: webcmd when adapters are
installed and the bridge is up, else a direct CDP fallback speaking the same
envelope. The run header prints which served it — check it before trusting a
demo.
If webcmd doctor won't go green
The failure we hit, and the fix, because the error doesn't name it:
Opening in existing browser session. This usually means that the profile is already in use by another instance of Chromium.
An orphaned cloak Chromium holds a lock on ~/.webcmd/cloak/profiles/default.
basket setup clears this for you, or by hand:
Get-CimInstance Win32_Process -Filter "Name='chrome.exe'" |
Where-Object { $_.CommandLine -like '*cloakbrowser*' } |
ForEach-Object { Stop-Process -Id $_.ProcessId -Force }rm -f ~/.webcmd/cloak/profiles/default/Singleton{Lock,Cookie,Socket}
webcmd doctorA first-run fetch failed is different: cloak is downloading ~150 MB of Chromium
into ~/.cloakbrowser/. That one just needs working network and patience.
Platforms
Site | Status | Strategy |
Blinkit | ✅ default |
|
Zepto | ✅ default |
|
BigBasket | ✅ default |
|
Amazon Now | ⚠ opt-in |
|
Instamart | ❌ stub | Results render intermittently |
JioMart, DMart | ❌ | No prices without a location cookie / login wall |
Zepto's live domain is zepto.com — zeptonow.com doesn't resolve.
Adding one
Recon in the webcmd browser. A hydration blob on
windowbeats CSS selectors.src/extract/<site>.jsexportingsite,label,searchUrl,readyExpression,extractExpression, with a strategy note in the header.Return the shared envelope exactly.
Register in
src/extract/index.js, and add its display name toLABELSinsrc/fees.js. (No fee numbers — that file holds none by design.)npm run build:adapters && node scripts/probe.js <site> "amul butter 500g"and compare against the live page. A probe that passes on wrong data is worse than one that fails.
MCP
claude mcp add basket -- node "$(npm root -g)/comparebasket/src/mcp-server.js"Tool | Does |
| Whole basket → markdown table + JSON summary |
| One product priced everywhere — fast |
| Starts the web view and returns its URL |
| Buy link, defaults to the winner |
The MCP process hosts the web server itself, so open_basket_view hands back a
live URL the user can keep using after the conversation moves on.
compare_basket's JSON block carries totalsInclude: "goods only" | "goods + fees" alongside feesKnown and feesMissing, so a model can't quote a
goods-only figure as a final bill without having been told.
Layout
Path | Job |
| Command surface |
|
|
| Basket text → |
| Per-platform extraction (source of truth for adapters) |
| Pack parsing, match confidence, price-per-unit |
| Best pick, packs needed, totals, ranking, coverage |
| User-supplied fee config — carries no fee numbers itself |
| Local HTTP server + JSON API |
| Boxed terminal renderer |
|
|
| Package root vs writable |
Runtime state lives in ~/.basket/ (override with BASKET_HOME) — nothing is
ever written inside the installed package.
Development
npm test # 47 tests, no network
node scripts/probe.js bigbasket "amul butter" # one site, one query
node scripts/mcp-smoke.js # MCP protocol check
npm run build:adapters # regenerate webcmd adaptersTroubleshooting
Symptom | Cause |
| webcmd bridge down and no debug Chrome — run |
| Delivery location not set for that platform |
Every platform returns 0 rows | Location lost from the webcmd profile |
One platform empty, rest fine | That site changed markup — re-run recon |
Implausible price | A discount badge parsed as price — filter badge lines |
| A comparison is already running |
Total has no delivery charge | Expected — goods-only until you run |
Not implemented
Cart preparation · login/auth · persistence beyond the last result · multi-pincode · coupons · membership pricing · price history · split-basket optimization (cheapest single platform vs cheapest split across two, fees counted twice — the strongest next upgrade).
License
MIT
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityBmaintenanceA Model Context Protocol server for real-time Swiss grocery shopping that searches and compares products across 8 major Swiss retailers (Migros, Coop, Aldi, Denner, Lidl, Farmy, Volgshop, Otto’s), normalizes per-unit prices, surfaces promotions, computes optimal multi-store shopping plans, and works with any MCP-compatible client without API keys or accounts.Last updated74426AGPL 3.0
- Flicense-qualityCmaintenanceMCP server for grocery-related web automation using Playwright, enabling AI assistants to interact with grocery websites.Last updated
- AlicenseBqualityBmaintenanceMCP server for finding, comparing, and ranking the cheapest real offers across eBay, Amazon, Craigslist, OfferUp, and Google Shopping, with tax estimation and exact-model filtering.Last updated6MIT
- AlicenseAqualityBmaintenanceAn API-only MCP server for Blinkit that enables automated shopping on the Indian quick-commerce platform, supporting login, search, cart, checkout, and payment via UPI.Last updated25MIT
Related MCP Connectors
Hosted Amazon Seller and Vendor MCP server for Claude, ChatGPT, Cursor, Codex, Gemini, Copilot.
Shopping MCP for AI agents: search, compare, Amazon buy links. Auto-register.
Hosted MCP server for LLM cost estimation, model comparison, and budget-aware routing.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- 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/aizen2006/comparebasket'
If you have feedback or need assistance with the MCP directory API, please join our Discord server