Resy × AI Agents: From Customer Journey to MCP Server

How Resy becomes an agent-ready platform
Kevin Middleton
The Experience

The Resy Customer Journey

AI agents are starting to book rides, order food, and complete tasks inside apps. This walkthrough explores how Resy's existing customer journey maps to an MCP server that gives those agents structured, safe access to dining reservations.

Journey Phases

1

Discovery

Cardholder discovers restaurants through editorial content, SEO-driven articles, and curated lists on Resy.

Content & SEO
2

Search

Filters by date, party size, cuisine, location, and availability.

Structured Query
3

Login

Frictionless mobile auth via SMS verification. Establishes identity and links to Amex cardholder profile.

Authentication
4

Booking

Select timeslot, hold reservation, confirm payment method, and finalize. If unavailable, join the waitlist.

Transaction
5

Post-Booking

Modify, cancel, or coordinate across services: calendar conflict checks, messaging, travel time estimates, and guest invitations.

Orchestration
Why This Matters

These five phases are the customer journey. The MCP (Model Context Protocol) server replicates each one, giving agents the same path a human takes: discover, search, authenticate, transact, manage, and orchestrate across services to deliver a concierge-level experience.

What Changes with AI Agents

👤

Human Journey (Today)

The cardholder navigates Resy's UI, taps through filters, reads reviews, and confirms their own booking. Every decision has a visual confirmation step.

🤖

Agent-Facilitated Journey (Tomorrow)

An AI agent traverses the same journey programmatically. It reads tool descriptions instead of UI labels, calls functions instead of tapping buttons, and needs guardrails instead of visual confirmations.

Key Design Principle

The MCP server mirrors the customer journey. Every tool maps to a journey phase, every parameter mirrors a UI input, and every access control replicates a visual gate (like the login screen or the "Confirm Booking" button).

Technical Foundation

API Architecture

Each journey phase is powered by specific API endpoints. These become the building blocks for MCP tool definitions.

Discovery
GET /articles/{id}
Parameters
id: string // Article identifier
Response
{ title, body, restaurants[], tags[] }
GET /articles
Parameters
category?: string location?: string
Response
{ articles: [{ id, title, summary }] }
GET /content
Parameters
type: "list" | "guide" | "featured" location?: string
Response
{ content: [{ title, items[], type }] }
Search
GET /cities/{city}/search
Parameters
city?: string // e.g. "new-york-ny" lat?: number // Latitude (use with lng) lng?: number // Longitude (use with lat) date: string // YYYY-MM-DD seats: number query?: string // e.g. "Pizza" activeView?: string // "list" | "map"
Response
{ restaurants: [{ id, name, cuisine, rating, price_range, available_slots[] }] }
GET /cities/{city}/venues/{slug}
Parameters
city: string // e.g. "new-york-ny" slug: string // e.g. "lartusi" date: string // YYYY-MM-DD seats: number
Response
{ name, description, cuisine, rating, photos[], reviews[], menu_url, available_timeslots: [{ id, time, type }] }
Authentication
POST /auth/verify/send
Parameters
phone: string // E.164 format
Response
{ sent: true, expires_in: 300 }
POST /auth/verify/confirm
Parameters
phone: string code: string // 6-digit SMS code
Response
{ token: "eyJhb...", user_id: "u_123", expires_at: "2026-04-15T..." }
Booking
GET /timeslots/{id}
Parameters
id: string // Timeslot identifier
Response
{ id, restaurant_id, time, type, deposit_required, cancellation_policy }
POST /reservations/hold
Parameters
timeslot_id: string hold_until: string // ISO timestamp
Response
{ hold_id: "h_456", expires_at: "...", status: "held" }
GET /profiles/{id}
Parameters
id: string // User profile ID
Response
{ name, email, phone, payment_methods: [{ id, last4, type }], dietary_preferences[] }
POST /payment/cards
Parameters
token: string // Payment token
Response
{ card_id, last4, brand, status }
POST /reservations
Parameters
restaurant_id: string timeslot_id: string party_size: number payment_method_id: string special_requests?: string
Response
{ reservation_id: "r_789", confirmation_code: "RESY-ABC123", status: "confirmed" }
POST /waitlist
Parameters
restaurant_id: string date: string // YYYY-MM-DD time_window?: { earliest, latest } party_size: number notify_via?: "push" | "sms" | "email"
Response
{ waitlist_id, position, estimated_notify_time }
DELETE /waitlist/{id}
Parameters
id: string // Waitlist entry identifier
Response
{ status: "removed" }
Post-Booking
PUT /reservations/{id}
Parameters
id: string party_size?: number timeslot_id?: string special_requests?: string
Response
{ reservation_id, status: "modified", updated_fields[] }
DELETE /reservations/{id}
Parameters
id: string // Reservation identifier
Response
{ status: "cancelled", cancellation_fee: null, refund_amount: 0.00 }
Why This Matters

Notice the hold pattern in the Booking section: the reservation flow uses a two-step commit. POST /reservations/hold creates a temporary lock, then POST /reservations finalizes. This pattern is critical for agentic experiences: it lets an AI agent secure a timeslot while the cardholder confirms, without risking a lost booking or an unauthorized charge.

The Protocol Layer

MCP Server Design

The Model Context Protocol turns Resy's APIs into tools that any AI agent can discover, understand, and invoke. Tool descriptions become "UX for machines."

Architecture Overview

MCP Server Flow

AI Agent
Gemini, Siri, Claude, etc.
Resy MCP Server
Tool definitions + auth
Resy Platform APIs
Existing endpoints

The MCP server is a translation layer: it wraps existing APIs with tool metadata that agents can reason about.

Why MCP, Not Just an API?

APIs are built for developers who read docs. MCP tools are built for AI agents that read descriptions. The tool's description, parameter names, and schema are the interface.

An agent doesn't browse Resy's API docs. It reads tool definitions at runtime and decides what to call based on the user's intent.

Tool descriptions are UX for machines. Write them like you're explaining the tool to a smart assistant who has never seen your product.

The Agentic Spectrum

Informational

Read-only access. Search restaurants, check availability, view details.

Assistive

Agent suggests + holds. Cardholder confirms the final action.

Fully Agentic

Agent books, modifies, cancels on cardholder's behalf autonomously.

Tool Definitions

search_restaurants

Read-Only
Tool Description (What the Agent Reads)
Search for available restaurants on Resy by location, date, seats, and optional keyword. Supports both city-based and proximity-based search. Returns a list of restaurants with available reservation times. Use this when a user wants to find somewhere to eat. Always ask for date and party size before calling. If the user says "near me" or shares a location, use lat/lng instead of city. Maps to resy.com/cities/{city}/search.
Input Schema
{ "type": "object", "properties": { "city": { "type": "string", "description": "City slug (e.g. new-york-ny, los-angeles-ca). Use this OR lat/lng." }, "lat": { "type": "number", "description": "Latitude for proximity search. Use with lng instead of city." }, "lng": { "type": "number", "description": "Longitude for proximity search. Use with lat instead of city." }, "date": { "type": "string", "description": "Date in YYYY-MM-DD format" }, "seats": { "type": "integer", "minimum": 1, "maximum": 20 }, "query": { "type": "string", "description": "Optional search keyword (e.g. Pizza, Sushi, Italian)" } }, "required": ["city", "date", "seats"] }

get_restaurant_details

Read-Only
Tool Description (What the Agent Reads)
Get detailed information about a specific restaurant including description, photos, reviews, menu link, and available timeslots for a given date and party size. Use this after search_restaurants when a user wants more info about a specific place. Maps to resy.com/cities/{city}/venues/{slug}.
Input Schema
{ "type": "object", "properties": { "city": { "type": "string", "description": "City slug (e.g. new-york-ny)" }, "venue_slug": { "type": "string", "description": "Restaurant URL slug (e.g. lartusi)" }, "date": { "type": "string", "description": "YYYY-MM-DD" }, "seats": { "type": "integer" } }, "required": ["city", "venue_slug", "date", "seats"] }

check_availability

Read-Only
Tool Description (What the Agent Reads)
Check real-time availability for a specific timeslot at a restaurant. Returns whether the slot is still open, any deposit requirements, and the cancellation policy. Call this before attempting to create a reservation to verify the slot hasn't been taken.
Input Schema
{ "type": "object", "properties": { "timeslot_id": { "type": "string", "description": "Timeslot ID from restaurant details" } }, "required": ["timeslot_id"] }

