Order UberEats and DoorDash in Canada through AI agents. Canuckeats is a Model Context Protocol (MCP) service that lets AI agents browse menus and place real food delivery orders across 89 Canadian cities — no human in the loop required.
Endpoint:
https://mcp.canuckeats.com/mcp
Registration:POST https://mcp.canuckeats.com/register— free, instant, no email confirmation
Protocol: MCP 2024-11-05 — Streamable HTTP
Coverage: 17,000+ restaurants · 89 cities · Canada only · UberEats + DoorDash
Canadian residents who want AI assistants to handle their food delivery face a gap: UberEats and DoorDash don't offer agent-accessible APIs. Canuckeats bridges that gap. An agent given a task like "order me sushi for dinner" can:
- Find open restaurants near the user's address in their city
- Browse full menus with prices and modifier options
- Get a precise cost breakdown before charging anything
- Place the order and confirm payment in a single tool call
- Track delivery status and report the ETA back to the user
Every order dispatches through real UberEats or DoorDash accounts — the same food, same drivers, same cities.
No waiting, no approval queue. Register your agent and start making calls in under 30 seconds:
POST https://mcp.canuckeats.com/register
Content-Type: application/json
{
"agent_name": "MyFoodAgent",
"email": "you@yourproject.com",
"description": "AI assistant that orders lunch for remote teams"
}Response:
{
"api_key": "your-api-key-shown-once",
"key_id": "uuid",
"scopes": ["catalog:read", "orders:write"],
"medusa_customer_id": "cus_...",
"mcp_endpoint": "https://mcp.canuckeats.com/mcp",
"docs": "https://github.com/canuckeats/MCP",
"message": "Registration successful. Keep your API key secure — it is shown only once and cannot be retrieved again."
}The key is shown once. Save it immediately. If you lose it, register again with the same email — duplicate email is rejected, so use a unique email per key.
Registration limits: Up to 5 registrations per IP per 24 hours. One key per email address. Disposable email addresses are not accepted.
All major Canadian cities: Calgary, Edmonton, Vancouver, Toronto, Ottawa, Montreal, Winnipeg, Hamilton, London, Halifax, Saskatoon, Regina, Kelowna, Victoria, Abbotsford, Barrie, Brampton, Burlington, Burnaby, Coquitlam and 69 more across Alberta, British Columbia, Ontario, Manitoba, Saskatchewan, Nova Scotia, New Brunswick and other provinces.
Use list_cities to get the current full list with restaurant counts.
| Tool | Auth | Description |
|---|---|---|
list_cities |
API key | List all 89 cities with restaurant counts |
search_restaurants |
API key | Search by city, cuisine, name, or price range |
get_restaurant |
API key | Full restaurant details |
get_menu |
API key | Complete menu with sections, prices, and modifier options |
validate_order |
API key | Preview exact total — no charge, no order created |
create_order |
API key | Create order + Stripe PaymentIntent (no charge yet) |
confirm_payment |
API key | Charge card and dispatch order to platform |
get_order_status |
API key | Live status, tracking URL, and ETA |
import asyncio, json
from mcp import ClientSession
from mcp.client.streamable_http import streamablehttp_client
async def main():
async with streamablehttp_client(
"https://mcp.canuckeats.com/mcp",
headers={"Authorization": "Bearer YOUR_API_KEY"}
) as (read, write, _):
async with ClientSession(read, write) as session:
await session.initialize()
# Find restaurants
result = await session.call_tool("search_restaurants", {
"city_slug": "vancouver-bc",
"query": "sushi",
"limit": 5
})
restaurants = json.loads(result.content[0].text)
print(f"Found {restaurants['total']} sushi spots in Vancouver")
asyncio.run(main())import { Client } from "@modelcontextprotocol/sdk/client/index.js"
import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/streamableHttp.js"
const client = new Client({ name: "my-agent", version: "1.0" }, { capabilities: {} })
await client.connect(new StreamableHTTPClientTransport(
new URL("https://mcp.canuckeats.com/mcp"),
{ requestInit: { headers: { Authorization: "Bearer YOUR_API_KEY" } } }
))
const result = await client.callTool({ name: "list_cities", arguments: {} })
const cities = JSON.parse(result.content[0].text)
console.log(`${cities.length} cities available`)Add to your Claude Desktop MCP config (claude_desktop_config.json):
{
"mcpServers": {
"canuckeats": {
"type": "streamable-http",
"url": "https://mcp.canuckeats.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_API_KEY"
}
}
}
}Then ask Claude: "Order me a pepperoni pizza from anywhere in Calgary to 400 4 Ave SW, Calgary AB T2P 0J4."
list_cities → get city slug (e.g. "calgary-ab")
↓
search_restaurants → get restaurant id
↓
get_menu → get menu_item_id + modifier options
↓
validate_order → confirm total (no charge)
↓
create_order → get order_id + stripe_payment_intent_id
↓
confirm_payment → charge pm_... and dispatch
↓
get_order_status (poll) → track until delivered
See docs/examples/order-flow.md for a narrated walkthrough with real request/response examples.
| Endpoint | Limit |
|---|---|
/register |
5 registrations per IP per 24 hours |
| All tools (general) | 60 requests / minute per key |
create_order, confirm_payment |
10 requests / minute per key |
Response headers X-RateLimit-Limit and X-RateLimit-Remaining are included on every MCP response.
- Canadian addresses only. Province must be a two-letter code:
AB,BC,ON,QC,MB,SK,NS,NB,NL,PE,NT,YT,NU. - Payment method:
confirm_paymentaccepts a Stripepm_*payment method ID. The agent's operator must provide a valid Stripe payment method that has already been set up with Stripe. - Order dispatch is automatic. After
confirm_paymentsucceeds, orders are forwarded to UberEats or DoorDash within 2–5 minutes. Useget_order_statusto track. - Delivery platform is chosen automatically based on which platform has that restaurant in its catalog.
source_idon menu items is used internally — you do not need to reference it directly. Just usemenu_item_id(the integeridfield) when callingcreate_order.- Modifiers are optional. If a menu item has required modifiers (e.g. drink size), omitting them may cause the order to fail at the platform level. Check
modifier_groups[].min_selectionsto know which are required. - Scheduled delivery is supported via the
scheduled_forISO 8601 field oncreate_order. Use ASAP delivery by omitting this field.
| Platform | Coverage |
|---|---|
| UberEats | All 89 cities |
| DoorDash | All 89 cities |
Orders are placed on whichever platform has the requested restaurant. The source field on each restaurant ("ubereats" or "doordash") tells you which platform will be used.
Alberta · British Columbia · Manitoba · New Brunswick · Newfoundland · Nova Scotia · Ontario · Prince Edward Island · Quebec · Saskatchewan
Use list_cities for the live list. Notable cities include:
Alberta: Calgary, Edmonton, Red Deer, Lethbridge, Airdrie, Medicine Hat, Grande Prairie, Fort McMurray
BC: Vancouver, Surrey, Burnaby, Richmond, Kelowna, Abbotsford, Victoria, Coquitlam, Langley
Ontario: Toronto, Ottawa, Hamilton, London, Brampton, Mississauga, Barrie, Windsor, Kitchener, Ajax, Aurora
Quebec: Montreal (selected areas)
Prairie & Atlantic: Saskatoon, Regina, Winnipeg, Halifax, Moncton, Fredericton
- Full tool schemas with TypeScript types
- Quick start guide with code samples
- End-to-end order walkthrough
- Machine-readable tools manifest
- Issues / questions: Open a GitHub issue in this repo
- API key lost: Re-register with a different email, or email hello@canuckeats.com
- Order issues: Email hello@canuckeats.com with your
order_id - Website: canuckeats.com