Skip to main content
Glama
Uber Eats MCP Server

Uber Eats MCP Server

Claude, I’m hungry. 🍜

Order food from Uber Eats through natural language in Cursor or Claude Code — with an assistant that can browse menus, prep checkout, and (when you say so) place the order.

This project is an MCP server (Model Context Protocol): a small program your AI client starts over stdio so it can call tools like uber_eats_search and uber_eats_checkout_preview.
It is not a Cursor extension / VS Code plugin.

Under the hood: Uber web JSON APIs for search, menus, cart (add/remove via addItemsToDraftOrderV2 / removeItemsFromDraftOrderV2), checkout, and orders. Playwright is used for login, optional address picker UI, and place order fallback when API submit is unavailable or fails.


What you can do

  • Browse & decide fast

    • Search and browse nearby stores

    • Pull full menus with categories and item prices

    • Get item detail payloads (including customization metadata where available)

  • Cart & checkout prep

    • View cart via API (draft order + carts view)

    • Checkout preview with totals, fees, tip options, and delivery address

    • List eligible payment methods (when cart is non-empty)

    • Set checkout tip / select payment / apply promo / view savings

  • Orders

    • Track active orders (and past orders)

    • “Reorder helper” that resolves the store + previous items (then add with uber_eats_add_to_cart API)

  • Reverse-engineering mode

    • Run an API discovery browser that logs full request/response bodies to ~/.ubereats-api-log.jsonl


Related MCP server: @striderlabs/mcp-grubhub

Quick start (after git clone)

From inside uber-eats-mcp/ (this folder):

macOS / Linux

chmod +x scripts/setup.sh
./scripts/setup.sh

Windows (PowerShell)

powershell -ExecutionPolicy Bypass -File scripts\setup.ps1

Manual (same as the scripts)

uv sync
uv run playwright install chromium

The setup script prints a ready-to-paste JSON block with the correct path to this clone.


Connect Cursor

  1. Open Cursor → Settings → MCP (or edit the MCP config file your Cursor version uses).

  2. Merge the uber-eats entry into your existing mcpServers object (do not delete other servers).

  3. Restart Cursor or reload MCP.

If you prefer a project-local config, add .cursor/mcp.json in a project and paste the same mcpServers snippet.

Example shape (use the exact output from ./scripts/setup.sh so paths match your machine):

{
  "mcpServers": {
    "uber-eats": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/uber-eats-mcp", "uber-eats-mcp"]
    }
  }
}

Requires uv on your PATH: install uv.

Optional: “I’m hungry” Cursor rule

This repo includes .cursor/rules/uber-eats-hungry.mdc, which nudges the agent to call the Uber Eats tools when you sound hungry or want to order.

  • It is not part of the pip / wheel install — pyproject.toml only packages the Python server (server.py, api.py, …). Cloning the repo (or copying the file) is what brings the rule in.

  • For Cursor to load it, open uber-eats-mcp as the project root, or copy uber-eats-hungry.mdc into your own app’s .cursor/rules/.


Connect Claude Code

Add an .mcp.json at the root of the project you open in Claude Code (or use the global location your version documents). Use the same mcpServers JSON as above.


Typical flow (what the assistant should do)

  1. uber_eats_login

  2. uber_eats_get_preferences (optional personalization)

  3. uber_eats_get_address (confirm delivery address)

  4. uber_eats_search or uber_eats_nearby_restaurants

  5. uber_eats_restaurant_menu → decide items

  6. If needed: uber_eats_menu_item_detail / uber_eats_get_item_options

  7. uber_eats_add_to_cart (API — requires restaurant_url)

  8. uber_eats_view_cart

  9. uber_eats_checkout_preview

  10. Optional: uber_eats_list_payment_methods, uber_eats_set_checkout_payment, uber_eats_set_checkout_tip, uber_eats_apply_promo

  11. Only after explicit confirmation: uber_eats_place_order (API submit first, browser fallback if needed)


Run without MCP (debug)

uv run uber-eats-mcp

or

uv run python server.py

Environment (optional)

Variable

Meaning

UBEREATS_WEB_LOCALE

