Features: - 400+ tools covering entire GoHighLevel API - Contact management, conversations, opportunities, calendars - Invoices, payments, products, store management - Social media, email marketing, workflows, and more - Self-host or use managed solution at mcp.localbosses.org
1960 lines
69 KiB
TypeScript
1960 lines
69 KiB
TypeScript
/**
|
|
* MCP Calendar Tools for GoHighLevel Integration
|
|
* Exposes calendar and appointment management capabilities to Claude Desktop
|
|
*/
|
|
|
|
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
|
import { GHLApiClient } from '../clients/ghl-api-client.js';
|
|
import {
|
|
MCPGetCalendarsParams,
|
|
MCPCreateCalendarParams,
|
|
MCPUpdateCalendarParams,
|
|
MCPGetCalendarEventsParams,
|
|
MCPGetFreeSlotsParams,
|
|
MCPCreateAppointmentParams,
|
|
MCPUpdateAppointmentParams,
|
|
MCPCreateBlockSlotParams,
|
|
MCPUpdateBlockSlotParams,
|
|
GHLCalendar,
|
|
GHLGetCalendarsResponse,
|
|
GHLGetCalendarGroupsResponse,
|
|
GHLGetCalendarEventsResponse,
|
|
GHLGetFreeSlotsResponse,
|
|
GHLCalendarEvent,
|
|
GHLBlockSlotResponse,
|
|
MCPCreateCalendarGroupParams,
|
|
MCPValidateGroupSlugParams,
|
|
MCPUpdateCalendarGroupParams,
|
|
MCPDeleteCalendarGroupParams,
|
|
MCPDisableCalendarGroupParams,
|
|
MCPGetAppointmentNotesParams,
|
|
MCPCreateAppointmentNoteParams,
|
|
MCPUpdateAppointmentNoteParams,
|
|
MCPDeleteAppointmentNoteParams,
|
|
MCPGetCalendarResourcesParams,
|
|
MCPCreateCalendarResourceParams,
|
|
MCPGetCalendarResourceParams,
|
|
MCPUpdateCalendarResourceParams,
|
|
MCPDeleteCalendarResourceParams,
|
|
MCPGetCalendarNotificationsParams,
|
|
MCPCreateCalendarNotificationParams,
|
|
MCPGetCalendarNotificationParams,
|
|
MCPUpdateCalendarNotificationParams,
|
|
MCPDeleteCalendarNotificationParams,
|
|
MCPGetBlockedSlotsParams
|
|
} from '../types/ghl-types.js';
|
|
|
|
/**
|
|
* Calendar Tools Class
|
|
* Implements MCP tools for calendar and appointment management
|
|
*/
|
|
export class CalendarTools {
|
|
constructor(private ghlClient: GHLApiClient) {}
|
|
|
|
/**
|
|
* Get all calendar tool definitions for MCP server
|
|
*/
|
|
getToolDefinitions(): Tool[] {
|
|
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: string, args: any): Promise<any> {
|
|
switch (name) {
|
|
case 'get_calendar_groups':
|
|
return this.getCalendarGroups();
|
|
|
|
case 'get_calendars':
|
|
return this.getCalendars(args as MCPGetCalendarsParams);
|
|
|
|
case 'create_calendar':
|
|
return this.createCalendar(args as MCPCreateCalendarParams);
|
|
|
|
case 'get_calendar':
|
|
return this.getCalendar(args.calendarId);
|
|
|
|
case 'update_calendar':
|
|
return this.updateCalendar(args as MCPUpdateCalendarParams);
|
|
|
|
case 'delete_calendar':
|
|
return this.deleteCalendar(args.calendarId);
|
|
|
|
case 'get_calendar_events':
|
|
return this.getCalendarEvents(args as MCPGetCalendarEventsParams);
|
|
|
|
case 'get_free_slots':
|
|
return this.getFreeSlots(args as MCPGetFreeSlotsParams);
|
|
|
|
case 'create_appointment':
|
|
return this.createAppointment(args as MCPCreateAppointmentParams);
|
|
|
|
case 'get_appointment':
|
|
return this.getAppointment(args.appointmentId);
|
|
|
|
case 'update_appointment':
|
|
return this.updateAppointment(args as MCPUpdateAppointmentParams);
|
|
|
|
case 'delete_appointment':
|
|
return this.deleteAppointment(args.appointmentId);
|
|
|
|
case 'create_block_slot':
|
|
return this.createBlockSlot(args as MCPCreateBlockSlotParams);
|
|
|
|
case 'update_block_slot':
|
|
return this.updateBlockSlot(args as MCPUpdateBlockSlotParams);
|
|
|
|
case 'create_calendar_group':
|
|
return this.createCalendarGroup(args as MCPCreateCalendarGroupParams);
|
|
|
|
case 'validate_group_slug':
|
|
return this.validateGroupSlug(args as MCPValidateGroupSlugParams);
|
|
|
|
case 'update_calendar_group':
|
|
return this.updateCalendarGroup(args as MCPUpdateCalendarGroupParams);
|
|
|
|
case 'delete_calendar_group':
|
|
return this.deleteCalendarGroup(args as MCPDeleteCalendarGroupParams);
|
|
|
|
case 'disable_calendar_group':
|
|
return this.disableCalendarGroup(args as MCPDisableCalendarGroupParams);
|
|
|
|
case 'get_appointment_notes':
|
|
return this.getAppointmentNotes(args as MCPGetAppointmentNotesParams);
|
|
|
|
case 'create_appointment_note':
|
|
return this.createAppointmentNote(args as MCPCreateAppointmentNoteParams);
|
|
|
|
case 'update_appointment_note':
|
|
return this.updateAppointmentNote(args as MCPUpdateAppointmentNoteParams);
|
|
|
|
case 'delete_appointment_note':
|
|
return this.deleteAppointmentNote(args as MCPDeleteAppointmentNoteParams);
|
|
|
|
case 'get_calendar_resources_equipments':
|
|
return this.getCalendarResourcesEquipments(args as MCPGetCalendarResourcesParams);
|
|
|
|
case 'create_calendar_resource_equipment':
|
|
return this.createCalendarResourceEquipment(args as MCPCreateCalendarResourceParams);
|
|
|
|
case 'get_calendar_resource_equipment':
|
|
return this.getCalendarResourceEquipment(args as MCPGetCalendarResourceParams);
|
|
|
|
case 'update_calendar_resource_equipment':
|
|
return this.updateCalendarResourceEquipment(args as MCPUpdateCalendarResourceParams);
|
|
|
|
case 'delete_calendar_resource_equipment':
|
|
return this.deleteCalendarResourceEquipment(args as MCPDeleteCalendarResourceParams);
|
|
|
|
case 'get_calendar_resources_rooms':
|
|
return this.getCalendarResourcesRooms(args as MCPGetCalendarResourcesParams);
|
|
|
|
case 'create_calendar_resource_room':
|
|
return this.createCalendarResourceRoom(args as MCPCreateCalendarResourceParams);
|
|
|
|
case 'get_calendar_resource_room':
|
|
return this.getCalendarResourceRoom(args as MCPGetCalendarResourceParams);
|
|
|
|
case 'update_calendar_resource_room':
|
|
return this.updateCalendarResourceRoom(args as MCPUpdateCalendarResourceParams);
|
|
|
|
case 'delete_calendar_resource_room':
|
|
return this.deleteCalendarResourceRoom(args as MCPDeleteCalendarResourceParams);
|
|
|
|
case 'get_calendar_notifications':
|
|
return this.getCalendarNotifications(args as MCPGetCalendarNotificationsParams);
|
|
|
|
case 'create_calendar_notifications':
|
|
return this.createCalendarNotifications(args as MCPCreateCalendarNotificationParams);
|
|
|
|
case 'get_calendar_notification':
|
|
return this.getCalendarNotification(args as MCPGetCalendarNotificationParams);
|
|
|
|
case 'update_calendar_notification':
|
|
return this.updateCalendarNotification(args as MCPUpdateCalendarNotificationParams);
|
|
|
|
case 'delete_calendar_notification':
|
|
return this.deleteCalendarNotification(args as MCPDeleteCalendarNotificationParams);
|
|
|
|
case 'get_blocked_slots':
|
|
return this.getBlockedSlots(args as MCPGetBlockedSlotsParams);
|
|
|
|
default:
|
|
throw new Error(`Unknown calendar tool: ${name}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET CALENDAR GROUPS
|
|
*/
|
|
private async getCalendarGroups(): Promise<{ success: boolean; groups: any[]; message: string }> {
|
|
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 as GHLGetCalendarGroupsResponse;
|
|
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
|
|
*/
|
|
private async getCalendars(params: MCPGetCalendarsParams = {}): Promise<{ success: boolean; calendars: GHLCalendar[]; message: string }> {
|
|
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 as GHLGetCalendarsResponse;
|
|
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
|
|
*/
|
|
private async createCalendar(params: MCPCreateCalendarParams): Promise<{ success: boolean; calendar: GHLCalendar; message: string }> {
|
|
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
|
|
*/
|
|
private async getCalendar(calendarId: string): Promise<{ success: boolean; calendar: GHLCalendar; message: string }> {
|
|
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
|
|
*/
|
|
private async updateCalendar(params: MCPUpdateCalendarParams): Promise<{ success: boolean; calendar: GHLCalendar; message: string }> {
|
|
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
|
|
*/
|
|
private async deleteCalendar(calendarId: string): Promise<{ success: boolean; message: string }> {
|
|
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
|
|
*/
|
|
private async getCalendarEvents(params: MCPGetCalendarEventsParams): Promise<{ success: boolean; events: GHLCalendarEvent[]; message: string }> {
|
|
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 as GHLGetCalendarEventsResponse;
|
|
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
|
|
*/
|
|
private async getFreeSlots(params: MCPGetFreeSlotsParams): Promise<{ success: boolean; freeSlots: any; message: string }> {
|
|
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
|
|
*/
|
|
private async createAppointment(params: MCPCreateAppointmentParams): Promise<{ success: boolean; appointment: GHLCalendarEvent; message: string }> {
|
|
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(appointmentData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
appointment: response.data,
|
|
message: `Appointment created successfully with ID: ${response.data.id}`
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to create appointment: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET APPOINTMENT BY ID
|
|
*/
|
|
private async getAppointment(appointmentId: string): Promise<{ success: boolean; appointment: GHLCalendarEvent; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.getAppointment(appointmentId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
appointment: response.data.event,
|
|
message: 'Appointment retrieved successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to get appointment: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* UPDATE APPOINTMENT
|
|
*/
|
|
private async updateAppointment(params: MCPUpdateAppointmentParams): Promise<{ success: boolean; appointment: GHLCalendarEvent; message: string }> {
|
|
try {
|
|
const { appointmentId, ...updateData } = params;
|
|
|
|
const response = await this.ghlClient.updateAppointment(appointmentId, updateData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
appointment: response.data,
|
|
message: 'Appointment updated successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to update appointment: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* DELETE APPOINTMENT
|
|
*/
|
|
private async deleteAppointment(appointmentId: string): Promise<{ success: boolean; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.deleteAppointment(appointmentId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
message: 'Appointment deleted successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to delete appointment: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CREATE BLOCK SLOT
|
|
*/
|
|
private async createBlockSlot(params: MCPCreateBlockSlotParams): Promise<{ success: boolean; blockSlot: GHLBlockSlotResponse; message: string }> {
|
|
try {
|
|
const blockSlotData = {
|
|
locationId: this.ghlClient.getConfig().locationId,
|
|
startTime: params.startTime,
|
|
endTime: params.endTime,
|
|
title: params.title,
|
|
calendarId: params.calendarId,
|
|
assignedUserId: params.assignedUserId
|
|
};
|
|
|
|
const response = await this.ghlClient.createBlockSlot(blockSlotData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
blockSlot: response.data,
|
|
message: `Block slot created successfully with ID: ${response.data.id}`
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to create block slot: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* UPDATE BLOCK SLOT
|
|
*/
|
|
private async updateBlockSlot(params: MCPUpdateBlockSlotParams): Promise<{ success: boolean; blockSlot: GHLBlockSlotResponse; message: string }> {
|
|
try {
|
|
const { blockSlotId, ...updateData } = params;
|
|
|
|
const response = await this.ghlClient.updateBlockSlot(blockSlotId, updateData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
blockSlot: response.data,
|
|
message: 'Block slot updated successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to update block slot: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Helper method to convert date string to milliseconds
|
|
*/
|
|
private convertToMilliseconds(dateString: string): string {
|
|
// If already in milliseconds, return as is
|
|
if (/^\d+$/.test(dateString)) {
|
|
return dateString;
|
|
}
|
|
|
|
// Try to parse as ISO date
|
|
const date = new Date(dateString);
|
|
if (!isNaN(date.getTime())) {
|
|
return date.getTime().toString();
|
|
}
|
|
|
|
// Return as is if can't parse
|
|
return dateString;
|
|
}
|
|
|
|
/**
|
|
* Helper method to convert date string to milliseconds for date-only values
|
|
*/
|
|
private convertDateToMilliseconds(dateString: string): number {
|
|
// If already in milliseconds, parse and return
|
|
if (/^\d+$/.test(dateString)) {
|
|
return parseInt(dateString, 10);
|
|
}
|
|
|
|
// Try to parse as date string (YYYY-MM-DD format)
|
|
const date = new Date(dateString);
|
|
if (!isNaN(date.getTime())) {
|
|
return date.getTime();
|
|
}
|
|
|
|
// Fallback to current time
|
|
return Date.now();
|
|
}
|
|
|
|
/**
|
|
* CREATE CALENDAR GROUP
|
|
*/
|
|
private async createCalendarGroup(params: MCPCreateCalendarGroupParams): Promise<{ success: boolean; group: any; message: string }> {
|
|
try {
|
|
const groupData = {
|
|
locationId: this.ghlClient.getConfig().locationId,
|
|
name: params.name,
|
|
description: params.description,
|
|
slug: params.slug
|
|
};
|
|
|
|
const response = await this.ghlClient.createCalendarGroup(groupData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
group: response.data,
|
|
message: `Calendar group created successfully with slug: ${params.slug}`
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to create calendar group: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* VALIDATE GROUP SLUG
|
|
*/
|
|
private async validateGroupSlug(params: MCPValidateGroupSlugParams): Promise<{ success: boolean; available?: boolean; message: string }> {
|
|
try {
|
|
const locationId = params.locationId || this.ghlClient.getConfig().locationId;
|
|
const response = await this.ghlClient.validateCalendarGroupSlug(params.slug, locationId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
available: response.data.available,
|
|
message: response.data.available ? 'Slug is available' : 'Slug is not available'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to validate group slug: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* UPDATE CALENDAR GROUP
|
|
*/
|
|
private async updateCalendarGroup(params: MCPUpdateCalendarGroupParams): Promise<{ success: boolean; group: any; message: string }> {
|
|
try {
|
|
const { groupId, ...updateData } = params;
|
|
const response = await this.ghlClient.updateCalendarGroup(groupId, updateData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
group: response.data,
|
|
message: 'Calendar group updated successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to update calendar group: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* DELETE CALENDAR GROUP
|
|
*/
|
|
private async deleteCalendarGroup(params: MCPDeleteCalendarGroupParams): Promise<{ success: boolean; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.deleteCalendarGroup(params.groupId);
|
|
|
|
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 group deleted successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to delete calendar group: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* DISABLE CALENDAR GROUP
|
|
*/
|
|
private async disableCalendarGroup(params: MCPDisableCalendarGroupParams): Promise<{ success: boolean; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.disableCalendarGroup(params.groupId, params.isActive);
|
|
|
|
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 group ${params.isActive ? 'enabled' : 'disabled'} successfully`
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to disable calendar group: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET APPOINTMENT NOTES
|
|
*/
|
|
private async getAppointmentNotes(params: MCPGetAppointmentNotesParams): Promise<{ success: boolean; notes: any[]; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.getAppointmentNotes(params.appointmentId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
const notes = Array.isArray(response.data.notes) ? response.data.notes : [];
|
|
|
|
return {
|
|
success: true,
|
|
notes,
|
|
message: `Retrieved ${notes.length} appointment notes`
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to get appointment notes: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CREATE APPOINTMENT NOTE
|
|
*/
|
|
private async createAppointmentNote(params: MCPCreateAppointmentNoteParams): Promise<{ success: boolean; note: any; message: string }> {
|
|
try {
|
|
const { appointmentId, ...noteData } = params;
|
|
const response = await this.ghlClient.createAppointmentNote(appointmentId, noteData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
note: response.data,
|
|
message: 'Appointment note created successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to create appointment note: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* UPDATE APPOINTMENT NOTE
|
|
*/
|
|
private async updateAppointmentNote(params: MCPUpdateAppointmentNoteParams): Promise<{ success: boolean; note: any; message: string }> {
|
|
try {
|
|
const { appointmentId, noteId, ...updateData } = params;
|
|
const response = await this.ghlClient.updateAppointmentNote(appointmentId, noteId, updateData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
note: response.data,
|
|
message: 'Appointment note updated successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to update appointment note: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* DELETE APPOINTMENT NOTE
|
|
*/
|
|
private async deleteAppointmentNote(params: MCPDeleteAppointmentNoteParams): Promise<{ success: boolean; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.deleteAppointmentNote(params.appointmentId, params.noteId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
message: 'Appointment note deleted successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to delete appointment note: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET CALENDAR RESOURCES - EQUIPMENTS
|
|
*/
|
|
private async getCalendarResourcesEquipments(params: MCPGetCalendarResourcesParams): Promise<{ success: boolean; resources: any[]; message: string }> {
|
|
try {
|
|
const locationId = params.locationId || this.ghlClient.getConfig().locationId;
|
|
const response = await this.ghlClient.getCalendarResources('equipments', params.limit, params.skip, locationId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
const resources = Array.isArray(response.data) ? response.data : [];
|
|
|
|
return {
|
|
success: true,
|
|
resources,
|
|
message: `Retrieved ${resources.length} equipment resources`
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to get equipment resources: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CREATE CALENDAR RESOURCE - EQUIPMENT
|
|
*/
|
|
private async createCalendarResourceEquipment(params: MCPCreateCalendarResourceParams): Promise<{ success: boolean; resource: any; message: string }> {
|
|
try {
|
|
const resourceData = {
|
|
...params,
|
|
locationId: params.locationId || this.ghlClient.getConfig().locationId
|
|
};
|
|
const response = await this.ghlClient.createCalendarResource('equipments', resourceData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
resource: response.data,
|
|
message: 'Equipment resource created successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to create equipment resource: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET CALENDAR RESOURCE - EQUIPMENT
|
|
*/
|
|
private async getCalendarResourceEquipment(params: MCPGetCalendarResourceParams): Promise<{ success: boolean; resource: any; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.getCalendarResource('equipments', params.resourceId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
resource: response.data,
|
|
message: 'Equipment resource retrieved successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to get equipment resource: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* UPDATE CALENDAR RESOURCE - EQUIPMENT
|
|
*/
|
|
private async updateCalendarResourceEquipment(params: MCPUpdateCalendarResourceParams): Promise<{ success: boolean; resource: any; message: string }> {
|
|
try {
|
|
const { resourceId, ...updateData } = params;
|
|
const response = await this.ghlClient.updateCalendarResource('equipments', resourceId, updateData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
resource: response.data,
|
|
message: 'Equipment resource updated successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to update equipment resource: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* DELETE CALENDAR RESOURCE - EQUIPMENT
|
|
*/
|
|
private async deleteCalendarResourceEquipment(params: MCPDeleteCalendarResourceParams): Promise<{ success: boolean; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.deleteCalendarResource('equipments', params.resourceId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
message: 'Equipment resource deleted successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to delete equipment resource: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET CALENDAR RESOURCES - ROOMS
|
|
*/
|
|
private async getCalendarResourcesRooms(params: MCPGetCalendarResourcesParams): Promise<{ success: boolean; resources: any[]; message: string }> {
|
|
try {
|
|
const locationId = params.locationId || this.ghlClient.getConfig().locationId;
|
|
const response = await this.ghlClient.getCalendarResources('rooms', params.limit, params.skip, locationId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
const resources = Array.isArray(response.data) ? response.data : [];
|
|
|
|
return {
|
|
success: true,
|
|
resources,
|
|
message: `Retrieved ${resources.length} room resources`
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to get room resources: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CREATE CALENDAR RESOURCE - ROOM
|
|
*/
|
|
private async createCalendarResourceRoom(params: MCPCreateCalendarResourceParams): Promise<{ success: boolean; resource: any; message: string }> {
|
|
try {
|
|
const resourceData = {
|
|
...params,
|
|
locationId: params.locationId || this.ghlClient.getConfig().locationId
|
|
};
|
|
const response = await this.ghlClient.createCalendarResource('rooms', resourceData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
resource: response.data,
|
|
message: 'Room resource created successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to create room resource: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET CALENDAR RESOURCE - ROOM
|
|
*/
|
|
private async getCalendarResourceRoom(params: MCPGetCalendarResourceParams): Promise<{ success: boolean; resource: any; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.getCalendarResource('rooms', params.resourceId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
resource: response.data,
|
|
message: 'Room resource retrieved successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to get room resource: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* UPDATE CALENDAR RESOURCE - ROOM
|
|
*/
|
|
private async updateCalendarResourceRoom(params: MCPUpdateCalendarResourceParams): Promise<{ success: boolean; resource: any; message: string }> {
|
|
try {
|
|
const { resourceId, ...updateData } = params;
|
|
const response = await this.ghlClient.updateCalendarResource('rooms', resourceId, updateData);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
resource: response.data,
|
|
message: 'Room resource updated successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to update room resource: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* DELETE CALENDAR RESOURCE - ROOM
|
|
*/
|
|
private async deleteCalendarResourceRoom(params: MCPDeleteCalendarResourceParams): Promise<{ success: boolean; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.deleteCalendarResource('rooms', params.resourceId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
message: 'Room resource deleted successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to delete room resource: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET CALENDAR NOTIFICATIONS
|
|
*/
|
|
private async getCalendarNotifications(params: MCPGetCalendarNotificationsParams): Promise<{ success: boolean; notifications: any[]; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.getCalendarNotifications(params.calendarId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
const notifications = Array.isArray(response.data) ? response.data : [];
|
|
|
|
return {
|
|
success: true,
|
|
notifications,
|
|
message: `Retrieved ${notifications.length} calendar notifications`
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to get calendar notifications: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* CREATE CALENDAR NOTIFICATIONS
|
|
*/
|
|
private async createCalendarNotifications(params: MCPCreateCalendarNotificationParams): Promise<{ success: boolean; message: string }> {
|
|
try {
|
|
const { calendarId, notifications } = params;
|
|
const response = await this.ghlClient.createCalendarNotifications(calendarId, notifications);
|
|
|
|
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 notifications created successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to create calendar notifications: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET CALENDAR NOTIFICATION
|
|
*/
|
|
private async getCalendarNotification(params: MCPGetCalendarNotificationParams): Promise<{ success: boolean; notification: any; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.getCalendarNotification(params.calendarId, params.notificationId);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
return {
|
|
success: true,
|
|
notification: response.data,
|
|
message: 'Calendar notification retrieved successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to get calendar notification: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* UPDATE CALENDAR NOTIFICATION
|
|
*/
|
|
private async updateCalendarNotification(params: MCPUpdateCalendarNotificationParams): Promise<{ success: boolean; message: string }> {
|
|
try {
|
|
const { calendarId, notificationId, ...updateData } = params;
|
|
const response = await this.ghlClient.updateCalendarNotification(calendarId, notificationId, updateData);
|
|
|
|
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 notification updated successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to update calendar notification: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* DELETE CALENDAR NOTIFICATION
|
|
*/
|
|
private async deleteCalendarNotification(params: MCPDeleteCalendarNotificationParams): Promise<{ success: boolean; message: string }> {
|
|
try {
|
|
const response = await this.ghlClient.deleteCalendarNotification(params.calendarId, params.notificationId);
|
|
|
|
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 notification deleted successfully'
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to delete calendar notification: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* GET BLOCKED SLOTS
|
|
*/
|
|
private async getBlockedSlots(params: MCPGetBlockedSlotsParams): Promise<{ success: boolean; slots: any[]; message: string }> {
|
|
try {
|
|
const eventParams = {
|
|
locationId: this.ghlClient.getConfig().locationId,
|
|
startTime: params.startTime,
|
|
endTime: params.endTime,
|
|
userId: params.userId,
|
|
calendarId: params.calendarId,
|
|
groupId: params.groupId
|
|
};
|
|
|
|
const response = await this.ghlClient.getBlockedSlots(eventParams);
|
|
|
|
if (!response.success || !response.data) {
|
|
const errorMsg = response.error?.message || 'Unknown API error';
|
|
throw new Error(`API request failed: ${errorMsg}`);
|
|
}
|
|
|
|
const slots = Array.isArray(response.data.events) ? response.data.events : [];
|
|
|
|
return {
|
|
success: true,
|
|
slots,
|
|
message: `Retrieved ${slots.length} blocked time slots`
|
|
};
|
|
} catch (error) {
|
|
throw new Error(`Failed to get blocked slots: ${error instanceof Error ? error.message : String(error)}`);
|
|
}
|
|
}
|
|
}
|