An MCP App built with Reboot that demonstrates a small food-ordering flow driven from inside an MCP client. The AI calls tools to start an order, browse the menu, and add or remove items; humans see two embedded React UIs — a menu grid and a cart — rendered alongside the conversation.
User— per-user entry point. Auto-constructed for each authenticated chat user; exposesstart_order, which atomically creates a freshFoodOrder(with the pre-populated menu) and returns its ID.FoodOrder— one ordering session. Holds amenu(the list of items the AI can offer) and acart(the items the user has added so far, with quantities). The cart's running total is recomputed from the menu on read, so item prices stay in sync if the menu is ever updated.
The user-facing flow is:
- The AI calls
User.start_orderand gets back an order ID. - It calls
FoodOrder.show_menuto open the menu UI in the chat, where the user can browse items. - As the conversation continues, the AI calls
add_to_cart/remove_from_cart(or the user clicks "+ Add" buttons in the menu UI), andshow_cartopens the cart UI to display the running total.
get_menu, get_cart, add_to_cart, and remove_from_cart
are exposed as MCP tools, so an MCP-aware AI client can
drive the order programmatically.
# Install Python dependencies and create the virtualenv.
uv sync
# Install web dependencies.
cd frontend && npm install && cd ..
# Generate API code (Python + React bindings).
uv run rbt generate
# Build the React UIs.
cd frontend && npm run build && cd ..Then run the app (each command in its own terminal, from the project directory):
# Terminal 1: start the Reboot backend, as https://chick-potle.localhost.
uv run rbt dev run
# Terminal 2: start the Vite dev server for Hot Module Replacement,
# as https://frontend-chick-potle.localhost.
cd frontend && npm run devBoth run under portless,
which gives them names instead of ports: npm run dev is
portless frontend-chick-potle vite, portless being a dev dependency, and
rbt dev run needs the portless CLI too: install it once with
npm install -g portless and start its proxy with
portless proxy start. (For plain ports instead, run
uv run rbt dev run --config=ports and cd frontend && npm run dev:ports,
and read http://localhost:9991 below.)
Then open https://chick-potle.localhost and follow the setup wizard to connect a chat host (such as Claude or ChatGPT) to the app.
State persists between restarts under the name chick-potle
(configured in .rbtrc). To wipe it:
uv run rbt dev expunge --application-name=chick-potleThe backend has an in-process test suite that exercises the
User and FoodOrder servicers via direct Reboot calls —
no MCP client, no browser, no external services.
uv sync
uv run pytestFrom the connected chat host, try these prompts to exercise each capability:
Start a new food order.— exercisesstart_order, which creates aFoodOrderfor this user and returns its ID.Show me the menu.— exercisesshow_menuand renders the menu UI in the chat.Add a Chicken Burrito and two Mexican Coca-Colas to my cart.— exercisesadd_to_cart(the AI looks up the matchingitem_indexfromget_menu).What's in my cart?— exercisesget_cartandshow_cart; the rendered UI lists each line item with the running total.Remove the Coca-Colas.— exercisesremove_from_cart.
chick-potle/
├── api/mcp_app_food/v1/food.py # State models + method declarations.
├── backend/
│ ├── api/ # Generated Python bindings.
│ └── src/
│ ├── main.py # Application entrypoint.
│ └── servicers/food.py # User and FoodOrder servicers.
└── frontend/
├── api/ # Generated React bindings.
└── mcp/
├── menu/ # Menu grid UI.
└── cart/ # Cart UI.