{"$schema":"https://static.modelcontextprotocol.io/schemas/mcp-server-card/v1.json","name":"ro.manubbq/ordering","title":"ManuBBQ Ordering","version":"1.0.0","description":"Read the ManuBBQ menu (Ploiești, Romania), place pickup/delivery orders that the human pays via a Stripe link, and cancel them while unpaid.","websiteUrl":"https://manubbq.ro/developers","documentationUrl":"https://manubbq.ro/llms-full.txt","remotes":[{"type":"streamable-http","url":"https://manubbq.ro/mcp"}],"transport":{"type":"streamable-http","url":"https://manubbq.ro/mcp","stateless":true},"authentication":{"required":false,"schemes":[]},"capabilities":{"tools":{"listChanged":false}},"tools":[{"name":"get_menu","title":"Get ManuBBQ menu","description":"Step 1. Current ManuBBQ menu: item ids, prices in RON, Romanian names (English when available), allergens when published (null = unknown, ask the restaurant) and option groups with min/max selections.","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"title":"Get menu"}},{"name":"get_availability","title":"Opening hours and limits","description":"Step 2. Whether ManuBBQ accepts orders right now (isOpen, reason), weekly hours, last-order time (lastOrderTime), minimum order (minOrderRon, on the items subtotal before delivery fee), delivery radius and fee, and order limits. If closed, tell the human when it reopens. Minimum order: 50 RON, counted on the items subtotal (items + options, before delivery fee and discounts). quote_order reports minimumOrder {minOrderRon, met, shortfallRon} and orderable=false when it is not met; place_order then returns 422 below_minimum_order (details.shortfallRon), so ask the human to add items first. Last orders: 22:00 Europe/Bucharest time. From 22:00 until midnight get_availability shows isOpen=false, reason after_last_order, and quote_order/place_order return 409 ordering_closed (not retryable tonight).","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"title":"Get availability"}},{"name":"check_delivery","title":"Check delivery address","description":"Optional, for delivery. Checks whether a street address in Ploiești is inside the delivery area and returns the fee. If not deliverable, offer pickup.","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"title":"Check delivery"}},{"name":"quote_order","title":"Price a cart","description":"Step 3. Server-computed prices, delivery fee and total in RON. Creates nothing. If orderable is false the minimum order (minimumOrder.minOrderRon, items subtotal before delivery fee) is not met: ask the human to add items worth minimumOrder.shortfallRon. After the last-order time it returns ordering_closed (409). Show the lines and totalRon to the human and get an explicit yes before place_order.","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"title":"Quote order"}},{"name":"place_order","title":"Place confirmed order","description":"Step 4, ONLY after the human explicitly confirmed the quoted items and total. Creates an order awaiting card payment and returns paymentUrl (give it to the human; they pay on Stripe) and a secret statusToken. It can be cancelled with cancel_order only until it is paid. Use a fresh idempotency_key per order; reuse it only to retry the same order. Rejected with 422 below_minimum_order when the items subtotal is under the minimum, and 409 ordering_closed after the last-order time.","annotations":{"title":"Place order","readOnlyHint":false,"destructiveHint":false,"idempotentHint":true,"openWorldHint":true}},{"name":"get_order_status","title":"Order status","description":"Step 5. Status of an order you placed (needs its statusToken). Returns status, payment status, total and items only, no personal data. Poll at most every 30 seconds.","annotations":{"readOnlyHint":true,"destructiveHint":false,"idempotentHint":true,"openWorldHint":false,"title":"Get order status"}},{"name":"cancel_order","title":"Cancel unpaid order","description":"Cancels an order you placed (needs its statusToken), ONLY while it is unpaid and not yet sent to the kitchen; the payment link stops working. Only call it when the human asks to cancel. Paid orders return order_not_cancellable with the restaurant's phone. Safe to repeat.","annotations":{"title":"Cancel order","readOnlyHint":false,"destructiveHint":true,"idempotentHint":true,"openWorldHint":true}}],"instructions":"You order food from ManuBBQ (BBQ restaurant, Ploiești, Romania) for a human. Flow: get_menu -> get_availability -> (check_delivery for delivery) -> quote_order -> show the human the exact items and totalRon and get an explicit yes -> place_order (fresh idempotency key) -> give the human paymentUrl -> poll get_order_status at most every 30 s. If the human wants to cancel before paying: cancel_order. Never place an order the human has not confirmed. Use the human's real name, email and phone. The human pays on the Stripe page themselves; you never handle card data. The kitchen only receives the order after payment. Prices are in RON and computed by the server. Orders cannot be changed via the API. Only call cancel_order when the human asks; it works only while the order is unpaid, otherwise give the human the restaurant's phone from error.hint. On an error, read error.hint. If error.retryable is true, wait (Retry-After) and retry; otherwise fix the request or ask the human.","openapi":"https://manubbq.ro/api/v1/openapi.json"}