create_reservation

Action · Requires Auth
Tool Description (What the Agent Reads)
Create a reservation at a restaurant. This first places a temporary hold (e.g., 5 minutes, configurable per restaurant), then confirms if the cardholder approves. IMPORTANT: This action uses the cardholder's payment method and should only be called after explicit user confirmation. The hold pattern ensures no charge occurs without approval.
Input Schema
{ "type": "object", "properties": { "restaurant_id": { "type": "string" }, "timeslot_id": { "type": "string" }, "party_size": { "type": "integer" }, "payment_method_id": { "type": "string", "description": "From cardholder profile" }, "special_requests": { "type": "string" } }, "required": ["restaurant_id", "timeslot_id", "party_size", "payment_method_id"] }
How This Works in Practice

The agent can start a reservation, but it can't finish one alone. It places a temporary hold, then asks the cardholder to confirm. No confirmation, no booking. The cardholder always has the final say.

manage_reservation

Elevated · Cardholder Re-confirm
Tool Description (What the Agent Reads)
Modify or cancel an existing reservation. Supports changing party size, time, or cancelling entirely. Cancellations may incur fees depending on the restaurant's policy. Always confirm the action and any potential fees with the cardholder before proceeding.
Input Schema
{ "type": "object", "properties": { "reservation_id": { "type": "string" }, "action": { "type": "string", "enum": ["modify", "cancel"] }, "changes": { "type": "object", "properties": { "party_size": { "type": "integer" }, "timeslot_id": { "type": "string" } } } }, "required": ["reservation_id", "action"] }
Why This Matters

Cancelling a reservation at a premium restaurant can trigger fees of $500+. That's why changes and cancellations require the cardholder to re-confirm. The agent can suggest and prepare the action, but anything with financial consequences needs a human in the loop.

join_waitlist

Read-Only
Tool Description (What the Agent Reads)
Join the waitlist for a fully-booked restaurant. The cardholder will be notified when a table becomes available for their desired date, time window, and party size. No financial commitment is made. Use this when search_restaurants or check_availability shows no open slots and the cardholder still wants to try for that restaurant. This is a concierge-level feature. Proactively suggest it when a top pick is unavailable.
Input Schema
{ "type": "object", "properties": { "restaurant_id": { "type": "string" }, "date": { "type": "string", "description": "YYYY-MM-DD" }, "time_window": { "type": "object", "properties": { "earliest": { "type": "string", "description": "Earliest acceptable time (e.g. 19:00)" }, "latest": { "type": "string", "description": "Latest acceptable time (e.g. 21:30)" } } }, "party_size": { "type": "integer" }, "notify_via": { "type": "string", "enum": ["push", "sms", "email"], "description": "How to notify when a spot opens" } }, "required": ["restaurant_id", "date", "party_size"] }
The Concierge Play

"Get me into Carbone whenever something opens up." That's the whole prompt. The agent watches for cancellations, auto-holds the slot, and pings the cardholder to confirm. No commitment until they say yes.

export_to_calendar

Action · Cross-Server
Tool Description (What the Agent Reads)
Add a confirmed reservation to the cardholder's calendar. Before creating the event, check for scheduling conflicts within ±90 minutes of the reservation time. If conflicts exist, surface them to the cardholder and ask how to proceed before adding. Include restaurant name, address, party size, confirmation number, and cancellation policy in the event details. This tool coordinates with an external Calendar MCP server.
Input Schema
{ "type": "object", "properties": { "reservation_id": { "type": "string", "description": "ID of the confirmed reservation" }, "calendar_id": { "type": "string", "description": "Target calendar (default: primary)" }, "add_travel_time": { "type": "boolean", "description": "If true, estimate travel time from prior event location and add a buffer" }, "invite_guests": { "type": "array", "items": { "type": "string" }, "description": "Email addresses of dining companions to invite" } }, "required": ["reservation_id"] }
Multi-Server Orchestration

This is where MCP shines. The Resy server handles the reservation. The Calendar server handles scheduling. The agent orchestrates both, checking for conflicts, estimating travel time from a prior event's location, and sending invites to dining companions. No single server does it all; the agent directs them.

