UNPKG

ghl-mcp-server

Version:

GoHighLevel MCP Server for Claude Desktop and ChatGPT integration

1,094 lines 77.1 kB
"use strict"; /** * MCP Calendar Tools for GoHighLevel Integration * Exposes calendar and appointment management capabilities to Claude Desktop */ Object.defineProperty(exports, "__esModule", { value: true }); exports.CalendarTools = void 0; /** * Calendar Tools Class * Implements MCP tools for calendar and appointment management */ class CalendarTools { ghlClient; constructor(ghlClient) { this.ghlClient = ghlClient; } /** * Get all calendar tool definitions for MCP server */ getToolDefinitions() { return [ { name: 'get_calendar_groups', description: 'Get all calendar groups in the GoHighLevel location', inputSchema: { type: 'object', properties: {} } }, { name: 'get_calendars', description: 'Get all calendars in the GoHighLevel location with optional filtering', inputSchema: { type: 'object', properties: { groupId: { type: 'string', description: 'Filter calendars by group ID' }, showDrafted: { type: 'boolean', description: 'Include draft calendars (default: true)', default: true } } } }, { name: 'create_calendar', description: 'Create a new calendar in GoHighLevel', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Name of the calendar' }, description: { type: 'string', description: 'Description of the calendar' }, calendarType: { type: 'string', description: 'Type of calendar to create', enum: ['round_robin', 'event', 'class_booking', 'collective', 'service_booking', 'personal'], default: 'event' }, groupId: { type: 'string', description: 'Calendar group ID to organize the calendar' }, slotDuration: { type: 'number', description: 'Duration of appointment slots in minutes (default: 30)', default: 30 }, slotDurationUnit: { type: 'string', description: 'Unit for slot duration', enum: ['mins', 'hours'], default: 'mins' }, autoConfirm: { type: 'boolean', description: 'Automatically confirm appointments (default: true)', default: true }, allowReschedule: { type: 'boolean', description: 'Allow clients to reschedule appointments (default: true)', default: true }, allowCancellation: { type: 'boolean', description: 'Allow clients to cancel appointments (default: true)', default: true }, isActive: { type: 'boolean', description: 'Make calendar active immediately (default: true)', default: true } }, required: ['name', 'calendarType'] } }, { name: 'get_calendar', description: 'Get detailed information about a specific calendar by ID', inputSchema: { type: 'object', properties: { calendarId: { type: 'string', description: 'The unique ID of the calendar to retrieve' } }, required: ['calendarId'] } }, { name: 'update_calendar', description: 'Update an existing calendar in GoHighLevel', inputSchema: { type: 'object', properties: { calendarId: { type: 'string', description: 'The unique ID of the calendar to update' }, name: { type: 'string', description: 'Updated name of the calendar' }, description: { type: 'string', description: 'Updated description of the calendar' }, slotDuration: { type: 'number', description: 'Updated duration of appointment slots in minutes' }, autoConfirm: { type: 'boolean', description: 'Updated auto-confirm setting' }, allowReschedule: { type: 'boolean', description: 'Updated reschedule permission setting' }, allowCancellation: { type: 'boolean', description: 'Updated cancellation permission setting' }, isActive: { type: 'boolean', description: 'Updated active status' } }, required: ['calendarId'] } }, { name: 'delete_calendar', description: 'Delete a calendar from GoHighLevel', inputSchema: { type: 'object', properties: { calendarId: { type: 'string', description: 'The unique ID of the calendar to delete' } }, required: ['calendarId'] } }, { name: 'get_calendar_events', description: 'Get appointments/events from calendars within a date range', inputSchema: { type: 'object', properties: { startTime: { type: 'string', description: 'Start time in milliseconds or ISO date (e.g., "2024-01-01" or "1704067200000")' }, endTime: { type: 'string', description: 'End time in milliseconds or ISO date (e.g., "2024-01-31" or "1706745599999")' }, calendarId: { type: 'string', description: 'Filter events by specific calendar ID' }, userId: { type: 'string', description: 'Filter events by assigned user ID' }, groupId: { type: 'string', description: 'Filter events by calendar group ID' } }, required: ['startTime', 'endTime'] } }, { name: 'get_free_slots', description: 'Get available time slots for booking appointments on a specific calendar', inputSchema: { type: 'object', properties: { calendarId: { type: 'string', description: 'The calendar ID to check availability for' }, startDate: { type: 'string', description: 'Start date for availability check (YYYY-MM-DD format or milliseconds)' }, endDate: { type: 'string', description: 'End date for availability check (YYYY-MM-DD format or milliseconds)' }, timezone: { type: 'string', description: 'Timezone for the results (e.g., "America/New_York")' }, userId: { type: 'string', description: 'Specific user ID to check availability for' } }, required: ['calendarId', 'startDate', 'endDate'] } }, { name: 'create_appointment', description: 'Create a new appointment/booking in GoHighLevel', inputSchema: { type: 'object', properties: { calendarId: { type: 'string', description: 'The calendar ID to book the appointment in' }, contactId: { type: 'string', description: 'The contact ID for whom to book the appointment' }, startTime: { type: 'string', description: 'Start time in ISO format (e.g., "2024-01-15T10:00:00-05:00")' }, endTime: { type: 'string', description: 'End time in ISO format (optional, will be calculated from slot duration if not provided)' }, title: { type: 'string', description: 'Title/subject of the appointment' }, appointmentStatus: { type: 'string', description: 'Initial status of the appointment', enum: ['new', 'confirmed'], default: 'confirmed' }, assignedUserId: { type: 'string', description: 'User ID to assign this appointment to' }, address: { type: 'string', description: 'Meeting location or address' }, meetingLocationType: { type: 'string', description: 'Type of meeting location', enum: ['custom', 'zoom', 'gmeet', 'phone', 'address'], default: 'custom' }, ignoreDateRange: { type: 'boolean', description: 'Ignore minimum scheduling notice and date range restrictions', default: false }, toNotify: { type: 'boolean', description: 'Send notifications for this appointment', default: true } }, required: ['calendarId', 'contactId', 'startTime'] } }, { name: 'get_appointment', description: 'Get detailed information about a specific appointment by ID', inputSchema: { type: 'object', properties: { appointmentId: { type: 'string', description: 'The unique ID of the appointment to retrieve' } }, required: ['appointmentId'] } }, { name: 'update_appointment', description: 'Update an existing appointment in GoHighLevel', inputSchema: { type: 'object', properties: { appointmentId: { type: 'string', description: 'The unique ID of the appointment to update' }, title: { type: 'string', description: 'Updated title/subject of the appointment' }, appointmentStatus: { type: 'string', description: 'Updated status of the appointment', enum: ['new', 'confirmed', 'cancelled', 'showed', 'noshow'] }, assignedUserId: { type: 'string', description: 'Updated assigned user ID' }, address: { type: 'string', description: 'Updated meeting location or address' }, startTime: { type: 'string', description: 'Updated start time in ISO format' }, endTime: { type: 'string', description: 'Updated end time in ISO format' }, toNotify: { type: 'boolean', description: 'Send notifications for this update', default: true } }, required: ['appointmentId'] } }, { name: 'delete_appointment', description: 'Cancel/delete an appointment from GoHighLevel', inputSchema: { type: 'object', properties: { appointmentId: { type: 'string', description: 'The unique ID of the appointment to delete' } }, required: ['appointmentId'] } }, { name: 'create_block_slot', description: 'Create a blocked time slot to prevent bookings during specific times', inputSchema: { type: 'object', properties: { startTime: { type: 'string', description: 'Start time of the block in ISO format (e.g., "2024-01-15T10:00:00-05:00")' }, endTime: { type: 'string', description: 'End time of the block in ISO format (e.g., "2024-01-15T12:00:00-05:00")' }, title: { type: 'string', description: 'Title/reason for the block (e.g., "Lunch Break", "Meeting")' }, calendarId: { type: 'string', description: 'Specific calendar to block (optional, blocks all if not specified)' }, assignedUserId: { type: 'string', description: 'User ID to apply the block for' } }, required: ['startTime', 'endTime'] } }, { name: 'update_block_slot', description: 'Update an existing blocked time slot', inputSchema: { type: 'object', properties: { blockSlotId: { type: 'string', description: 'The unique ID of the block slot to update' }, startTime: { type: 'string', description: 'Updated start time in ISO format' }, endTime: { type: 'string', description: 'Updated end time in ISO format' }, title: { type: 'string', description: 'Updated title/reason for the block' }, calendarId: { type: 'string', description: 'Updated calendar ID for the block' }, assignedUserId: { type: 'string', description: 'Updated assigned user ID' } }, required: ['blockSlotId'] } }, { name: 'create_calendar_group', description: 'Create a new calendar group', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Group name' }, description: { type: 'string', description: 'Group description' }, slug: { type: 'string', description: 'URL slug for the group' }, isActive: { type: 'boolean', description: 'Whether group is active', default: true } }, required: ['name', 'description', 'slug'] } }, { name: 'validate_group_slug', description: 'Validate if a calendar group slug is available', inputSchema: { type: 'object', properties: { slug: { type: 'string', description: 'Slug to validate' }, locationId: { type: 'string', description: 'Location ID' } }, required: ['slug'] } }, { name: 'update_calendar_group', description: 'Update calendar group details', inputSchema: { type: 'object', properties: { groupId: { type: 'string', description: 'Calendar group ID' }, name: { type: 'string', description: 'Group name' }, description: { type: 'string', description: 'Group description' }, slug: { type: 'string', description: 'URL slug for the group' } }, required: ['groupId', 'name', 'description', 'slug'] } }, { name: 'delete_calendar_group', description: 'Delete a calendar group', inputSchema: { type: 'object', properties: { groupId: { type: 'string', description: 'Calendar group ID' } }, required: ['groupId'] } }, { name: 'disable_calendar_group', description: 'Enable or disable a calendar group', inputSchema: { type: 'object', properties: { groupId: { type: 'string', description: 'Calendar group ID' }, isActive: { type: 'boolean', description: 'Whether to enable (true) or disable (false) the group' } }, required: ['groupId', 'isActive'] } }, { name: 'get_appointment_notes', description: 'Get notes for an appointment', inputSchema: { type: 'object', properties: { appointmentId: { type: 'string', description: 'Appointment ID' }, limit: { type: 'number', description: 'Maximum number of notes to return', default: 10 }, offset: { type: 'number', description: 'Number of notes to skip', default: 0 } }, required: ['appointmentId'] } }, { name: 'create_appointment_note', description: 'Create a note for an appointment', inputSchema: { type: 'object', properties: { appointmentId: { type: 'string', description: 'Appointment ID' }, body: { type: 'string', description: 'Note content' }, userId: { type: 'string', description: 'User ID creating the note' } }, required: ['appointmentId', 'body'] } }, { name: 'update_appointment_note', description: 'Update an appointment note', inputSchema: { type: 'object', properties: { appointmentId: { type: 'string', description: 'Appointment ID' }, noteId: { type: 'string', description: 'Note ID' }, body: { type: 'string', description: 'Updated note content' }, userId: { type: 'string', description: 'User ID updating the note' } }, required: ['appointmentId', 'noteId', 'body'] } }, { name: 'delete_appointment_note', description: 'Delete an appointment note', inputSchema: { type: 'object', properties: { appointmentId: { type: 'string', description: 'Appointment ID' }, noteId: { type: 'string', description: 'Note ID' } }, required: ['appointmentId', 'noteId'] } }, { name: 'get_calendar_resources_equipments', description: 'Get calendar equipment resources', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Maximum number to return', default: 20 }, skip: { type: 'number', description: 'Number to skip', default: 0 } } } }, { name: 'create_calendar_resource_equipment', description: 'Create a calendar equipment resource', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Equipment name' }, description: { type: 'string', description: 'Equipment description' }, quantity: { type: 'number', description: 'Total quantity available' }, outOfService: { type: 'number', description: 'Number currently out of service' }, capacity: { type: 'number', description: 'Capacity per unit' }, calendarIds: { type: 'array', items: { type: 'string' }, description: 'Associated calendar IDs' } }, required: ['name', 'description', 'quantity', 'outOfService', 'capacity', 'calendarIds'] } }, { name: 'get_calendar_resource_equipment', description: 'Get specific equipment resource details', inputSchema: { type: 'object', properties: { resourceId: { type: 'string', description: 'Equipment resource ID' } }, required: ['resourceId'] } }, { name: 'update_calendar_resource_equipment', description: 'Update equipment resource details', inputSchema: { type: 'object', properties: { resourceId: { type: 'string', description: 'Equipment resource ID' }, name: { type: 'string', description: 'Equipment name' }, description: { type: 'string', description: 'Equipment description' }, quantity: { type: 'number', description: 'Total quantity available' }, outOfService: { type: 'number', description: 'Number currently out of service' }, capacity: { type: 'number', description: 'Capacity per unit' }, calendarIds: { type: 'array', items: { type: 'string' }, description: 'Associated calendar IDs' }, isActive: { type: 'boolean', description: 'Whether resource is active' } }, required: ['resourceId'] } }, { name: 'delete_calendar_resource_equipment', description: 'Delete an equipment resource', inputSchema: { type: 'object', properties: { resourceId: { type: 'string', description: 'Equipment resource ID' } }, required: ['resourceId'] } }, { name: 'get_calendar_resources_rooms', description: 'Get calendar room resources', inputSchema: { type: 'object', properties: { limit: { type: 'number', description: 'Maximum number to return', default: 20 }, skip: { type: 'number', description: 'Number to skip', default: 0 } } } }, { name: 'create_calendar_resource_room', description: 'Create a calendar room resource', inputSchema: { type: 'object', properties: { name: { type: 'string', description: 'Room name' }, description: { type: 'string', description: 'Room description' }, quantity: { type: 'number', description: 'Total quantity available' }, outOfService: { type: 'number', description: 'Number currently out of service' }, capacity: { type: 'number', description: 'Room capacity' }, calendarIds: { type: 'array', items: { type: 'string' }, description: 'Associated calendar IDs' } }, required: ['name', 'description', 'quantity', 'outOfService', 'capacity', 'calendarIds'] } }, { name: 'get_calendar_resource_room', description: 'Get specific room resource details', inputSchema: { type: 'object', properties: { resourceId: { type: 'string', description: 'Room resource ID' } }, required: ['resourceId'] } }, { name: 'update_calendar_resource_room', description: 'Update room resource details', inputSchema: { type: 'object', properties: { resourceId: { type: 'string', description: 'Room resource ID' }, name: { type: 'string', description: 'Room name' }, description: { type: 'string', description: 'Room description' }, quantity: { type: 'number', description: 'Total quantity available' }, outOfService: { type: 'number', description: 'Number currently out of service' }, capacity: { type: 'number', description: 'Room capacity' }, calendarIds: { type: 'array', items: { type: 'string' }, description: 'Associated calendar IDs' }, isActive: { type: 'boolean', description: 'Whether resource is active' } }, required: ['resourceId'] } }, { name: 'delete_calendar_resource_room', description: 'Delete a room resource', inputSchema: { type: 'object', properties: { resourceId: { type: 'string', description: 'Room resource ID' } }, required: ['resourceId'] } }, { name: 'get_calendar_notifications', description: 'Get calendar notifications', inputSchema: { type: 'object', properties: { calendarId: { type: 'string', description: 'Calendar ID' }, isActive: { type: 'boolean', description: 'Filter by active status' }, deleted: { type: 'boolean', description: 'Include deleted notifications' }, limit: { type: 'number', description: 'Maximum number to return' }, skip: { type: 'number', description: 'Number to skip' } }, required: ['calendarId'] } }, { name: 'create_calendar_notifications', description: 'Create calendar notifications', inputSchema: { type: 'object', properties: { calendarId: { type: 'string', description: 'Calendar ID' }, notifications: { type: 'array', items: { type: 'object', properties: { receiverType: { type: 'string', enum: ['contact', 'guest', 'assignedUser', 'emails'], description: 'Who receives the notification' }, channel: { type: 'string', enum: ['email', 'inApp'], description: 'Notification channel' }, notificationType: { type: 'string', enum: ['booked', 'confirmation', 'cancellation', 'reminder', 'followup', 'reschedule'], description: 'Type of notification' }, isActive: { type: 'boolean', description: 'Whether notification is active' }, templateId: { type: 'string', description: 'Template ID' }, body: { type: 'string', description: 'Notification body' }, subject: { type: 'string', description: 'Notification subject' } }, required: ['receiverType', 'channel', 'notificationType'] }, description: 'Array of notification configurations' } }, required: ['calendarId', 'notifications'] } }, { name: 'get_calendar_notification', description: 'Get specific calendar notification', inputSchema: { type: 'object', properties: { calendarId: { type: 'string', description: 'Calendar ID' }, notificationId: { type: 'string', description: 'Notification ID' } }, required: ['calendarId', 'notificationId'] } }, { name: 'update_calendar_notification', description: 'Update calendar notification', inputSchema: { type: 'object', properties: { calendarId: { type: 'string', description: 'Calendar ID' }, notificationId: { type: 'string', description: 'Notification ID' }, receiverType: { type: 'string', enum: ['contact', 'guest', 'assignedUser', 'emails'], description: 'Who receives the notification' }, channel: { type: 'string', enum: ['email', 'inApp'], description: 'Notification channel' }, notificationType: { type: 'string', enum: ['booked', 'confirmation', 'cancellation', 'reminder', 'followup', 'reschedule'], description: 'Type of notification' }, isActive: { type: 'boolean', description: 'Whether notification is active' }, deleted: { type: 'boolean', description: 'Whether notification is deleted' }, templateId: { type: 'string', description: 'Template ID' }, body: { type: 'string', description: 'Notification body' }, subject: { type: 'string', description: 'Notification subject' } }, required: ['calendarId', 'notificationId'] } }, { name: 'delete_calendar_notification', description: 'Delete calendar notification', inputSchema: { type: 'object', properties: { calendarId: { type: 'string', description: 'Calendar ID' }, notificationId: { type: 'string', description: 'Notification ID' } }, required: ['calendarId', 'notificationId'] } }, { name: 'get_blocked_slots', description: 'Get blocked time slots for a location', inputSchema: { type: 'object', properties: { userId: { type: 'string', description: 'Filter by user ID' }, calendarId: { type: 'string', description: 'Filter by calendar ID' }, groupId: { type: 'string', description: 'Filter by group ID' }, startTime: { type: 'string', description: 'Start time for the query range' }, endTime: { type: 'string', description: 'End time for the query range' } }, required: ['startTime', 'endTime'] } } ]; } /** * Execute calendar tool based on tool name and arguments */ async executeTool(name, args) { switch (name) { case 'get_calendar_groups': return this.getCalendarGroups(); case 'get_calendars': return this.getCalendars(args); case 'create_calendar': return this.createCalendar(args); case 'get_calendar': return this.getCalendar(args.calendarId); case 'update_calendar': return this.updateCalendar(args); case 'delete_calendar': return this.deleteCalendar(args.calendarId); case 'get_calendar_events': return this.getCalendarEvents(args); case 'get_free_slots': return this.getFreeSlots(args); case 'create_appointment': return this.createAppointment(args); case 'get_appointment': return this.getAppointment(args.appointmentId); case 'update_appointment': return this.updateAppointment(args); case 'delete_appointment': return this.deleteAppointment(args.appointmentId); case 'create_block_slot': return this.createBlockSlot(args); case 'update_block_slot': return this.updateBlockSlot(args); case 'create_calendar_group': return this.createCalendarGroup(args); case 'validate_group_slug': return this.validateGroupSlug(args); case 'update_calendar_group': return this.updateCalendarGroup(args); case 'delete_calendar_group': return this.deleteCalendarGroup(args); case 'disable_calendar_group': return this.disableCalendarGroup(args); case 'get_appointment_notes': return this.getAppointmentNotes(args); case 'create_appointment_note': return this.createAppointmentNote(args); case 'update_appointment_note': return this.updateAppointmentNote(args); case 'delete_appointment_note': return this.deleteAppointmentNote(args); case 'get_calendar_resources_equipments': return this.getCalendarResourcesEquipments(args); case 'create_calendar_resource_equipment': return this.createCalendarResourceEquipment(args); case 'get_calendar_resource_equipment': return this.getCalendarResourceEquipment(args); case 'update_calendar_resource_equipment': return this.updateCalendarResourceEquipment(args); case 'delete_calendar_resource_equipment': return this.deleteCalendarResourceEquipment(args); case 'get_calendar_resources_rooms': return this.getCalendarResourcesRooms(args); case 'create_calendar_resource_room': return this.createCalendarResourceRoom(args); case 'get_calendar_resource_room': return this.getCalendarResourceRoom(args); case 'update_calendar_resource_room': return this.updateCalendarResourceRoom(args); case 'delete_calendar_resource_room': return this.deleteCalendarResourceRoom(args); case 'get_calendar_notifications': return this.getCalendarNotifications(args); case 'create_calendar_notifications': return this.createCalendarNotifications(args); case 'get_calendar_notification': return this.getCalendarNotification(args); case 'update_calendar_notification': return this.updateCalendarNotification(args); case 'delete_calendar_notification': return this.deleteCalendarNotification(args); case 'get_blocked_slots': return this.getBlockedSlots(args); default: throw new Error(`Unknown calendar tool: ${name}`); } } /** * GET CALENDAR GROUPS */ async getCalendarGroups() { try { const response = await this.ghlClient.getCalendarGroups(); if (!response.success || !response.data) { const errorMsg = response.error?.message || 'Unknown API error'; throw new Error(`API request failed: ${errorMsg}`); } const data = response.data; const groups = Array.isArray(data.groups) ? data.groups : []; return { success: true, groups, message: `Retrieved ${groups.length} calendar groups` }; } catch (error) { process.stderr.write(`[GHL MCP] Get calendar groups error: ${JSON.stringify(error, null, 2)}\n`); throw new Error(`Failed to get calendar groups: ${error instanceof Error ? error.message : String(error)}`); } } /** * GET CALENDARS */ async getCalendars(params = {}) { try { const response = await this.ghlClient.getCalendars(params); if (!response.success || !response.data) { const errorMsg = response.error?.message || 'Unknown API error'; throw new Error(`API request failed: ${errorMsg}`); } const data = response.data; const calendars = Array.isArray(data.calendars) ? data.calendars : []; return { success: true, calendars, message: `Retrieved ${calendars.length} calendars` }; } catch (error) { throw new Error(`Failed to get calendars: ${error instanceof Error ? error.message : String(error)}`); } } /** * CREATE CALENDAR */ async createCalendar(params) { try { const calendarData = { locationId: this.ghlClient.getConfig().locationId, name: params.name, description: params.description, calendarType: params.calendarType, groupId: params.groupId, teamMembers: params.teamMembers, slotDuration: params.slotDuration || 30, slotDurationUnit: params.slotDurationUnit || 'mins', autoConfirm: params.autoConfirm !== undefined ? params.autoConfirm : true, allowReschedule: params.allowReschedule !== undefined ? params.allowReschedule : true, allowCancellation: params.allowCancellation !== undefined ? params.allowCancellation : true, isActive: params.isActive !== undefined ? params.isActive : true }; const response = await this.ghlClient.createCalendar(calendarData); if (!response.success || !response.data) { const errorMsg = response.error?.message || 'Unknown API error'; throw new Error(`API request failed: ${errorMsg}`); } return { success: true, calendar: response.data.calendar, message: `Calendar created successfully with ID: ${response.data.calendar.id}` }; } catch (error) { throw new Error(`Failed to create calendar: ${error instanceof Error ? error.message : String(error)}`); } } /** * GET CALENDAR BY ID */ async getCalendar(calendarId) { try { const response = await this.ghlClient.getCalendar(calendarId); if (!response.success || !response.data) { const errorMsg = response.error?.message || 'Unknown API error'; throw new Error(`API request failed: ${errorMsg}`); } return { success: true, calendar: response.data.calendar, message: 'Calendar retrieved successfully' }; } catch (error) { throw new Error(`Failed to get calendar: ${error instanceof Error ? error.message : String(error)}`); } } /** * UPDATE CALENDAR */ async updateCalendar(params) { try { const { calendarId, ...updateData } = params; const response = await this.ghlClient.updateCalendar(calendarId, updateData); if (!response.success || !response.data) { const errorMsg = response.error?.message || 'Unknown API error'; throw new Error(`API request failed: ${errorMsg}`); } return { success: true, calendar: response.data.calendar, message: 'Calendar updated successfully' }; } catch (error) { throw new Error(`Failed to update calendar: ${error instanceof Error ? error.message : String(error)}`); } } /** * DELETE CALENDAR */ async deleteCalendar(calendarId) { try { const response = await this.ghlClient.deleteCalendar(calendarId); if (!response.success || !response.data) { const errorMsg = response.error?.message || 'Unknown API error'; throw new Error(`API request failed: ${errorMsg}`); } return { success: true, message: 'Calendar deleted successfully' }; } catch (error) { throw new Error(`Failed to delete calendar: ${error instanceof Error ? error.message : String(error)}`); } } /** * GET CALENDAR EVENTS */ async getCalendarEvents(params) { try { // Convert date strings to milliseconds if needed const startTime = this.convertToMilliseconds(params.startTime); const endTime = this.convertToMilliseconds(params.endTime); const eventParams = { locationId: this.ghlClient.getConfig().locationId, startTime, endTime, userId: params.userId, calendarId: params.calendarId, groupId: params.groupId }; const response = await this.ghlClient.getCalendarEvents(eventParams); if (!response.success || !response.data) { const errorMsg = response.error?.message || 'Unknown API error'; throw new Error(`API request failed: ${errorMsg}`); } const data = response.data; const events = Array.isArray(data.events) ? data.events : []; return { success: true, events, message: `Retrieved ${events.length} calendar events` }; } catch (error) { throw new Error(`Failed to get calendar events: ${error instanceof Error ? error.message : String(error)}`); } } /** * GET FREE SLOTS */ async getFreeSlots(params) { try { // Convert dates to milliseconds if needed const startDate = this.convertDateToMilliseconds(params.startDate); const endDate = this.convertDateToMilliseconds(params.endDate); const slotParams = { calendarId: params.calendarId, startDate, endDate, timezone: params.timezone, userId: params.userId }; const response = await this.ghlClient.getFreeSlots(slotParams); if (!response.success || !response.data) { const errorMsg = response.error?.message || 'Unknown API error'; throw new Error(`API request failed: ${errorMsg}`); } return { success: true, freeSlots: response.data, message: 'Free slots retrieved successfully' }; } catch (error) { throw new Error(`Failed to get free slots: ${error instanceof Error ? error.message : String(error)}`); } } /** * CREATE APPOINTMENT */ async createAppointment(params) { try { const appointmentData = { calendarId: params.calendarId, locationId: this.ghlClient.getConfig().locationId, contactId: params.contactId, startTime: params.startTime, endTime: params.endTime, title: params.title, appointmentStatus: params.appointmentStatus || 'confirmed', assignedUserId: params.assignedUserId, address: params.address, meetingLocationType: params.meetingLocationType, ignoreDateRange: params.ignoreDateRange, toNotify: params.toNotify !== undefined ? params.toNotify : true }; const response = await this.ghlClient.createAppointment(appointmentD