/** * Shared tool execution — single source of truth for all 11 HemmaBo federation tools. * * The MCP transport (api/mcp.ts) is a thin wrapper that: * 1. Constructs its own Supabase clients (service-role + anon reader). * 2. Validates inputs (JSON-Schema). * 3. Delegates tool execution to `executeTool` below. * 4. Preserves its own error-handling semantics. * * This module does NOT catch errors — errors bubble up to the caller so the * transport can apply its own error-handling rules unchanged. * * MCP-06 invariant: bookings-dependent reads (checkAvailability, resolveQuote's * gap detection) MUST use the service-role client, because anon is denied on * the `bookings` table by RLS (`USING (false)`). */ import type { SupabaseClient } from "@supabase/supabase-js"; export interface ToolClients { /** Service-role client — bypasses RLS. Required for bookings reads + all writes. */ supabase: SupabaseClient; /** Anon client — subject to RLS. Used for published property/snapshot reads. */ reader: SupabaseClient; } export type ToolResult = { content: { type: "text"; text: string; }[]; /** Machine-readable data shared with the model and Apps SDK widget. */ structuredContent?: Record; /** Widget-only metadata, when a transport or UI needs non-model context. */ _meta?: Record; /** * MCP-05: when true, the client must treat this as a tool-level failure * rather than a successful tool call whose `content` happens to describe * an error. Required by the MCP spec for tool errors; JSON-RPC protocol * errors go through a separate channel (`-32603`) and are not set here. */ isError?: boolean; }; /** * Normalize an inbound tool name to the canonical snake_case form. * * Background (#59): The wire-level canonical names are snake_case * (`hemmabo_search_properties`) so they pass the claude.ai web frontend * regex `^[a-zA-Z0-9_-]{1,64}$`. The original dotted names * (`search.properties`) remain accepted as inbound aliases for backwards * compatibility — every dispatcher, validator, and auth gate funnels * names through this function so dotted callers continue to work. */ export declare function normalizeToolName(name: string): string; /** Returns an error string if any of the provided date strings are not YYYY-MM-DD. */ export declare function validateDates(...dates: (string | undefined)[]): string | null; /** Returns an error string if checkOut is not strictly after checkIn. */ export declare function validateDateOrder(checkIn: string, checkOut: string): string | null; /** * Returns an error string listing any required keys whose value is `undefined` * or `null` in `args`. Prevents missing-arg values from reaching Supabase * filters as the literal string "undefined" (Postgres int parser rejects it * with `invalid input syntax for type integer: "undefined"`). * * Note: this does NOT validate types — JSON-Schema in TOOLS metadata is the * source of truth for shapes. This is a fail-fast guard against the most * common AI-agent error: omitting required fields entirely. */ export declare function validateRequiredArgs(args: Record, required: readonly string[]): string | null; type SearchPropertyRow = { id: string; name: string; domain: string | null; region: string | null; city: string | null; country: string | null; max_guests: number | null; currency: string | null; property_type: string | null; direct_booking_discount: number | null; }; export declare function normalizeLocationTerm(value: string | null | undefined): string; export declare function expandLocationTerms(...values: Array): string[]; export declare function propertyMatchesLocation(property: Pick, region?: string, country?: string): boolean; export declare function buildSameMonthDateWindows(checkIn: string, checkOut: string, max?: number): Array<{ checkIn: string; checkOut: string; }>; export declare function executeTool(name: string, args: Record, clients: ToolClients): Promise; export {};