Skip to main content
Glama
README.md
# Dukaan Agent(Track 1: AI Growth & Agentic Commerce)

> An open agentic-commerce agent for D2C merchants with WhatsApp-first customers — built on **MCP** + **Razorpay test-mode APIs**.

![Python](https://img.shields.io/badge/python-3.11%2B-blue)
![FastMCP](https://img.shields.io/badge/MCP-FastMCP-6E56CF)
![Razorpay](https://img.shields.io/badge/Razorpay-test--mode-0C2451)
![Mode](https://img.shields.io/badge/runs-offline%20(mock--first)-brightgreen)
![License](https://img.shields.io/badge/license-MIT-green)

---

## What this is

Tier-2 D2C merchants take orders on WhatsApp by hand and send payment links one message at a time. **Dukaan Agent** exposes a merchant's catalog and checkout as MCP tools so *any* AI agent (Claude Desktop, etc.) can search products, honour a customer's spend mandate, and complete a **UPI** checkout autonomously — no human clicking a link, every money action bounded and logged.

Razorpay demoed exactly this loop for Zomato at FTX'26 on the Claude Agent SDK. This is the **open version** any WhatsApp-first D2C merchant can plug in — no enterprise contract — with a real delegation model, an append-only audit trail, and measured results across 50 sessions.

**Mock-first:** the whole project runs offline with zero credentials. Razorpay orders and Hinglish parsing fall back to deterministic mocks; adding real keys flips on the live path with no code changes.

---

## Architecture

```
   Customer (WhatsApp-style chat)
        │  "ek blue shirt chahiye 800 se kam mein"
        ▼
   Mock Chat UI  (ui/index.html — demo surface)
        │
        ▼
   MCP Server (FastMCP)  ── server/mcp_server.py
   ├── Tools
   │     search_catalog · get_product_details · create_order · get_session_audit
   ├── Intent parsing      server/intent_parser.py   (Claude Haiku ▸ mock fallback)
   ├── Catalog             server/catalog.py          (SQLite + fuzzy search)
   ├── Delegation          server/delegation.py       (spend mandates)
   ├── Guardrails          server/guardrails.py       (velocity · allowlist · auth · fraction)
   └── Audit trail         server/audit.py            (append-only JSONL)
        │
        ▼
   Razorpay Test-Mode API  ── server/razorpay_client.py  (live ▸ mock fallback)
        │
        ▼
   UPI deep link + QR      ── server/upi.py   →  upi://pay?pa=…&am=…&cu=INR
```

---

## How it works

1. **Customer sends a message** — English or Hinglish (`"ek blue shirt chahiye 800 se kam mein"`).
2. **Intent is parsed** into `{category, keywords, max_price_inr, quantity, color}` (Claude Haiku, or the built-in deterministic parser offline).
3. **`search_catalog`** fuzzy-matches the SQLite catalog and returns in-stock products (out-of-stock items are flagged, never silently ordered).
4. **`create_order` runs all guardrails** — velocity → merchant allowlist → mandate authorization → single-order fraction — before any money moves.
5. **Razorpay order + UPI QR** are generated; the agent hands back a `upi://pay` deep link and a scannable QR — no human in the checkout loop.
6. **Every step is written to an append-only audit log**, retrievable as a timestamped timeline via `get_session_audit`.

---

## Guardrails — the 3-layer delegation model

A spend cap is one `if`-statement; this is a delegation model. A customer pre-authorizes an agent with a **mandate** (total cap, per-category allowlist, expiry). Every order clears four checks — all run (no short-circuit) so the audit log records the full picture, and the first failure is reported as the blocking reason.

| Layer | Check | Blocks when | Reason code |
|---|---|---|---|
| Velocity | ≤ 3 orders / hour / customer | 4th order within the hour | `VELOCITY_EXCEEDED` |
| Anomaly | Merchant on pre-approved allowlist | Merchant not recognised | `SUSPICIOUS_MERCHANT` |
| Authorization | Within mandate: not expired, total cap, category allowlist | Cap / category / expiry breached | `CAP_EXCEEDED` · `CATEGORY_LIMIT_EXCEEDED` · `MANDATE_EXPIRED` · `NO_MANDATE` |
| Single-order | No order > 40% of remaining balance | One order too large | `SINGLE_ORDER_TOO_LARGE` |

---

## Batch results

Seeded 50 synthetic shopping sessions (English + Hinglish) across four customer mandates, run fully offline. Reproduce with `make batch`.

```
18/50 sessions completed successfully · avg 3.0 tool calls to checkout
· guardrails fired correctly in 21/21 attempted violations
```

| Outcome | Count |
|---|---|
| Successful orders | 18 |
| Blocked by guardrails | 21 (cap 6 · category 7 · velocity 5 · expired 3) |
| Errors (out-of-stock / ambiguous) | 11 |
| **Accuracy vs expected outcome** | **50 / 50 (100%)** |

Full breakdown is written to [`batch/report.txt`](batch/report.txt).

---

## Setup

Everything runs **without any API keys** (mock mode). Keys are optional and only enable the live path.

```bash
# 1. Clone and enter
git clone <your-repo-url> dukaan-agent && cd dukaan-agent

# 2. Install dependencies
pip install -r requirements.txt          # or: make setup

# 3. (Optional) add real keys
cp .env.example .env                      # fill in Razorpay test + Anthropic keys

# 4. Seed the catalog
python -m server.catalog                  # or: make seed

# 5. Run the 50-session batch + report
python batch/runner.py && python batch/report.py    # or: make batch

# 6. Run the tests
pytest tests/ -v                          # or: make test

# 7. Open the demo chat UI
open ui/index.html
```

### Connect to Claude Desktop (requires Python 3.10+ for FastMCP)

```bash
python -m server.mcp_server               # or: make serve
```

Add to `claude_desktop_config.json`:

```json
{
  "mcpServers": {
    "dukaan-agent": {
      "command": "python",
      "args": ["-m", "server.mcp_server"],
      "cwd": "/absolute/path/to/dukaan-agent",
      "env": {
        "RAZORPAY_KEY_ID": "your_key_here",
        "RAZORPAY_KEY_SECRET": "your_secret_here",
        "ANTHROPIC_API_KEY": "your_key_here"
      }
    }
  }
}
```

> **Note:** The MCP server (`make serve`) needs Python 3.10+ (FastMCP). The offline pipeline — `make seed`, `make test`, `make batch` — runs on Python 3.9+.

---

## Project structure

```
dukaan-agent/
├── server/
│   ├── mcp_server.py       # FastMCP server — 4 tools, 3 resources (entry point)
│   ├── catalog.py          # SQLite catalog + token-level fuzzy search
│   ├── delegation.py       # spend mandates (cap · category allowlist · expiry)
│   ├── guardrails.py       # velocity · allowlist · authorization · single-order
│   ├── audit.py            # append-only JSONL audit trail
│   ├── intent_parser.py    # Hinglish/English parser (Claude Haiku ▸ mock)
│   ├── razorpay_client.py  # Razorpay test-mode wrapper (live ▸ mock)
│   └── upi.py              # UPI deep link + QR code
├── batch/
│   ├── intents.json        # 50 synthetic shopping intents
│   ├── runner.py           # batch runner (direct calls, offline)
│   └── report.py           # stats + headline metric → report.txt
├── ui/index.html           # mock WhatsApp-style demo chat
├── tests/                  # catalog · delegation · guardrails (pytest)
├── data/                   # SQLite DB, audit log, QR PNGs (auto-created)
├── requirements.txt
├── Makefile                # setup · seed · serve · test · batch · clean
└── .env.example
```

---

## Why this matters

India is building **NPCI's Unified Agent Protocol (UAP)** — national infrastructure for AI agents to make UPI payments under one-time consent with per-merchant spend limits, extending UPI Circle's delegation framework. Dukaan Agent is a working prototype of that direction: consent-bounded, category-limited, auditable agentic checkout over UPI — the shape of Indian agentic commerce before the rails ship.

---

## License

MIT