get_vip_booking_status
Retrieve VIP booking status for a nightlife venue. Input your booking request ID and matching customer email or phone to get the current status.
Instructions
Fetch VIP booking status from the venue booking workflow. Requires booking request ID and matching customer email or phone.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| booking_request_id | Yes | ||
| customer_email | No | ||
| customer_phone | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| booking_request_id | Yes | ||
| status | Yes | ||
| last_updated_at | Yes | ||
| status_message | Yes | ||
| latest_note | Yes | ||
| history | Yes | ||
| deposit_status | Yes | ||
| deposit_amount_jpy | Yes | ||
| deposit_payment_url | Yes |
Implementation Reference
- src/services/vipBookings.ts:799-889 (handler)The actual handler function `getVipBookingStatus` that executes the tool logic. It validates the booking request ID and customer email/phone, fetches the booking from the DB, verifies ownership, loads status event history, loads deposit info, and returns the full status result.
export async function getVipBookingStatus( supabase: SupabaseClient, input: GetVipBookingStatusInput, ): Promise<VipBookingStatusResult> { const { bookingRequestId, customerEmail, customerPhone } = normalizeStatusLookupContacts(input); const { data: booking, error: bookingError } = await supabase .from("vip_booking_requests") .select("id,status,updated_at,status_message,customer_email,customer_phone") .eq("id", bookingRequestId) .maybeSingle<VipBookingLookupRow>(); if (bookingError) { throw new NightlifeError("DB_QUERY_FAILED", "Failed to fetch VIP booking request.", { cause: bookingError.message, }); } if (!booking) { throw new NightlifeError("BOOKING_REQUEST_NOT_FOUND", "VIP booking request not found."); } const emailMatches = !!customerEmail && booking.customer_email === customerEmail; const phoneMatches = !!customerPhone && booking.customer_phone === customerPhone; if (!emailMatches && !phoneMatches) { throw new NightlifeError("BOOKING_REQUEST_NOT_FOUND", "VIP booking request not found."); } const { data: events, error: eventsError } = await supabase .from("vip_booking_status_events") .select("to_status,note,created_at") .eq("booking_request_id", booking.id) .order("created_at", { ascending: true }) .limit(20); if (eventsError) { throw new NightlifeError("DB_QUERY_FAILED", "Failed to fetch VIP booking history.", { cause: eventsError.message, }); } const history = ((events || []) as VipStatusEventRow[]) .filter((row) => isVipStatus(row.to_status)) .map((row) => ({ status: row.to_status, at: row.created_at, note: row.note, })); const latestHistory = history[history.length - 1]; // Load deposit info let depositStatus: string | null = null; let depositAmountJpy: number | null = null; let depositPaymentUrl: string | null = null; const { data: depositRow } = await supabase .from("vip_booking_deposits") .select("status,amount_jpy,stripe_checkout_url") .eq("booking_request_id", booking.id) .maybeSingle(); if (depositRow) { depositStatus = depositRow.status as string; depositAmountJpy = depositRow.amount_jpy as number; depositPaymentUrl = depositRow.status === "pending" ? (depositRow.stripe_checkout_url as string | null) : null; } else { // Check booking's denormalized deposit_status (e.g., not_required) const { data: bookingDeposit } = await supabase .from("vip_booking_requests") .select("deposit_status") .eq("id", booking.id) .single(); if (bookingDeposit?.deposit_status) { depositStatus = bookingDeposit.deposit_status as string; } } return { booking_request_id: booking.id, status: booking.status, last_updated_at: booking.updated_at, status_message: booking.status_message, latest_note: latestHistory?.note || null, history, deposit_status: depositStatus, deposit_amount_jpy: depositAmountJpy, deposit_payment_url: depositPaymentUrl, }; } - src/tools/vipBookings.ts:47-63 (schema)Input schema (`vipBookingStatusInputSchema`) and output schema (`vipBookingStatusOutputSchema`) for the tool, defining validated fields including booking_request_id, customer_email, customer_phone, and the returned status/history/deposit fields.
export const vipBookingStatusInputSchema = { booking_request_id: z.string().min(1), customer_email: z.string().optional(), customer_phone: z.string().optional(), }; export const vipBookingStatusOutputSchema = z.object({ booking_request_id: z.string(), status: z.enum(["submitted", "in_review", "deposit_required", "confirmed", "rejected", "cancelled"]), last_updated_at: z.string(), status_message: z.string(), latest_note: z.string().nullable(), history: z.array(vipBookingHistorySchema), deposit_status: z.string().nullable(), deposit_amount_jpy: z.number().nullable(), deposit_payment_url: z.string().nullable(), }); - src/tools/vipBookings.ts:158-171 (registration)Tool registration on the MCP server via `server.registerTool('get_vip_booking_status', ...)`, with input/output schemas and a callback that invokes `getVipBookingStatus(deps.supabase, args)`.
server.registerTool( "get_vip_booking_status", { description: "Fetch VIP booking status from the venue booking workflow. Requires booking request ID and matching customer email or phone.", inputSchema: vipBookingStatusInputSchema, outputSchema: vipBookingStatusOutputSchema, }, async (args) => runTool( "get_vip_booking_status", vipBookingStatusOutputSchema, async () => getVipBookingStatus(deps.supabase, args), ), ); - src/types.ts:227-237 (schema)TypeScript interface `VipBookingStatusResult` defining the return type of the handler, including booking_request_id, status, last_updated_at, status_message, latest_note, history, and deposit fields.
export interface VipBookingStatusResult { booking_request_id: string; status: VipBookingStatus; last_updated_at: string; status_message: string; latest_note: string | null; history: VipBookingStatusHistoryEntry[]; deposit_status: string | null; deposit_amount_jpy: number | null; deposit_payment_url: string | null; } - src/services/vipBookings.ts:656-677 (helper)Helper function `normalizeStatusLookupContacts` that validates and normalizes the booking request input: ensures UUID format for booking_request_id and requires at least one of customer_email or customer_phone.
function normalizeStatusLookupContacts(input: GetVipBookingStatusInput): { bookingRequestId: string; customerEmail: string | null; customerPhone: string | null; } { const bookingRequestId = ensureUuid(input.booking_request_id, "booking_request_id"); const emailRaw = String(input.customer_email || "").trim(); const phoneRaw = String(input.customer_phone || "").trim(); if (!emailRaw && !phoneRaw) { throw new NightlifeError( "INVALID_BOOKING_REQUEST", "Either customer_email or customer_phone is required.", ); } return { bookingRequestId, customerEmail: emailRaw ? normalizeCustomerEmail(emailRaw) : null, customerPhone: phoneRaw ? normalizeCustomerPhone(phoneRaw) : null, }; }