Country-language path for the website (login, address UI, discovery). Default cl-en (Chile, English), matching https://www.ubereats.com/cl-en. Set to us-en, mx-en, etc. for other regions, or empty to open https://www.ubereats.com/ only.

UBEREATS_QUIET

If 1 / true, hides the MCP startup banner on stderr.

UBEREATS_LOGIN_TRACE

Default on: each uber_eats_login clears then appends JSON lines to ~/.ubereats-mcp-login-trace.jsonl (no cookie values). In another terminal: tail -f ~/.ubereats-mcp-login-trace.jsonl. Set to 0 to disable. After a successful save, look for storage_audit_after_save: session_file_exists, positive session_cookie_entries, session_includes_sid_cookie, config_file_exists, config_has_sid_field — that pattern means disk storage looks healthy.

UBEREATS_DISCOVERY_LOG

Path to the browser discovery JSONL (full API request/response bodies). Default ~/.ubereats-api-log.jsonl. Set to e.g. …/uber-eats-mcp/discovery-api-log.jsonl so logs stay in this repo; scripts/run_discovery_interactive.py sets that automatically. Cursor MCP: add the same path under env for uber_eats_discover_apis.

Headed browser (login, address, discovery): only one flow runs at a time. If the assistant triggers uber_eats_login twice in parallel, or login runs while another tool opens the same browser, Playwright can error with page or browser has been closed—run one login and wait for it to finish.


What gets stored locally

Session and preferences are under your home directory (e.g. ~/.ubereats-session.json, ~/.ubereats-preferences.json). Do not commit those.

If login fails mid-way, you may see ~/.ubereats-session.json.prelogin.bak (and a matching .ubereats-config.json.prelogin.bak). A successful retry restores them automatically; if *.prelogin.bak exists but the main files do not, you can recover manually: copy each *.prelogin.bak over the non-.bak filename (then remove the .bak files if you like).


Prerequisites

  • Python ≥ 3.12

  • uv (recommended) or another way to install from pyproject.toml

  • Chromium via Playwright (playwright install chromium — included in the setup scripts)


More tools

See the tool list in Cursor/Claude Code after connecting. The implementation lives in server.py.


This project is unofficial and not affiliated with, endorsed by, or sponsored by Uber Technologies, Inc. in any way. Uber Eats and the Uber logo are trademarks of Uber Technologies, Inc.

  • Reverse-engineered APIs. This tool interacts with Uber Eats through undocumented internal APIs captured from browser network traffic. These APIs are not publicly supported and may change or break without notice.

  • Terms of Service. Automating interactions with Uber Eats may violate their Terms of Service. You are solely responsible for ensuring your use complies with Uber's terms. The authors take no responsibility for account suspensions, bans, or any other consequences arising from use of this tool.

  • No warranty. This software is provided as-is. Orders placed through this tool are your responsibility — always verify your order, delivery address, and payment method before confirming.

  • Use responsibly. Do not use this tool for bulk ordering, scraping, or any activity that places undue load on Uber's infrastructure.

Available Tools

34 tools
uber_eats_add_favoriteB
Save a restaurant or menu item as a favorite.

Args:
    kind: 'restaurants' or 'items'
    name: Name of the restaurant or item
    uuid: Restaurant UUID (for restaurants)
    url: Restaurant URL (for restaurants)
    restaurant: Which restaurant this item is from (for items)

Inputs: kind (required), name (required), url, uuid, +1 more. Returns: result

uber_eats_add_to_cartA
Add a line via addItemsToDraftOrderV2 + getMenuItemV1 (same stack for restaurants and grocery).

Best: pass store_uuid + menu_item_uuid (required). The server loads getStoreV1 and resolves the
real section_uuid / subsection_uuid from the menu—so wrong search data (e.g. section_uuid =
store_uuid) is fixed automatically when the SKU exists in the menu.

Optional: section_uuid, subsection_uuid, item_name from uber_eats_search items[] or restaurant_menu.

Fallback: restaurant_url + item_name (fuzzy match on full menu; more error-prone).

If the item has required customizations, call uber_eats_get_item_options first.

