Blinkit MCP Server
by viztfxyz
README.md
# blinkit-tool
[](https://github.com/viztfxyz/blinkit-tool/actions/workflows/ci.yml)
[](https://www.npmjs.com/package/blinkit-tool)
[](LICENSE)
Unofficial [Blinkit](https://blinkit.com) client: search, browse, cart, checkout and UPI pay, as a **CLI**, a
**TypeScript library**, and an **MCP server** for Claude, Cursor and other agents.
Payment is headless (Blinkit → Zomato zpaykit, no browser needed). The UPI QR is handed to whoever pays either as a
[qrbaton](https://qrbaton.vercel.app) pay page (items, bill, delivery address, one-tap GPay / PhonePe / Paytm) or
as a plain QR image.
> [!WARNING]
> Not affiliated with, endorsed by, or supported by Blinkit or Zomato. It talks to the same private
> endpoints blinkit.com uses, which can change or break at any time, and automated use may be against
> their terms. Use it for your own account, at your own risk. Real orders and real money are involved:
> `pay` only proceeds when you pass the exact amount `checkout` showed.
## Requirements
- Node.js ≥ 22
- A Chromium-based browser only for `pay --browser` (or if the headless API path fails)
## Install
```bash
npm install -g blinkit-tool # gives you the `blinkit` command
blinkit search milk -p 560034
```
Or run it without installing:
```bash
npx blinkit-tool search milk -p 560034
```
As a library in your own project: `npm install blinkit-tool`. To hack on it, see [CONTRIBUTING.md](CONTRIBUTING.md).
## CLI
```bash
blinkit location 560034 # browse without login (indicative prices)
blinkit search paneer --in-stock
blinkit search "pears soap" --out-of-stock # also list sold-out items
blinkit browse "Bathing Soaps" --sort price
blinkit product 211410
blinkit login 98xxxxxxxx # SMS OTP
blinkit address list
blinkit address use home # label, id, or part of the address
blinkit cart add 211410 -q 2
blinkit checkout # payable bill for that address
blinkit pay --confirm 642 # the exact amount checkout showed
```
Every listing command takes `--json`. Run `blinkit <command> --help` for all options.
### Sold-out products
Blinkit's search never returns sold-out products, and category listings put them at the very end, so by default
you mostly see what's in stock. Pass `--out-of-stock` (`-o`) to `search` or `browse` (MCP: `includeOutOfStock: true`)
to also list sold-out items, tagged `[OUT OF STOCK]` / `inStock: false`, after the in-stock ones. For search this
looks up the categories the top results belong to and pages their listings, so it takes a few extra seconds.
`blinkit product <id>` works for sold-out products too.
### Paying
`blinkit pay --confirm <rupees>` places the order and waits for the UPI payment (10 minutes by default). How the
QR reaches the payer is set with `--handoff`:
| `--handoff` | What you get |
| ------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qrbaton` (default) | A [qrbaton](https://qrbaton.vercel.app) link. The page shows the items, bill and delivery address; the payer taps Pay to open their UPI app, and the page updates when the payment completes. No account or API key. |
| `qr` | Just the UPI QR as a PNG (and the `upi://` link). Nothing leaves your machine except the payment itself. |
If qrbaton can't be reached, `pay` falls back to the plain QR and says so. The QR PNG is always saved to
`~/.cache/blinkit-tool/upi_qr.png`.
Other options: `--no-open` prints the link / QR path instead of opening it, `--agent <name>` shows who prepared the
order on the pay page, `--browser` drives blinkit.com in Chromium instead of the API, `--dry-run` stops before a QR
is generated.
> qrbaton never handles money, but anyone with a pay link can see the order, including the delivery address.
> Use `--handoff qr` if you don't want that.
## MCP server (Claude, Cursor, Grok…)
Add the stdio server to your client. `npx` downloads and runs the latest version, nothing to install first:
```json
{
"mcpServers": {
"blinkit": {
"command": "npx",
"args": ["-y", "blinkit-tool", "mcp"]
}
}
}
```
- **Claude Desktop**: `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or `%APPDATA%\Claude\claude_desktop_config.json` (Windows), then restart Claude
- **Claude Code**: `claude mcp add blinkit -- npx -y blinkit-tool mcp`
- **Cursor**: `.cursor/mcp.json` (project) or `~/.cursor/mcp.json` (global)
- **Grok CLI**: `grok mcp add blinkit -- npx -y blinkit-tool mcp`
Log in once from a terminal (`npx blinkit-tool login <phone>`), or let the agent do it with the OTP tools.
The server runs on your machine, so cloud-only agents can't reach it.
### Agent flow
`blinkit_session` → (login: `blinkit_login_request_otp`, `blinkit_login_verify_otp`) → `blinkit_use_address` →
`blinkit_search` / `blinkit_browse` → `blinkit_cart_set` → `blinkit_checkout` → **user confirms the amount** →
`blinkit_pay` → poll `blinkit_pay_status` until `qr_ready` → send the user `payLink` (or, with `handoff: "qr"`, the QR
image attached to the status result).
The server's instructions tell agents never to request an OTP for a number the user didn't give, and never to call
`blinkit_pay` without explicit confirmation of the exact amount.
## Library
```ts
import { Blinkit, payWithUpi } from "blinkit-tool";
const bk = new Blinkit(); // session at ~/.config/blinkit-tool/session.json, or pass a path
await bk.setLocation({ pincode: "560034" });
const milk = await bk.catalog.search("milk", { sort: "price", inStock: true, limit: 5 });
await bk.cart.add(milk[0].productId, 2);
console.log((await bk.cart.get()).bill.toPay);
// Login: bk.account.requestOtp(phone), then bk.account.verifyOtp(code).
// Pay: await payWithUpi(bk, { confirmAmount: 642, handoff: "qr", openPage: false });
```
## Configuration
| Variable | Purpose |
| ----------------- | --------------------------------------------------------------------------------- |
| `BLINKIT_SESSION` | Session file (default `~/.config/blinkit-tool/session.json`, owner-readable only) |
| `BLINKIT_BROWSER` | Chromium-based browser for the browser pay path (auto-detected otherwise) |
| `QRBATON_URL` | qrbaton host, if you run your own (default `https://qrbaton.vercel.app`) |
Caches (pincode lookups, category tree, last pay status, QR image) live in `~/.cache/blinkit-tool/`.
## Troubleshooting
- **"blinkit.com is refusing automated requests"**: Cloudflare is challenging the request. Wait a few minutes and retry.
- **"session expired or not logged in"**: run `blinkit login <phone>` again.
- **Search doesn't show something you expected**: it may be sold out; retry with `--out-of-stock`.
- **`pay` says the amount differs**: the bill changed (stock, charges, promo). Run `blinkit checkout` and confirm the new amount.
- **"createOrder returned no PAS token"**: the cart has a pending payment. Wait for it to expire (about 10 minutes) and retry.
## Project layout
```
src/
bin/ CLI and MCP entry points
cli/ commander commands and terminal formatting
mcp/ MCP tool definitions
client.ts Blinkit: the public client (session + catalog, cart, account)
core/ config, HTTP transport (Chrome TLS impersonation), session, storage, errors
services/ catalog, cart, account, and parsing of Blinkit's layout payloads
pay/ zpaykit API path, browser fallback, QR decoding, qrbaton / QR handoff
types.ts shared types
test/ vitest
```
## Development
| Script | Purpose |
| ----------------------- | ----------------------------- |
| `npm run dev -- <args>` | CLI from source (tsx) |
| `npm run mcp` | MCP server from source |
| `npm test` | Vitest |
| `npm run typecheck` | Type-check `src/` and `test/` |
| `npm run build` | Compile to `dist/` |
| `npm run lint` | Biome lint + format check |
| `npm run format` | Apply Biome fixes/formatting |
| `npm run check` | Lint, typecheck and tests |
## Contributing
Issues and PRs welcome: see [CONTRIBUTING.md](CONTRIBUTING.md). Please follow the [Code of Conduct](CODE_OF_CONDUCT.md),
and report security problems privately as described in [SECURITY.md](SECURITY.md). Never paste your `session.json`,
OTPs, or pay links into an issue.
## License
[MIT](LICENSE)
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues