get_vip_pricing
Retrieve VIP pricing information for a venue, including minimum spend ranges, zone summaries, and table chart image URL, to help users understand bottle service costs and table reservation options.
Instructions
Get VIP pricing information for a venue. Returns honest weekday and weekend minimum spend ranges, zone summaries, table chart image URL, and booking affordance.
WHEN TO CALL: When a user asks about VIP tables, VIP pricing, bottle service costs, minimum spend, or table reservations at a specific venue.
WHAT TO DO AFTER:
Present pricing conversationally ("Weekday minimums start around ¥100K, weekends from ¥200K")
Show table chart URL as a layout reference only — do not infer availability from the image
If booking_supported is true and user is interested, offer to submit an inquiry via create_vip_booking_request
Do NOT suggest specific table codes unless the user asks
If busy_night is true, mention the event name and that demand may be higher on that night
When pricing_approximate is true, use hedging language ("around", "approximately") rather than stating exact figures
When venue_open is false, the venue is closed on that specific date but general pricing ranges for open nights are still included. Present the open nights and pricing to the user.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| venue_id | Yes | ||
| date | No |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| venue_id | Yes | ||
| venue_name | Yes | ||
| venue_open | Yes | ||
| venue_closed_message | Yes | ||
| pricing_configured | Yes | ||
| pricing_not_configured_message | Yes | ||
| weekday_min_spend | Yes | ||
| weekend_min_spend | Yes | ||
| currency | Yes | ||
| zones | Yes | ||
| layout_image_url | Yes | ||
| booking_supported | Yes | ||
| booking_note | Yes | ||
| generated_at | Yes | ||
| service_date | Yes | ||
| event_pricing_note | Yes | ||
| event_name | Yes | ||
| busy_night | Yes | ||
| pricing_approximate | Yes |
Implementation Reference
- src/services/vipPricing.ts:362-483 (handler)Main service function that computes VIP pricing for a venue. Validates venue_id, resolves venue/city context, determines service date, checks open/closed status, fetches VIP tables and day defaults, aggregates pricing by weekday/weekend and zone, and returns the full VipPricingResult.
export async function getVipPricing( supabase: SupabaseClient, input: GetVipPricingInput, ): Promise<VipPricingResult> { // 1. Validate UUID const venueId = ensureUuid(input.venue_id, "venue_id"); // 2. Resolve venue const venue = await resolveVenueForPricing(supabase, venueId); const venueName = venue.name; // 3. Resolve city context const city = await fetchPricingCityContext(supabase, venue.city_id); // 4. Determine service date (null when no date requested) let serviceDate: string | null = null; const dateInput = input.date?.trim().toLowerCase(); if (dateInput === "tonight") { serviceDate = getCurrentServiceDate(new Date(), city.timezone, city.cutoff); } else if (dateInput && /^\d{4}-\d{2}-\d{2}$/.test(dateInput)) { serviceDate = dateInput; } // When no date provided: serviceDate stays null — return general pricing only // 5. Run open-day check (only when a specific date was requested) let venueOpen: boolean | null = null; let venueClosedMessage: string | null = null; let eventName: string | null = null; if (serviceDate) { const { closedDates, eventByDate } = await resolvePricingClosedDates(supabase, venueId, [serviceDate], city); venueOpen = !closedDates.has(serviceDate); venueClosedMessage = venueOpen ? null : `${venueName || "This venue"} appears to be closed on ${serviceDate}.`; eventName = eventByDate.get(serviceDate) ?? null; } // 6. Fetch active vip_venue_tables const { data: tableData, error: tableError } = await supabase .from("vip_venue_tables") .select("id,table_code,table_name,metadata,zone,capacity_min,capacity_max") .eq("venue_id", venueId) .eq("is_active", true); if (tableError) { throw new NightlifeError("DB_QUERY_FAILED", "Failed to load VIP venue tables.", { cause: tableError.message, }); } const tables = (tableData || []) as VipVenueTableRow[]; // 7. Fetch ALL vip_table_day_defaults for venue const { data: dayDefaultData, error: dayDefaultError } = await supabase .from("vip_table_day_defaults") .select("vip_venue_table_id,day_of_week,min_spend,currency,note") .eq("venue_id", venueId); if (dayDefaultError) { throw new NightlifeError("DB_QUERY_FAILED", "Failed to load VIP table day defaults.", { cause: dayDefaultError.message, }); } const dayDefaults = (dayDefaultData || []) as VipTableDayDefaultRow[]; // 8. Check per-date overrides from vip_table_availability let eventPricingNote: string | null = null; const { data: dateOverrideData } = await supabase .from("vip_table_availability") .select("min_spend") .eq("venue_id", venueId) .eq("booking_date", serviceDate); const overrideRows = (dateOverrideData || []) as Array<{ min_spend: number | string | null }>; const hasOverridesWithPricing = overrideRows.some((r) => coerceMinSpend(r.min_spend) !== null); if (hasOverridesWithPricing) { eventPricingNote = `Special event pricing may apply on ${serviceDate} — actual minimums may differ from the general ranges shown.`; } // 9. Aggregate pricing const aggregated = aggregatePricing(tables, dayDefaults); // 10. Determine pricing_configured and pricing_approximate const venueDefaultMinSpend = coerceMinSpend(venue.vip_default_min_spend); const pricingConfigured = dayDefaults.length > 0 || venueDefaultMinSpend !== null; const pricingNotConfiguredMessage = pricingConfigured ? null : "VIP pricing information is not yet available for this venue."; const pricingApproximate = dayDefaults.length === 0 && venueDefaultMinSpend !== null; // 11. Extract layout_image_url const layoutImageUrl = tables.map((t) => extractLayoutImageUrl(t.metadata)).find(Boolean) || null; // 12. Determine booking fields const bookingSupported = venue.vip_booking_enabled === true; // 13. Return result const busyNight = eventName !== null; return { venue_id: venueId, venue_name: venueName, venue_open: venueOpen === null ? true : venueOpen, venue_closed_message: venueClosedMessage, pricing_configured: pricingConfigured, pricing_not_configured_message: pricingNotConfiguredMessage, weekday_min_spend: aggregated.weekday_min_spend, weekend_min_spend: aggregated.weekend_min_spend, currency: aggregated.currency, zones: aggregated.zones, layout_image_url: layoutImageUrl, booking_supported: bookingSupported, booking_note: null, generated_at: new Date().toISOString(), service_date: serviceDate, event_pricing_note: eventPricingNote, event_name: eventName, busy_night: busyNight, pricing_approximate: pricingApproximate, }; } - src/services/vipPricing.ts:22-25 (schema)Input type definition for the getVipPricing function: venue_id (UUID) and optional date (tonight or YYYY-MM-DD).
export type GetVipPricingInput = { venue_id: string; date?: string; // "tonight" | YYYY-MM-DD | undefined }; - src/types.ts:582-601 (schema)Return type (VipPricingResult) defining the shape of the pricing response including venue info, min spends, zones with summaries, booking support, and event/pricing metadata.
export interface VipPricingResult { venue_id: string; venue_name: string | null; venue_open: boolean; venue_closed_message: string | null; pricing_configured: boolean; pricing_not_configured_message: string | null; weekday_min_spend: number | null; weekend_min_spend: number | null; currency: string; zones: VipZonePricingSummary[]; layout_image_url: string | null; booking_supported: boolean; booking_note: string | null; generated_at: string; service_date: string | null; event_pricing_note: string | null; event_name: string | null; // name of event on requested date busy_night: boolean; // true when event exists on requested date pricing_approximate: boolean; // true when pricing from venue-level default (no day-defaults) - src/types.ts:573-579 (schema)VipZonePricingSummary interface defining per-zone pricing data including capacity range and min spends.
export interface VipZonePricingSummary { zone: string; capacity_min: number | null; capacity_max: number | null; weekday_min_spend: number | null; weekend_min_spend: number | null; currency: string; - src/tools/vipTables.ts:124-138 (registration)Registers the 'get_vip_pricing' tool on the McpServer with Zod input/output schemas, description, and a handler that calls getVipPricing from services.
export function registerVipPricingTool(server: McpServer, deps: ToolDeps): void { server.registerTool( "get_vip_pricing", { description: VIP_PRICING_DESCRIPTION, inputSchema: vipPricingInputSchema, outputSchema: vipPricingOutputSchema, }, async (args) => runTool( "get_vip_pricing", vipPricingOutputSchema, async () => getVipPricing(deps.supabase, args), ), ); }