Args:
    item_name: Display / fuzzy name (optional if UUID path fills title from getMenuItemV1)
    quantity: How many to add (default 1)
    restaurant_url: Store URL or slug (legacy path)
    store_uuid: Merchant UUID (from search or menu payload)
    section_uuid: Catalog section UUID (never the same as store_uuid; optional if resolvable from menu)
    subsection_uuid: Submenu UUID (often empty; server retries with menu_item_uuid if needed)
    menu_item_uuid: SKU / catalog item UUID

Inputs: quantity, item_name, store_uuid, section_uuid, +3 more. Returns: result

uber_eats_apply_promoB
Apply a promo code (e.g. from email or offers). May succeed or return an error
if the code is invalid or expired.

Args:
    code: Promotion code string

Inputs: code (required). Returns: result

uber_eats_build_taste_profileA

Analyze past order history and build/update the user's taste profile. Identifies cuisine preferences, favorite restaurants, and ordering patterns. Call this periodically or when the user wants updated recommendations.

Inputs: no named parameters. Returns: result

uber_eats_checkout_previewA
Preview the order with full price breakdown. Always call this before
place_order and show the summary to the user for confirmation.
Does NOT place the order.

After showing the preview, you MUST:
1. Show a clear summary to the user (items, fees, total, address, payment)
2. Ask which payment method to use
3. Ask how much tip to add
4. Show the final total WITH tip
5. Ask for EXPLICIT confirmation before proceeding

Do NOT call place_order until the user explicitly confirms.

Inputs: no named parameters. Returns: result

uber_eats_checkout_savingsB

Fetch checkout savings / promo carousel data for the current draft order (API). Requires a non-empty cart.

Inputs: no named parameters. Returns: result

uber_eats_get_addressA
Current delivery address from saved session/config (no login browser).
Prefer this (with get_preferences) before uber_eats_login when starting a chat.

Inputs: no named parameters. Returns: result

uber_eats_get_item_optionsB
Get customization options for a menu item (sizes, extras, required choices).
Each group includes required, min_permitted, max_permitted, pick_one (when API provides them).
Call this before add_to_cart if the item has options/modifiers.

Args:
    item_name: Name of the menu item to inspect
    restaurant_url: Optional restaurant URL if not already on the page

Inputs: item_name (required), restaurant_url. Returns: result

uber_eats_get_preferencesA
Local preferences file (default address label, favorites, etc.). No browser.
Call first each session; then get_address—avoid opening login until an API
tool proves the Uber session is missing or expired.

Inputs: no named parameters. Returns: result

uber_eats_list_payment_methodsA
List eligible payment methods for the current cart (checkout API).
Requires items in the cart. Use after add_to_cart or when checkout fails
to show card / wallet options.

Inputs: no named parameters. Returns: result

uber_eats_list_profilesA
List Uber account profiles (Personal, Business, Family, etc.) and which is selected.
Use uber_eats_switch_profile to change the active profile before ordering.

Inputs: no named parameters. Returns: result

uber_eats_loginA
Open a visible browser window so the user can sign in to Uber Eats.
By default, if ~/.ubereats-session.json already works for Uber’s API, returns success
without opening a window (avoids wiping/restoring session by mistake).

Args:
    force: If true, always run the full login flow (clears saved session first). Use to
        switch accounts or recover from a bad cookie file.

Inputs: force. Returns: result

uber_eats_menu_item_detailA
Load one menu item with customization options (API). UUIDs come from uber_eats_restaurant_menu
item entries (section_uuid, subsection_uuid, uuid).

Args:
    store_uuid: Restaurant store UUID
    section_uuid: Section UUID from the menu item
    subsection_uuid: Subsection UUID from the menu item
    menu_item_uuid: Item UUID (catalog item)

Inputs: store_uuid (required), section_uuid (required), menu_item_uuid (required), subsection_uuid (required). Returns: result

uber_eats_nearby_restaurantsA
List nearby/popular restaurants from the Uber Eats home feed.
Good for browsing when the user doesn't have a specific craving.
Returns open/closed status for each restaurant.

Args:
    limit: Max restaurants to return (default 15)

Inputs: limit. Returns: result