Trust & Compliance

Guardrails & Governance

The trust model for agent-initiated financial actions in a regulated environment. What gets exposed, what stays internal, and how we protect the cardholder.

Data Exposure Model

Data Element Expose to Partner Agents? Rationale
Restaurant name, cuisine, location Expose Public information needed for search and recommendation
Available timeslots Expose Core functionality; agent needs this to facilitate booking
Pricing / deposit amounts Expose Cardholder must know costs before committing
Cardholder name (first name only) Partial Personalization without full PII exposure
Payment method (last 4 digits) Partial Confirmation display only, never full card number
Cardholder calendar data Partial Agent sees "conflict at 7:30 PM" but never the event title, attendees, or details. Conflict checks happen server-side.
Full cardholder profile Internal Only PII stays server-side. Agent sees tokenized references.
Payment processing details Internal Only Handled entirely by Resy MCP server; agent never touches payment rails
Reservation history / frequency Internal Only Behavioral data stays internal to avoid profiling by third parties
Why This Matters

The MCP server acts as a data firewall. Partner AI agents get exactly what they need to facilitate the experience, and nothing more. The agent never sees a full card number, never accesses raw payment rails, and never gets behavioral history that could be used for competitive profiling.

Safety Patterns

🔒 Hold-Before-Commit Pattern

The reservation flow uses a two-phase commit: hold, then confirm. This is the key safety mechanism for agentic booking.

  • 1 Agent calls create_reservation → MCP server places a configurable hold (e.g., 5 minutes)
  • 2 Hold details returned to agent (restaurant, time, any deposit)
  • 3 Agent presents hold to cardholder for confirmation
  • 4 Cardholder confirms → hold converts to reservation
  • × If cardholder doesn't confirm within the hold window, it expires automatically

🔑 OAuth Token Scoping

Different agent interactions require different permission levels, controlled via OAuth scopes.

  • restaurants:read Search and view restaurants (any agent)
  • availability:read Check timeslot availability
  • reservations:read View existing reservations
  • reservations:write Create reservations (requires cardholder auth)
  • reservations:manage Modify/cancel (requires re-confirmation)
  • waitlist:write Join/leave waitlists (no financial commitment)
  • calendar:write Cross-server calendar access (delegated scope, agent sees conflict times but not event details)

🛡 The Trust Model

"You're authorizing actions on behalf of a cardholder through a third-party agent."

Three parties, three trust relationships:

  • Cardholder and Amex: Existing trust. Cardholder trusts Amex with payment.
  • Cardholder and Agent: New trust. User chose to use this AI assistant.
  • Amex and Agent: Partnership trust. MCP server defines what the agent can do.

⚖️ Financial Services Compliance

Additional considerations for a regulated financial institution operating in the agentic space.

  • Audit trail: Every agent-initiated action logged with agent ID, timestamp, and cardholder consent token
  • Rate limiting: Per-agent, per-cardholder action limits prevent runaway agents
  • Revocation: Cardholder can revoke agent access at any time via Amex app
  • Dispute path: Agent-initiated transactions follow same dispute flow as card-present
Design Principle

The MCP server should be paranoid by default. Start with the narrowest possible permissions, and expand only when the cardholder explicitly opts in. The same principle that governs card-not-present transactions.

Open Questions

Things I'd want to explore with the team:

Hold duration

Is the hold window configurable per restaurant, or platform-wide? High-demand spots might need shorter holds to avoid inventory lock-up.

Rate limiting

Per-agent limits, per-cardholder limits, or both? How do you prevent a misbehaving agent from burning through availability?

Agent identity

How does Amex know which AI assistant is making a request? Does each partner get a unique identity, and can you revoke one without affecting others?

Cardholder consent model

One-time blanket consent, or per-action? How granular should opt-in be before it becomes friction?

What's Next

Where This Goes

Start with read-only tools. Prove they work. Then let agents do more.

The Agentic Roadmap

Today

Informational

AI agents can search restaurants, check availability, and view details on behalf of the cardholder. No actions are taken. The agent is purely a research assistant for dining decisions.

Search restaurants by cuisine Check availability for a date View restaurant details and reviews List existing reservations
Next

Assistive

