submit_to_guest_list
Submit a guest list entry for an event or venue. Provide event ID or venue ID with service date, customer name, and email to receive a confirmation with door instructions and guest list benefits.
Instructions
Submit a guest list entry for an event or venue. Provide either event_id or venue_id + service_date. Returns confirmation with door instructions and guest list benefits if available.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| event_id | No | ||
| venue_id | No | ||
| service_date | No | ||
| customer_name | Yes | ||
| customer_email | Yes | ||
| customer_phone | No | ||
| messaging_channel | No | ||
| messaging_handle | No | ||
| language | No | en | |
| source | No | concierge |
Output Schema
| Name | Required | Description | Default |
|---|---|---|---|
| entry_id | Yes | ||
| status | Yes | ||
| event_name | Yes | ||
| event_date | Yes | ||
| message | Yes | ||
| guest_list_benefit | Yes | ||
| door_instructions | Yes |
Implementation Reference
- src/services/guestList.ts:272-401 (handler)The main handler function for the 'submit_to_guest_list' tool. Resolves event context, checks guest list availability, cutoff time, capacity, duplicates, then inserts a guest list entry into the database and returns a confirmation response.
export async function submitToGuestList( supabase: SupabaseClient, input: SubmitInput, ): Promise<SubmitOutput> { // 1. Resolve event context const ctx = await resolveEventContext( supabase, input.event_id, input.venue_id, input.service_date, ); // 2. Load guest list settings const settings = await loadGuestListSettings(supabase, ctx.event_day_id, ctx.venue_id); if (!settings || settings.enabled === false) { throw new NightlifeError( "GUEST_LIST_NOT_AVAILABLE", "Guest list is not available for this event", ); } // 3. Check cutoff time if (settings.cutoff_time && ctx.service_date) { const now = new Date(); const tokyoFormatter = new Intl.DateTimeFormat("en-US", { timeZone: "Asia/Tokyo", hour: "2-digit", minute: "2-digit", hourCycle: "h23", }); const nowParts = tokyoFormatter.formatToParts(now); const nowHour = Number(nowParts.find((p) => p.type === "hour")?.value ?? 0); const nowMinute = Number(nowParts.find((p) => p.type === "minute")?.value ?? 0); const nowMinutes = nowHour * 60 + nowMinute; const [cutoffH, cutoffM] = settings.cutoff_time.split(":").map(Number); const cutoffMinutes = cutoffH * 60 + cutoffM; // Only check cutoff if the service date is today const dateFormatter = new Intl.DateTimeFormat("en-CA", { timeZone: "Asia/Tokyo" }); const todayStr = dateFormatter.format(now); if (ctx.service_date === todayStr && nowMinutes >= cutoffMinutes) { return { entry_id: "", status: "closed", event_name: ctx.event_name, event_date: ctx.event_date, message: "Guest list has closed for tonight. Consider VIP table booking instead.", guest_list_benefit: null, door_instructions: null, }; } } // 4. Check capacity if (settings.capacity) { const currentCount = await countExistingEntries( supabase, ctx.event_day_id, ctx.venue_id, ctx.service_date, ); if (currentCount >= settings.capacity) { return { entry_id: "", status: "full", event_name: ctx.event_name, event_date: ctx.event_date, message: "Guest list is full for this event. Consider VIP table booking instead.", guest_list_benefit: null, door_instructions: null, }; } } // 5. Check duplicate const isDuplicate = await checkDuplicate( supabase, input.customer_email, ctx.event_day_id, ctx.venue_id, ctx.service_date, ); if (isDuplicate) { throw new NightlifeError( "GUEST_LIST_DUPLICATE", "This email is already on the guest list for this event", ); } // 6. Insert entry const insertData: Record<string, unknown> = { email: input.customer_email.toLowerCase(), name: input.customer_name, group_size: 1, language: input.language, source: input.source, }; if (input.customer_phone) insertData.messaging_handle = input.customer_phone; if (input.messaging_channel) insertData.messaging_channel = input.messaging_channel; if (input.messaging_handle) insertData.messaging_handle = input.messaging_handle; if (ctx.event_day_id) insertData.event_day_id = ctx.event_day_id; if (ctx.venue_id) insertData.venue_id = ctx.venue_id; if (ctx.service_date) insertData.service_date = ctx.service_date; const { data: entry, error } = await supabase .from("event_guest_list_entries") .insert(insertData) .select("id, created_at") .single(); if (error) { throw new NightlifeError("DB_QUERY_FAILED", `Failed to create guest list entry: ${error.message}`); } const message = settings.confirmation_message_en || "You're on the guest list! Show this confirmation at the door."; return { entry_id: entry.id, status: "confirmed", event_name: ctx.event_name, event_date: ctx.event_date, message, guest_list_benefit: settings.benefit_en ?? null, door_instructions: settings.door_instructions_en ?? null, }; } - src/tools/guestList.ts:15-26 (schema)Input schema for submit_to_guest_list. Accepts event_id or venue_id+service_date, plus customer_name, customer_email, and optional fields like phone, messaging, language, and source.
export const submitToGuestListInputSchema = { event_id: z.string().optional(), venue_id: z.string().optional(), service_date: z.string().optional(), customer_name: z.string().min(1), customer_email: z.string().min(1), customer_phone: z.string().optional(), messaging_channel: z.string().optional(), messaging_handle: z.string().optional(), language: z.string().default("en"), source: z.string().default("concierge"), }; - src/tools/guestList.ts:28-36 (schema)Output schema for submit_to_guest_list. Returns entry_id, status (confirmed/full/closed), event_name, event_date, message, guest_list_benefit, and door_instructions.
export const submitToGuestListOutputSchema = z.object({ entry_id: z.string(), status: z.enum(["confirmed", "full", "closed"]), event_name: z.string().nullable(), event_date: z.string().nullable(), message: z.string(), guest_list_benefit: z.string().nullable(), door_instructions: z.string().nullable(), }); - src/tools/guestList.ts:113-127 (registration)Registration of the submit_to_guest_list tool via server.registerTool(). Wires the tool name, description, input/output schemas, and handler (which calls submitToGuestList from the service layer).
export function registerGuestListTools(server: McpServer, deps: ToolDeps): void { server.registerTool( "submit_to_guest_list", { description: "Submit a guest list entry for an event or venue. Provide either event_id or venue_id + service_date. Returns confirmation with door instructions and guest list benefits if available.", inputSchema: submitToGuestListInputSchema, outputSchema: submitToGuestListOutputSchema, }, async (args) => runTool( "submit_to_guest_list", submitToGuestListOutputSchema, async () => submitToGuestList(deps.supabase, args), ), ); - src/server.ts:37-37 (registration)Top-level registration call: registerGuestListTools(server, { supabase }) inside createNightlifeServer().
registerGuestListTools(server, { supabase });