uber_eats_place_orderA
Place the order (tries API checkoutOrdersByDraftOrdersV1 first, then browser click).
NEVER call this without explicit user confirmation.

REQUIRED before calling — ALL of these must be true:
1. checkout_preview was called and summary was shown to the user
2. User chose a payment method
3. User specified tip amount (or explicitly said no tip)
4. User saw the final total (including tip)
5. User explicitly said 'yes', 'confirm', 'place it', or similar

If ANY of these are missing, do NOT call this tool.
If the user said 'cancel', 'no', 'wait', or is uncertain, do NOT call this tool.

Inputs: no named parameters. Returns: result

uber_eats_recommendA
Get personalized food recommendations based on mood and social context.

If mood is empty, returns the available mood options for the user to pick from.

Mood options: tired, healthy, celebrating, stressed, adventurous, quick, craving
Social context options: alone, couple, family, friends (or custom contexts from preferences)

Args:
    mood: How the user is feeling (e.g. 'tired', 'celebrating', 'adventurous')
    social_context: Who they're eating with (e.g. 'alone', 'family', 'friends')
    craving: Free-text craving if mood is 'craving' (e.g. 'sushi', 'burgers')

Inputs: mood, craving, social_context. Returns: result

uber_eats_remove_from_cartB
Remove an item from the cart by name.

Args:
    item_name: Name of the item to remove

Inputs: item_name (required). Returns: result

uber_eats_reorderA
Look up a past order by UUID and return store UUID + previous line items so the user
can open the menu and add items again. Cart mutations still use the browser until
add-to-cart API is captured.

Args:
    order_uuid: Past order UUID from uber_eats_track_orders

Inputs: order_uuid (required). Returns: result

uber_eats_restaurant_menuA
Full menu for one store. OK for small restaurants; for supermarkets/groceries
the payload can be enormous (100k+ chars) and exceed the client's tool limit—
prefer uber_eats_search with the product name first, then item-level tools.