The agent can suggest options and place temporary holds, but the cardholder always confirms. The hold pattern is the safety mechanism: nothing commits without human approval. This is where we prove the trust model works.

Agent suggests 3 options Places hold on preferred choice Joins waitlists for unavailable picks Cardholder confirms in Amex app Calendar conflict check before booking Hold converts to reservation
Future

Fully Agentic

With established trust and proven safety patterns, AI agents can book, modify, and cancel reservations autonomously. The cardholder sets preferences and constraints ("Italian, under $50pp, near my hotel") and the agent handles the rest, including rebooking if plans change.

Autonomous booking within constraints Proactive rebooking on cancellation Calendar sync with travel time buffers Auto-waitlist when top picks are full Guest invites to dining companions Preference learning over time
Horizon

Agent-to-Agent Coordination

The Amex agent doesn't operate alone. It coordinates with airline agents, hotel agents, and restaurant agents to orchestrate complete travel experiences. "Book dinner near my hotel the night before my morning flight" becomes a multi-agent conversation.

Amex agent + airline agent Hotel concierge agent coordination Multi-restaurant itineraries Trip-aware dining suggestions Resy MCP + Calendar MCP + Maps MCP

The Strategic Insight

Whoever figures out the trust model for agent-initiated financial actions first wins the agentic finance space. Amex is uniquely positioned: you already have the cardholder trust, the merchant relationships, and now with Resy, the platform to prove it works.

Why Resy Is the Right Starting Point

Bounded Transaction Size

Restaurant reservations are low-to-medium stakes ($50-$500 deposits). Perfect for building trust in agent-initiated financial actions before expanding to higher-stakes domains like travel or shopping.

Clear Reversibility

Cancellation policies are well-defined and time-bound. If an agent makes a mistake, the blast radius is contained and the remedy path is clear.

High Intent Signal

When someone asks an AI to book a restaurant, the intent is unambiguous. Compare this to "buy me something nice": dining has structured inputs (date, time, party size) that reduce agent error.

Owned Platform

Amex owns Resy. You control the API surface, the data model, and the trust boundaries. No third-party dependency for the initial proof of concept.

The Bigger Picture

Resy is the proving ground. The patterns you build here (hold-before-commit, scoped OAuth for agents, cardholder re-confirmation for financial actions) become the template for agentic experiences across every Amex product: travel, shopping, financial planning. It all starts with "Book me a table for two on Friday."

Real Examples

How I Use AI & MCP

My AI Stack

💬 Telegram + Claude Code

Claude Code runs on my Mac mini with a Channels integration to Telegram. I message it tasks, it executes them against my repos, and replies with results. This is how I manage QuietFeed and other projects conversationally.

📱 Job Search Agent

Built an autonomous pipeline that scans LinkedIn twice daily, classifies roles using Claude Haiku and Gemini, and texts me matches. Runs at $0.06/day. Published a 4-part series on the build.

📰 QuietFeed

A passion project. An RSS reader built with AI. React + Supabase + Vercel. Claude Code handles feature development, bug fixes, and test coverage. quietfeed.com

🔌 Buffer MCP

Native MCP integration for social media scheduling. I tell Claude what to post, and it handles the rest through Buffer's MCP server.

Relevant Professional Experience

GridStrong.ai AI Copilot

Delivered an AI-powered compliance copilot that guided power plant owners through plant profiles, compliance workflows, and cross-standard tasks, reducing manual effort and error rates.

AI copilot that accelerated compliance workflows for power plant operators.

🏠 HVAC.com Conversational AI

Defined and drove development of an LLM-powered AI assistant that answers homeowner questions conversationally and drives users toward HVAC replacement and repair conversions.

Conversational AI that educates and connects homeowners to the sales team.

🔒 Sendoso Fraud Detection / 2FA

Increased platform security by implementing two-factor authentication and AI-driven fraud detection, reducing bot-driven attacks and strengthening customer trust.

AI-powered fraud detection and 2FA for eGift activation.

💼 Rocket Lawyer OAuth / OpenID Connect

Created and launched co-branded partner sites reaching 11.5M users, enabling OpenID Connect-based authentication, pricing, feature gating, and theming for enterprise partnerships.

OAuth and OpenID Connect across 11.5M users and enterprise partners.