commerce-ops-harness
README.md
# Commerce Ops Harness MCP
A remotely hosted [Model Context Protocol](https://modelcontextprotocol.io) server (TypeScript + PostgreSQL) that lets a commerce ops person handle the most engineer-dependent exception in the queue — a stuck or delayed order with a carrier exception — through to the refund decision: an automatic refund executed under policy, or a manager escalation that carries the full diagnosis.
The MCP is the product. There is no frontend; any MCP client (Claude, Cursor, MCP Inspector) is the operator console.
| | |
|---|---|
| **MCP endpoint** | `https://commerce-ops-harness.onrender.com/mcp` (Streamable HTTP) |
| **Health** | `https://commerce-ops-harness.onrender.com/health` |
| **Source** | `https://github.com/VasuBansal7576/commerce-ops-harness` |
| **Demo video** | https://youtu.be/HsXpjWSPT6k |
System design with diagrams: [ARCHITECTURE.md](./ARCHITECTURE.md). Product decisions, assumptions, and exclusions: [PRODUCT_DECISIONS.md](./PRODUCT_DECISIONS.md). AI usage: [AI_WORKLOG.md](./AI_WORKLOG.md).
## How it works
The AI client does the language; the server owns truth and money. Ops asks in plain English, the client drives the tools, and every dollar-moving decision is computed and enforced server-side in a single transaction — the model can request a refund, but it cannot talk its way past the policy.
A refund executes automatically only when **every** check passes; otherwise the server files a pending manager escalation with the diagnosis and the exact checks that failed, so the manager decides from evidence instead of re-investigating.
| Check | Rule |
|---|---|
| `amount_positive` | Requested amount > $0 |
| `amount_within_cap` | Requested amount ≤ **$150.00** |
| `amount_within_paid` | Requested amount ≤ refundable balance (paid − already refunded) |
| `order_within_30_days` | Order placed no more than **30 days** ago |
| `risk_score_below_70` | Customer risk score **< 70** (exactly 70 fails) |
| `carrier_exception_verified` | A lost / damaged / stuck exception **derived from the carrier event stream** — never a pre-set flag — and not superseded by a later delivery |
Duplicate protection covers the same eligible **amount and action**: repeating `decide_refund` for an amount already refunded returns the original refund; repeating it for an amount with a pending escalation returns that escalation. Both are backed by unique indexes, and the decision runs with the order row locked — concurrent requests cannot double-refund. Partial refunds are first-class: ops picks the amount (default: full paid amount) and it passes through the same checks.
## MCP tools
| Tool | What it does |
|---|---|
| `list_scenarios` | Seeded orders, one per way the workflow can go — start here |
| `open_case` | Full case: customer + risk score, payments, shipments, carrier events, refunds, escalations |
| `get_timeline` | Unified chronological timeline across all systems |
| `diagnose` | Derives carrier-exception verification from events, classifies root cause with evidence, previews what `decide_refund` would do (read-only) |
| `decide_refund` | The single state-changing tool: auto-refund or manager escalation, per the policy above |
| `get_escalations` | Manager view: pending escalations with failed checks + full diagnosis |
| `get_audit_log` | Audit trail of every decision |
| `reset_demo_data` | Reset the synthetic database to its seeds |
## Try it (no local setup)
Connect any MCP client to the hosted `/mcp` URL above, then:
1. `list_scenarios`
2. `open_case` → `get_timeline` → `diagnose` with `ord_1001`
3. `decide_refund` with `ord_1001` → automatic $89.99 refund
4. `decide_refund` again → the same refund returned, not a second one
5. `decide_refund` with `ord_1004` → manager escalation (risk score exactly 70)
6. `get_escalations` → the escalation with failed checks and diagnosis attached
### Seeded scenarios
| Order | Scenario | Expected outcome |
|---|---|---|
| `ord_1001` | Lost package, all checks pass | Auto-refund $89.99 |
| `ord_1002` | Damaged, but paid $210 (> cap) | Full refund escalates; partial ≤ $150 auto-executes |
| `ord_1003` | Lost, order 45 days old | Escalation (age) |
| `ord_1004` | Stuck, risk score exactly 70 | Escalation (risk) |
| `ord_1005` | Slow but no exception events | Escalation (exception not verified) |
| `ord_1006` | Refund already executed | Idempotent — original refund returned |
| `ord_1007` | Stuck event, later delivered | Escalation (exception superseded by delivery) |
The database is shared — concurrent testers see each other's refunds and escalations. `reset_demo_data(confirm=true)` restores a clean slate.
## Run locally
```bash
docker run -d --name commerce-ops-pg -e POSTGRES_PASSWORD=devpass \
-e POSTGRES_DB=commerce_ops -p 5433:5432 postgres:16-alpine
npm install
npm run dev # schema + seeds apply automatically on boot
npm test # 28 tests: policy boundaries, event derivation, idempotency, E2E over MCP
```
`DATABASE_URL` defaults to the docker container above; point it anywhere else to override.
## Deploy (Render)
`render.yaml` provisions the web service plus a managed PostgreSQL instance and wires `DATABASE_URL`; schema and seeds apply on first boot. See [HOSTING.md](./HOSTING.md).
## Design notes
- **Money is integer cents** in storage and policy; the tool boundary accepts dollars and rejects sub-cent amounts. The $150.00 cap is exact, not floating-point-adjacent.
- **Diagnosis is a deterministic evidence assembler** and the policy engine is a pure function — so the boundaries that matter are unit-tested exactly: $150.00 vs $150.01, day 30 vs 31, score 69 vs 70.
- **Verification is derived, not declared.** `shipments.status` exists as carrier metadata but is never consulted for eligibility — only `carrier_events` are.
- **One state-changing tool.** Everything else is read-only, which keeps the safety review surface small and the audit trail complete.
This server cannot be deployed
Maintenance
ActivitySlowing
ResponsivenessNo issues