Args:
    restaurant_url: Full URL (https://www.ubereats.com/store/...) or restaurant slug

Inputs: restaurant_url (required). Returns: result

uber_eats_saved_addressesA
List all saved delivery addresses. Shows labeled addresses (home, work, etc.)
that the user has saved in their Uber Eats account.
Use uber_eats_switch_address to switch between them.

Inputs: no named parameters. Returns: result

uber_eats_search_historyB

Recent search queries from the user's Uber Eats search history (API).

Inputs: no named parameters. Returns: result

uber_eats_set_addressA
Change the delivery address. Always confirm with the user before calling this.
Opens a headed browser to set the new address via the address picker.

Args:
    address: New delivery address (street address or landmark)

Inputs: address (required). Returns: result

uber_eats_set_checkout_paymentA
Select payment method for checkout (API). Use payment UUIDs from
uber_eats_list_payment_methods. Optionally set use_credits to 'true' or 'false'.
Set set_as_default to 'true' to also PATCH the account default card (payments profilePatch).

Args:
    draft_order_uuid: Draft order UUID from checkout preview
    payment_profile_uuid: Payment profile UUID to charge
    use_credits: If 'true' or 'false', toggles Uber Cash/credits; empty leaves unchanged
    set_as_default: If 'true', persist as default payment on the selected Uber profile

Inputs: draft_order_uuid (required), payment_profile_uuid (required), use_credits, set_as_default. Returns: result

uber_eats_set_checkout_tipA
Set the delivery tip on the current draft order (API). Use tip values that match
Uber's buttons: typically 0, 5, 10, 15, or 20. Call uber_eats_checkout_preview
first and pass draft_order_uuid from the response.

Args:
    draft_order_uuid: Draft order UUID from checkout preview
    tip_percent: Tip percentage (e.g. 10 for 10%)

Inputs: tip_percent (required), draft_order_uuid (required). Returns: result

uber_eats_set_preferenceA
Update a user preference by dotted key path.

Examples:
  key="default_address", value="home"
  key="default_tip_percent", value="15"
  key="dietary.restrictions", value='["no peanuts", "lactose intolerant"]'
  key="budget.default_per_person", value="15000"
  key="budget.currency", value="CLP"
  key="language", value="es"

Args:
    key: Dotted path to the preference (e.g. 'dietary.avoid')
    value: The value to set (JSON string for lists/objects, plain string for scalars)

Inputs: key (required), value (required). Returns: result

uber_eats_suggest_cartB
Suggest what to order from a specific restaurant based on group size
and preferences. Analyzes the menu and recommends mains, sides, and drinks.

Args:
    restaurant_url: Restaurant URL or slug
    social_context: Who you're eating with (alone, couple, family, friends)

Inputs: restaurant_url (required), social_context. Returns: result

uber_eats_switch_addressB
Switch to a saved delivery address by its label (e.g. 'home', 'work').
Call uber_eats_saved_addresses first to see available addresses.

Args:
    label: The label or name of the saved address to switch to

Inputs: label (required). Returns: result

uber_eats_switch_profileA
Switch the active Uber profile by UUID from uber_eats_list_profiles.

Args:
    profile_uuid: Profile UUID to select

Inputs: profile_uuid (required). Returns: result

uber_eats_track_active_ordersA
In-progress / active orders only (delivery, preparing, etc.). Lighter than track_orders.

Inputs: no named parameters. Returns: result

uber_eats_track_ordersB

Track active and past orders. Shows order status, restaurant, items, and totals. Uses direct API for fast results.

Inputs: no named parameters. Returns: result

uber_eats_update_cart_quantityA
Change the quantity of a line already in the cart (same API the site uses for line updates).

Best: pass shopping_cart_item_uuid from uber_eats_view_cart items[].shopping_cart_item_uuid.
Otherwise match by item_name (partial match ok).

For large markets / grocery carts, set grocery_store=true if quantity updates fail without it.

Args:
    quantity: New quantity (1 or more)
    item_name: Line title to match if UUID not provided
    shopping_cart_item_uuid: From view_cart items[] (preferred)
    grocery_store: Hint for grocery / convenience store drafts

Inputs: quantity (required), item_name, grocery_store, shopping_cart_item_uuid. Returns: result

uber_eats_view_cartA
View the current cart: line titles, quantities, shopping_cart_item_uuid per line (for updates),
and draft_order_uuid. Call before checkout so the user can review; use UUIDs when changing qty.

Inputs: no named parameters. Returns: result

uber_eats_whoamiA
Get current user profile info and login status from saved session (no login browser).
Use with get_preferences/get_address before deciding whether uber_eats_login is needed.

Inputs: no named parameters. Returns: result

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.6/5.0

    Scored across 34 tools

    Disambiguation3/5

    Most tools are clearly separated by domain (address, cart, checkout, orders, search, preferences), but there are some ambiguous boundaries. uber_eats_get_address vs uber_eats_saved_addresses vs uber_eats_set_address overlap conceptually, and uber_eats_track_orders vs uber_eats_track_active_orders overlap heavily. Checkout tools (checkout_preview, checkout_savings, set_checkout_tip, set_checkout_payment) are distinct but close enough that an agent could misselect.

    Naming Consistency4/5

    All tools follow the uber_eats_ prefix with consistent snake_case. Most use verb_noun structure (search, track, view, remove, set). Minor inconsistencies: 'whoami' and 'recommend' and 'reorder' lack a noun object, and 'build_taste_profile' uses adjective rather than a direct action on a noun. Overall naming is quite predictable.

    Tool Count3/5

    34 tools is on the heavier side. The domain genuinely has many facets (search, browsing, cart, checkout, payment, orders, preferences, recommendations, profiles, favorites), so the count is defensible, but it borders on excessive and could clutter an agent's tool selection. Some tools like track_orders vs track_active_orders could be merged.

    Completeness4/5

    The coverage is thorough: search, browse, menu, items, cart CRUD, checkout flow, payment, promo, tips, orders tracking, reordering, profiles, preferences, favorites, and recommendations. Minor gaps include lack of explicit remove-payment-method or a dedicated order-cancel tool, and reorder doesn't fully perform the action (only surface items for re-add). Overall the lifecycle from search through ordering to tracking is well covered.

    Related MCP Connectors

    Related MCP Servers