On the internet, no one knows you're three raccoons in a trenchcoat.
Three raccoons. One trenchcoat. Unlimited Uber Eats.
Trenchcoat is an MCP tool server + browser automation that lets AI agents order food, buy things, deliver them, and coordinate with people — on behalf of their human.
An AI agent can:
- Order food from UberEats, DoorDash, or any delivery platform via browser automation
- Pay for things with virtual Visa cards (Laso Finance) or saved payment methods
- Deliver anything via Uber Direct courier
- Call people with AI voice calls (StablePhone)
- Send emails (StableEmail)
- Find places via Google Maps geocoding and search
- Send/receive SMS via Twilio
Human: "Order me a bacon egg and cheese"
│
▼
Three Raccoons in a Trenchcoat (any AI agent)
│
├── MCP Server (31 tools) ← API-based actions
│ ├── pay (Laso virtual cards, Venmo, PayPal)
│ ├── browse (Browser Use cloud automation)
│ ├── deliver (Uber Direct courier)
│ ├── call (StablePhone AI voice calls)
│ ├── email (StableEmail)
│ ├── maps (Google Maps geocoding/search)
│ ├── sms (Twilio + sms4sats)
│ └── profile (encrypted user profile)
│
└── Playwright (local browser) ← For sites that block bots
└── Human logs in → Agent takes over → Places order
git clone https://github.com/Keeeeeeeks/tempohack.git
cd tempohack
npm install
npx playwright install chromiumcp .env.example .env
# Fill in your credentials (see Environment Variables below)node -e "console.log(require('crypto').randomBytes(32).toString('hex'))"
# Paste the output as PROFILE_ENCRYPTION_KEY in .env# Install Tempo CLI
curl -fsSL https://tempo.xyz/install | bash
# Log in (requires browser/passkey)
tempo wallet login
# Check balance
tempo wallet -t whoamiAdd to your agent's MCP config:
{
"mcpServers": {
"tempohack": {
"command": "npx",
"args": ["tsx", "src/index.ts"],
"cwd": "/path/to/tempohack",
"env": {
"PROFILE_ENCRYPTION_KEY": "your-key-here"
}
}
}
}Most food delivery platforms (UberEats, DoorDash, Grubhub, Seamless) do not expose public ordering APIs. The Uber Eats API is merchant-side only (for restaurants managing their store), not consumer-side. DoorDash, Grubhub — same story. There is no POST /orders endpoint for placing food orders as a customer.
This means the only way for an agent to order food is to drive a real browser, just like a human would.
We tried three browser approaches. Only one works:
| Approach | Result |
|---|---|
| Browser Use (cloud, via Tempo/MPP) | Blocked by Cloudflare/Arkose CAPTCHAs on UberEats and DoorDash. Cloud browser fingerprints are detected. |
| Browserbase (cloud, stealth browsers) | Same problem — major delivery platforms actively detect and block headless/cloud browsers. |
| Local Playwright (your machine, real Chrome) | Works. Launches a real Chrome window the human can see and interact with. Uses Chrome DevTools Protocol (CDP) on port 9222 for agent control. |
Local Playwright works because:
- It runs a real Chrome binary on the user's machine — same fingerprint as normal browsing
- The human logs in manually — handles 2FA, CAPTCHAs, and account verification
- The agent connects via CDP after login — takes over an already-authenticated session
- Session cookies persist in a local profile directory (
/tmp/uber-profile)
This is the core pattern for ordering from any site that doesn't have an API:
1. Agent launches visible Chrome → Human can see the browser
2. Human logs in → Handles 2FA, CAPTCHAs, bot detection
3. Human says "I'm logged in" → Agent connects via CDP port 9222
4. Agent takes over → Searches, selects, customizes, checks out
5. Agent confirms with human → "BEC from Brooklyn Bread, $11.70, 30 min. Place it?"
6. Human approves → Agent clicks Place Order
Things an agent cannot do on sites without ordering APIs:
- Log in — 2FA, CAPTCHAs, and phone verification require a human
- Create accounts — Same auth wall problem
- Bypass bot detection — Cloud browsers get fingerprinted and blocked
- Operate without a visible browser — Headless mode gets detected; the human needs to see and potentially interact with the browser
- Handle payment 3D Secure challenges — Some card transactions trigger additional verification
- Guarantee speed — DOM structures change, elements load asynchronously, modals pop up unexpectedly
Things an agent can do once the human is logged in:
- Search for restaurants and food items
- Navigate menus and extract item data from the DOM
- Select items, customize orders, add to cart
- Set delivery address and preferences
- Review totals and place orders
- Track order status
See AGENT_INSTRUCTIONS.md for the full step-by-step flow that agents should follow. The key principles:
- Always present choices — don't silently pick restaurants or menu items
- Check distance — use Maps to verify the restaurant is near the human
- Ask about customizations in plain English — "toasted? what bread? extras?"
- Batch Playwright actions — do multiple steps per script, don't reconnect every time
- The whole flow should take 2-3 minutes, not 15
# From the project root:
npx tsx <<'EOF'
import { chromium } from 'playwright';
const context = await chromium.launchPersistentContext('/tmp/uber-profile', {
headless: false,
channel: 'chrome',
viewport: { width: 1400, height: 900 },
args: ['--remote-debugging-port=9222']
});
const page = context.pages()[0] || await context.newPage();
await page.goto('https://www.ubereats.com');
console.log('Browser open — log in, then tell your agent to take over');
await new Promise(r => setTimeout(r, 1800000)); // 30 min keepalive
EOFimport { chromium } from 'playwright';
const browser = await chromium.connectOverCDP('http://127.0.0.1:9222');
const page = browser.contexts()[0].pages()[0];
// Agent can now control the page| Variable | Required | Description |
|---|---|---|
PROFILE_ENCRYPTION_KEY |
Yes | 32-byte hex string for AES-256-GCM encrypted profile storage |
TWILIO_ACCOUNT_SID |
For SMS | Twilio Account SID |
TWILIO_AUTH_TOKEN |
For SMS | Twilio Auth Token |
TWILIO_PHONE_NUMBER |
For SMS | Your Twilio phone number (local, not toll-free) |
UBER_DIRECT_CLIENT_ID |
For delivery | Uber Direct OAuth client ID |
UBER_DIRECT_CLIENT_SECRET |
For delivery | Uber Direct OAuth client secret |
UBER_DIRECT_CUSTOMER_ID |
For delivery | Uber Direct customer/org ID |
SMS4SATS_API_KEY |
For disposable numbers | sms4sats.com API key (Lightning-funded) |
No env vars needed for Tempo-backed services — Maps, Email, Phone Calls, Browser Use, Pay, and image generation all work through the Tempo CLI which is authenticated separately.
pay_create_card— Create virtual Visa ($5-$1000)pay_card_status— Poll until card is readypay_balance— Check wallet balancepay_venmo— Send money via Venmopay_paypal— Send money via PayPal
browse_website— AI browser automation (cloud browser)browse_status— Check task statusbrowse_result— Get task outputbrowse_stop— Stop a running task
maps_geocode— Address to lat/lngmaps_places— Search for restaurants, stores, etc.maps_directions— Get directions + distance
send_email— Send email ($0.02)
call_phone— AI voice call ($0.54)call_status— Get transcript + summarylookup_imessage— Check iMessage availability
sms_send— Send SMS via Twiliosms_inbox— Read inbound SMSsms_list— List sent messagessms_buy_number— Buy a phone numbersms_list_numbers— List your numberssms_disposable_receive— Disposable anonymous number (sms4sats)sms_disposable_status— Poll for received codesms_disposable_cancel— Cancel ordersms_disposable_services— List available services
profile_set— Save name, phone, address, delivery prefsprofile_get— Read saved profile
deliver_quote— Get delivery quotedeliver_create— Dispatch courierdeliver_status— Track deliverydeliver_cancel— Cancel delivery
src/
├── index.ts # MCP server entrypoint (31 tools)
├── tools/
│ ├── pay.ts # Laso Finance virtual cards
│ ├── browse.ts # Browser Use cloud automation
│ ├── maps.ts # Google Maps geocoding/search
│ ├── email.ts # StableEmail
│ ├── call.ts # StablePhone AI voice calls
│ ├── sms.ts # Twilio + sms4sats SMS
│ ├── profile.ts # Encrypted user profile
│ └── deliver.ts # Uber Direct courier
├── lib/
│ ├── tempo.ts # Shared Tempo CLI wrapper
│ ├── crypto.ts # AES-256-GCM encrypt/decrypt
│ └── types.ts # TypeScript interfaces
└── webhook/ # (Phase 2) Uber Direct webhooks
stable-sms/ # StableSMS MPP service
├── src/
│ ├── index.ts # Express + mppx payment middleware
│ ├── twilio.ts # Twilio API client
│ └── sms4sats.ts # sms4sats API client
- No food delivery platform has a consumer ordering API. UberEats, DoorDash, Grubhub — all merchant-side only. Browser automation is the only path.
- Cloud browsers get CAPTCHA'd. UberEats and DoorDash detect Browser Use / Browserbase. Local Playwright with a real Chrome binary is the only thing that works.
- The auth handoff pattern is the killer workflow. Human logs in (handles 2FA/CAPTCHA) → Agent takes over via CDP. This generalizes to any authenticated web app.
- Every food delivery platform requires phone-verified accounts. No way around it today without a human in the loop for initial auth.
- Agents should be conversational, not autonomous. Present 3-5 options at every decision point. Ask about customizations in plain English. Confirm before placing orders.
- Check distance before presenting restaurants. Use Maps to avoid suggesting places that are far away.
- Extract data from the DOM, not screenshots.
page.evaluate()is 10x faster than screenshot → image analysis loops.
- Tempo/MPP services work instantly. Maps, Email, Phone, Pay all work out of the box with just a funded Tempo wallet. No API keys needed.
- Toll-free Twilio numbers can't send SMS on trial. Buy a local number, or upgrade to paid.
- Email-to-SMS gateways are unreliable. Carriers silently drop emails from unknown senders.
