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
418 lines
16 KiB
TypeScript
418 lines
16 KiB
TypeScript
/**
|
|
* GoHighLevel Phone System Tools
|
|
* Tools for managing phone numbers, call settings, and IVR
|
|
*/
|
|
|
|
import { GHLApiClient } from '../clients/ghl-api-client.js';
|
|
|
|
export class PhoneTools {
|
|
constructor(private ghlClient: GHLApiClient) {}
|
|
|
|
getToolDefinitions() {
|
|
return [
|
|
// Phone Numbers
|
|
{
|
|
name: 'get_phone_numbers',
|
|
description: 'Get all phone numbers for a location',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
locationId: { type: 'string', description: 'Location ID' }
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'get_phone_number',
|
|
description: 'Get a specific phone number by ID',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
phoneNumberId: { type: 'string', description: 'Phone Number ID' },
|
|
locationId: { type: 'string', description: 'Location ID' }
|
|
},
|
|
required: ['phoneNumberId']
|
|
}
|
|
},
|
|
{
|
|
name: 'search_available_numbers',
|
|
description: 'Search for available phone numbers to purchase',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
locationId: { type: 'string', description: 'Location ID' },
|
|
country: { type: 'string', description: 'Country code (e.g., US, CA)' },
|
|
areaCode: { type: 'string', description: 'Area code to search' },
|
|
contains: { type: 'string', description: 'Number pattern to search for' },
|
|
type: { type: 'string', enum: ['local', 'tollfree', 'mobile'], description: 'Number type' }
|
|
},
|
|
required: ['country']
|
|
}
|
|
},
|
|
{
|
|
name: 'purchase_phone_number',
|
|
description: 'Purchase a phone number',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
locationId: { type: 'string', description: 'Location ID' },
|
|
phoneNumber: { type: 'string', description: 'Phone number to purchase' },
|
|
name: { type: 'string', description: 'Friendly name for the number' }
|
|
},
|
|
required: ['phoneNumber']
|
|
}
|
|
},
|
|
{
|
|
name: 'update_phone_number',
|
|
description: 'Update phone number settings',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
phoneNumberId: { type: 'string', description: 'Phone Number ID' },
|
|
locationId: { type: 'string', description: 'Location ID' },
|
|
name: { type: 'string', description: 'Friendly name' },
|
|
forwardingNumber: { type: 'string', description: 'Number to forward calls to' },
|
|
callRecording: { type: 'boolean', description: 'Enable call recording' },
|
|
whisperMessage: { type: 'string', description: 'Whisper message played to agent' }
|
|
},
|
|
required: ['phoneNumberId']
|
|
}
|
|
},
|
|
{
|
|
name: 'release_phone_number',
|
|
description: 'Release/delete a phone number',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
phoneNumberId: { type: 'string', description: 'Phone Number ID' },
|
|
locationId: { type: 'string', description: 'Location ID' }
|
|
},
|
|
required: ['phoneNumberId']
|
|
}
|
|
},
|
|
|
|
// Call Forwarding
|
|
{
|
|
name: 'get_call_forwarding_settings',
|
|
description: 'Get call forwarding configuration',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
phoneNumberId: { type: 'string', description: 'Phone Number ID' },
|
|
locationId: { type: 'string', description: 'Location ID' }
|
|
},
|
|
required: ['phoneNumberId']
|
|
}
|
|
},
|
|
{
|
|
name: 'update_call_forwarding',
|
|
description: 'Update call forwarding settings',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
phoneNumberId: { type: 'string', description: 'Phone Number ID' },
|
|
locationId: { type: 'string', description: 'Location ID' },
|
|
enabled: { type: 'boolean', description: 'Enable forwarding' },
|
|
forwardTo: { type: 'string', description: 'Number to forward to' },
|
|
ringTimeout: { type: 'number', description: 'Ring timeout in seconds' },
|
|
voicemailEnabled: { type: 'boolean', description: 'Enable voicemail on no answer' }
|
|
},
|
|
required: ['phoneNumberId']
|
|
}
|
|
},
|
|
|
|
// IVR/Call Menu
|
|
{
|
|
name: 'get_ivr_menus',
|
|
description: 'Get all IVR/call menus',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
locationId: { type: 'string', description: 'Location ID' }
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'create_ivr_menu',
|
|
description: 'Create an IVR/call menu',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
locationId: { type: 'string', description: 'Location ID' },
|
|
name: { type: 'string', description: 'Menu name' },
|
|
greeting: { type: 'string', description: 'Greeting message (text or URL)' },
|
|
options: {
|
|
type: 'array',
|
|
items: {
|
|
type: 'object',
|
|
properties: {
|
|
digit: { type: 'string', description: 'Digit to press (0-9, *, #)' },
|
|
action: { type: 'string', description: 'Action type' },
|
|
destination: { type: 'string', description: 'Action destination' }
|
|
}
|
|
},
|
|
description: 'Menu options'
|
|
}
|
|
},
|
|
required: ['name', 'greeting']
|
|
}
|
|
},
|
|
{
|
|
name: 'update_ivr_menu',
|
|
description: 'Update an IVR menu',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
menuId: { type: 'string', description: 'IVR Menu ID' },
|
|
locationId: { type: 'string', description: 'Location ID' },
|
|
name: { type: 'string', description: 'Menu name' },
|
|
greeting: { type: 'string', description: 'Greeting message' },
|
|
options: { type: 'array', description: 'Menu options' }
|
|
},
|
|
required: ['menuId']
|
|
}
|
|
},
|
|
{
|
|
name: 'delete_ivr_menu',
|
|
description: 'Delete an IVR menu',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
menuId: { type: 'string', description: 'IVR Menu ID' },
|
|
locationId: { type: 'string', description: 'Location ID' }
|
|
},
|
|
required: ['menuId']
|
|
}
|
|
},
|
|
|
|
// Voicemail
|
|
{
|
|
name: 'get_voicemail_settings',
|
|
description: 'Get voicemail settings',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
locationId: { type: 'string', description: 'Location ID' }
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'update_voicemail_settings',
|
|
description: 'Update voicemail settings',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
locationId: { type: 'string', description: 'Location ID' },
|
|
enabled: { type: 'boolean', description: 'Enable voicemail' },
|
|
greeting: { type: 'string', description: 'Voicemail greeting (text or URL)' },
|
|
transcriptionEnabled: { type: 'boolean', description: 'Enable transcription' },
|
|
notificationEmail: { type: 'string', description: 'Email for voicemail notifications' }
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'get_voicemails',
|
|
description: 'Get voicemail messages',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
locationId: { type: 'string', description: 'Location ID' },
|
|
phoneNumberId: { type: 'string', description: 'Filter by phone number' },
|
|
status: { type: 'string', enum: ['new', 'read', 'archived'], description: 'Filter by status' },
|
|
limit: { type: 'number', description: 'Max results' },
|
|
offset: { type: 'number', description: 'Pagination offset' }
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'delete_voicemail',
|
|
description: 'Delete a voicemail message',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
voicemailId: { type: 'string', description: 'Voicemail ID' },
|
|
locationId: { type: 'string', description: 'Location ID' }
|
|
},
|
|
required: ['voicemailId']
|
|
}
|
|
},
|
|
|
|
// Caller ID
|
|
{
|
|
name: 'get_caller_ids',
|
|
description: 'Get verified caller IDs',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
locationId: { type: 'string', description: 'Location ID' }
|
|
}
|
|
}
|
|
},
|
|
{
|
|
name: 'add_caller_id',
|
|
description: 'Add a caller ID for verification',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
locationId: { type: 'string', description: 'Location ID' },
|
|
phoneNumber: { type: 'string', description: 'Phone number to verify' },
|
|
name: { type: 'string', description: 'Friendly name' }
|
|
},
|
|
required: ['phoneNumber']
|
|
}
|
|
},
|
|
{
|
|
name: 'verify_caller_id',
|
|
description: 'Submit verification code for caller ID',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
callerIdId: { type: 'string', description: 'Caller ID record ID' },
|
|
locationId: { type: 'string', description: 'Location ID' },
|
|
code: { type: 'string', description: 'Verification code' }
|
|
},
|
|
required: ['callerIdId', 'code']
|
|
}
|
|
},
|
|
{
|
|
name: 'delete_caller_id',
|
|
description: 'Delete a caller ID',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
callerIdId: { type: 'string', description: 'Caller ID record ID' },
|
|
locationId: { type: 'string', description: 'Location ID' }
|
|
},
|
|
required: ['callerIdId']
|
|
}
|
|
}
|
|
];
|
|
}
|
|
|
|
async handleToolCall(toolName: string, args: Record<string, unknown>): Promise<unknown> {
|
|
const config = this.ghlClient.getConfig();
|
|
const locationId = (args.locationId as string) || config.locationId;
|
|
|
|
switch (toolName) {
|
|
// Phone Numbers
|
|
case 'get_phone_numbers': {
|
|
return this.ghlClient.makeRequest('GET', `/phone-numbers/?locationId=${locationId}`);
|
|
}
|
|
case 'get_phone_number': {
|
|
return this.ghlClient.makeRequest('GET', `/phone-numbers/${args.phoneNumberId}?locationId=${locationId}`);
|
|
}
|
|
case 'search_available_numbers': {
|
|
const params = new URLSearchParams();
|
|
params.append('locationId', locationId);
|
|
params.append('country', String(args.country));
|
|
if (args.areaCode) params.append('areaCode', String(args.areaCode));
|
|
if (args.contains) params.append('contains', String(args.contains));
|
|
if (args.type) params.append('type', String(args.type));
|
|
return this.ghlClient.makeRequest('GET', `/phone-numbers/available?${params.toString()}`);
|
|
}
|
|
case 'purchase_phone_number': {
|
|
return this.ghlClient.makeRequest('POST', `/phone-numbers/`, {
|
|
locationId,
|
|
phoneNumber: args.phoneNumber,
|
|
name: args.name
|
|
});
|
|
}
|
|
case 'update_phone_number': {
|
|
const body: Record<string, unknown> = { locationId };
|
|
if (args.name) body.name = args.name;
|
|
if (args.forwardingNumber) body.forwardingNumber = args.forwardingNumber;
|
|
if (args.callRecording !== undefined) body.callRecording = args.callRecording;
|
|
if (args.whisperMessage) body.whisperMessage = args.whisperMessage;
|
|
return this.ghlClient.makeRequest('PUT', `/phone-numbers/${args.phoneNumberId}`, body);
|
|
}
|
|
case 'release_phone_number': {
|
|
return this.ghlClient.makeRequest('DELETE', `/phone-numbers/${args.phoneNumberId}?locationId=${locationId}`);
|
|
}
|
|
|
|
// Call Forwarding
|
|
case 'get_call_forwarding_settings': {
|
|
return this.ghlClient.makeRequest('GET', `/phone-numbers/${args.phoneNumberId}/forwarding?locationId=${locationId}`);
|
|
}
|
|
case 'update_call_forwarding': {
|
|
const body: Record<string, unknown> = { locationId };
|
|
if (args.enabled !== undefined) body.enabled = args.enabled;
|
|
if (args.forwardTo) body.forwardTo = args.forwardTo;
|
|
if (args.ringTimeout) body.ringTimeout = args.ringTimeout;
|
|
if (args.voicemailEnabled !== undefined) body.voicemailEnabled = args.voicemailEnabled;
|
|
return this.ghlClient.makeRequest('PUT', `/phone-numbers/${args.phoneNumberId}/forwarding`, body);
|
|
}
|
|
|
|
// IVR
|
|
case 'get_ivr_menus': {
|
|
return this.ghlClient.makeRequest('GET', `/phone-numbers/ivr?locationId=${locationId}`);
|
|
}
|
|
case 'create_ivr_menu': {
|
|
return this.ghlClient.makeRequest('POST', `/phone-numbers/ivr`, {
|
|
locationId,
|
|
name: args.name,
|
|
greeting: args.greeting,
|
|
options: args.options
|
|
});
|
|
}
|
|
case 'update_ivr_menu': {
|
|
const body: Record<string, unknown> = { locationId };
|
|
if (args.name) body.name = args.name;
|
|
if (args.greeting) body.greeting = args.greeting;
|
|
if (args.options) body.options = args.options;
|
|
return this.ghlClient.makeRequest('PUT', `/phone-numbers/ivr/${args.menuId}`, body);
|
|
}
|
|
case 'delete_ivr_menu': {
|
|
return this.ghlClient.makeRequest('DELETE', `/phone-numbers/ivr/${args.menuId}?locationId=${locationId}`);
|
|
}
|
|
|
|
// Voicemail
|
|
case 'get_voicemail_settings': {
|
|
return this.ghlClient.makeRequest('GET', `/phone-numbers/voicemail/settings?locationId=${locationId}`);
|
|
}
|
|
case 'update_voicemail_settings': {
|
|
const body: Record<string, unknown> = { locationId };
|
|
if (args.enabled !== undefined) body.enabled = args.enabled;
|
|
if (args.greeting) body.greeting = args.greeting;
|
|
if (args.transcriptionEnabled !== undefined) body.transcriptionEnabled = args.transcriptionEnabled;
|
|
if (args.notificationEmail) body.notificationEmail = args.notificationEmail;
|
|
return this.ghlClient.makeRequest('PUT', `/phone-numbers/voicemail/settings`, body);
|
|
}
|
|
case 'get_voicemails': {
|
|
const params = new URLSearchParams();
|
|
params.append('locationId', locationId);
|
|
if (args.phoneNumberId) params.append('phoneNumberId', String(args.phoneNumberId));
|
|
if (args.status) params.append('status', String(args.status));
|
|
if (args.limit) params.append('limit', String(args.limit));
|
|
if (args.offset) params.append('offset', String(args.offset));
|
|
return this.ghlClient.makeRequest('GET', `/phone-numbers/voicemail?${params.toString()}`);
|
|
}
|
|
case 'delete_voicemail': {
|
|
return this.ghlClient.makeRequest('DELETE', `/phone-numbers/voicemail/${args.voicemailId}?locationId=${locationId}`);
|
|
}
|
|
|
|
// Caller ID
|
|
case 'get_caller_ids': {
|
|
return this.ghlClient.makeRequest('GET', `/phone-numbers/caller-id?locationId=${locationId}`);
|
|
}
|
|
case 'add_caller_id': {
|
|
return this.ghlClient.makeRequest('POST', `/phone-numbers/caller-id`, {
|
|
locationId,
|
|
phoneNumber: args.phoneNumber,
|
|
name: args.name
|
|
});
|
|
}
|
|
case 'verify_caller_id': {
|
|
return this.ghlClient.makeRequest('POST', `/phone-numbers/caller-id/${args.callerIdId}/verify`, {
|
|
locationId,
|
|
code: args.code
|
|
});
|
|
}
|
|
case 'delete_caller_id': {
|
|
return this.ghlClient.makeRequest('DELETE', `/phone-numbers/caller-id/${args.callerIdId}?locationId=${locationId}`);
|
|
}
|
|
|
|
default:
|
|
throw new Error(`Unknown tool: ${toolName}`);
|
|
}
|
|
}
|
|
}
|