demo · v1.0 · 18 tools

Standard MCP.
Built for agents.

Lumi MCP turns a restaurant POS into 18 typed tools any AI agent can call. No vendor SDK. No bespoke connector. Just the Model Context Protocol.

🤖 You are an AI agent? Skip the prose — read llms.txt, fetch tools.json for live schemas, paste mcp.json into your client.

Endpoints

stdio (Claude Desktop)
python -m services.mcp_external
streamable HTTP
POST <host>/mcp/mcp
tool manifest
/tools.json
audit tail (REST)
GET /api/external/agent_audit

Quick start

1. List the tools

# JSON-RPC over HTTP — no SDK required
curl -X POST $LUMI_HOST/mcp/mcp \
  -H "Authorization: Bearer $LUMI_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"jsonrpc":"2.0","id":1,"method":"tools/list"}'

2. Discover, calculate, place — the recommended flow

# 1) find a merchant
{"method":"tools/call","params":{"name":"merchant.search","arguments":{"area":"Central"}}}

# 2) read its menu (sku is a closed enum, validated)
{"method":"tools/call","params":{"name":"menu.get","arguments":{"merchant_id":"merch_..."}}}

# 3) quote the order — show user the total before they confirm
{"method":"tools/call","params":{"name":"order.calculate",
 "arguments":{"merchant_id":"merch_...",
              "items":[{"sku":"BEV-LATTE","quantity":2}]}}}
# → returns { quote_id, total_hkd, expires_at, needs_review, ... }

# 4) commit — quote_id is also a natural idempotency key
{"method":"tools/call","params":{"name":"order.place",
 "arguments":{"quote_id":"q_...",
              "payment_token":"<jwt from payment.authorize>"}}}

3. Or paste this MCP client config

{
  "mcpServers": {
    "lumi": {
      "url": "https://<host>/mcp/mcp",
      "transport": "streamable_http",
      "headers": { "Authorization": "Bearer <your-token>" }
    }
  }
}

Conversation flow

merchant.searchmenu.get[order.calculate →] order.place ↘ ↗ cart.create + cart.add* + cart.checkoutsession.handoff (cross-surface)

Two-stage commit (order.calculate → order.place(quote_id=…)) is the recommended path. The quote_id binds items + total + delivery_note at quote time, doubles as a natural idempotency key, and lets you preview the price before charging.

Tool catalog

18 primary tools across 7 namespaces. Schemas live in tools.json. {REQ} = required arg; {IDEM} = accepts idempotency_key; {BEARER} = identity prefers Authorization header.

merchant.*discovery
merchant.search
Discover merchants by area + cuisine. Returns opaque merchant_id to feed everything downstream.
menu.*catalog
menu.get merchant_id
Live menu with stock / promo / out-of-stock alternatives. items[*].sku is the closed enum the agent must reuse verbatim.
order.*single-call ordering · two-stage commit
order.calculate
Quote a draft order. Returns quote_id (10-min TTL) + frozen total + review flags. Show the user, wait for confirm.
order.place idempotency_key bearer
Commit. Either quote_id (recommended) or {merchant_id, items}. payment_token from payment.authorize charges immediately.
order.list
Recent orders placed via the external MCP channel. Replay-friendly.
cart.*multi-turn ordering
cart.create
Open a cart for (merchant, cardholder, agent). Returns cart_id.
cart.add idempotency_key
Append a line. Per-line note. Embeds the running cart card as ui://lumi/cart/<id>.
cart.update
Change qty (0 = delete) or rewrite note for one line.
cart.remove
Drop a line. Convenience for cart.update(qty=0).
cart.view
Read cart with the rendered UI card. cart_id optional (falls back to the cardholder's most recent open cart).
cart.checkout idempotency_key bearer
Convert open cart → real order via the same handler as order.place. Cart transitions to checked_out.
session.*cross-surface continuity
session.handoff
Mint a one-shot token. User pastes it into another agent host (Claude Desktop ↔ ChatGPT) to keep the same cart.
session.resume
Redeem the token. Returns the cardholder's open cart snapshot.
payment.*agentic payment + Mastercard ACP
payment.authorize
Mint a scoped JWT bound to (cardholder, agent, amount limit, intent hash, expiry). Pass it as payment_token to order/cart commit tools.
payment.charge
Submit charge. provider="hex" (default; needs token_id + cryptogram_wire) or provider="agenzo" (needs pm_id; fetches network token).
payment.refund
Refund a prior order. amount_cents=0 = full. Logs into the unified audit ledger.
payment.audit
Read-only tail of the actor chain (human → consumer_agent → token_issuer → hex_agent → mastercard → acquirer). Filter by correlation_id.
identity.*bearer issuance
identity.issue
Mint an Authorization Bearer JWT for a new agent host. Use this once per host; subsequent tool calls send the token in headers.

Conventions

Naming

  • Dotted: namespace.verb.
  • Snake-case names (search_merchants, place_order, …) are kept as aliases for back-compat. New agents should use the dotted form.

Identity

  • Bearer JWT in Authorization header is preferred.
  • agent_id / cardholder_id args on tools are a fallback for stdio. Ignored when the header is present.

Idempotency

  • Money-moving tools accept idempotency_key. Same key on retry returns the original order without re-charging.
  • quote_id auto-derives "q:<quote_id>" as the key.

SKU validation

  • items[*].sku is a closed enum derived from the live menu.
  • Bad SKUs are rejected at the JSON-Schema layer — never reach the handler.

Aliases

Legacy nameCanonical
search_merchantsmerchant.search
get_menumenu.get
place_orderorder.place
list_recent_ordersorder.list
payment.agenzo_chargepayment.charge(provider="agenzo")