Add all 11 MCP Apps with proper _meta.ui.resourceUri
- Fixed UI build path to dist/app-ui/ - Added _meta.ui.resourceUri to all 11 tool definitions - Changed MIME type to text/html;profile=mcp-app - Added resources capability and handlers (ListResourcesRequestSchema, ReadResourceRequestSchema) - Apps: contact-grid, pipeline-board, quick-book, opportunity-card, calendar-view, invoice-preview, campaign-stats, agent-stats, contact-timeline, workflow-status, dashboard Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
69db02d7cf
commit
19b03fe777
750
src/apps/index.ts
Normal file
750
src/apps/index.ts
Normal file
@ -0,0 +1,750 @@
|
||||
/**
|
||||
* MCP Apps Manager
|
||||
* Manages rich UI components for GoHighLevel MCP Server
|
||||
*/
|
||||
|
||||
import { Tool } from '@modelcontextprotocol/sdk/types.js';
|
||||
import { GHLApiClient } from '../clients/ghl-api-client.js';
|
||||
import * as fs from 'fs';
|
||||
import * as path from 'path';
|
||||
import { fileURLToPath } from 'url';
|
||||
|
||||
export interface AppToolResult {
|
||||
content: Array<{ type: 'text'; text: string }>;
|
||||
structuredContent?: {
|
||||
type: 'resource';
|
||||
resource: {
|
||||
uri: string;
|
||||
mimeType: string;
|
||||
text?: string;
|
||||
blob?: string;
|
||||
};
|
||||
};
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface AppResourceHandler {
|
||||
uri: string;
|
||||
mimeType: string;
|
||||
getContent: () => string;
|
||||
}
|
||||
|
||||
/**
|
||||
* MCP Apps Manager class
|
||||
* Registers app tools and handles structuredContent responses
|
||||
*/
|
||||
// Note: We use process.cwd() based path resolution to find UI dist
|
||||
// This works when running from the project root directory
|
||||
function getUIBuildPath(): string {
|
||||
// First try dist/app-ui (where MCP Apps are built)
|
||||
const appUiPath = path.join(process.cwd(), 'dist', 'app-ui');
|
||||
if (fs.existsSync(appUiPath)) {
|
||||
return appUiPath;
|
||||
}
|
||||
// Fallback to src/ui/dist for legacy UI components
|
||||
const fromCwd = path.join(process.cwd(), 'src', 'ui', 'dist');
|
||||
if (fs.existsSync(fromCwd)) {
|
||||
return fromCwd;
|
||||
}
|
||||
// Default fallback
|
||||
return appUiPath;
|
||||
}
|
||||
|
||||
export class MCPAppsManager {
|
||||
private ghlClient: GHLApiClient;
|
||||
private resourceHandlers: Map<string, AppResourceHandler> = new Map();
|
||||
private uiBuildPath: string;
|
||||
|
||||
constructor(ghlClient: GHLApiClient) {
|
||||
this.ghlClient = ghlClient;
|
||||
this.uiBuildPath = getUIBuildPath();
|
||||
process.stderr.write(`[MCP Apps] UI build path: ${this.uiBuildPath}\n`);
|
||||
this.registerResourceHandlers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register all UI resource handlers
|
||||
*/
|
||||
private registerResourceHandlers(): void {
|
||||
const resources: Array<{ uri: string; file: string }> = [
|
||||
// All 11 MCP Apps
|
||||
{ uri: 'ui://ghl/mcp-app', file: 'mcp-app.html' },
|
||||
{ uri: 'ui://ghl/pipeline-board', file: 'pipeline-board.html' },
|
||||
{ uri: 'ui://ghl/quick-book', file: 'quick-book.html' },
|
||||
{ uri: 'ui://ghl/opportunity-card', file: 'opportunity-card.html' },
|
||||
{ uri: 'ui://ghl/contact-grid', file: 'contact-grid.html' },
|
||||
{ uri: 'ui://ghl/calendar-view', file: 'calendar-view.html' },
|
||||
{ uri: 'ui://ghl/invoice-preview', file: 'invoice-preview.html' },
|
||||
{ uri: 'ui://ghl/campaign-stats', file: 'campaign-stats.html' },
|
||||
{ uri: 'ui://ghl/agent-stats', file: 'agent-stats.html' },
|
||||
{ uri: 'ui://ghl/contact-timeline', file: 'contact-timeline.html' },
|
||||
{ uri: 'ui://ghl/workflow-status', file: 'workflow-status.html' },
|
||||
];
|
||||
|
||||
for (const resource of resources) {
|
||||
this.resourceHandlers.set(resource.uri, {
|
||||
uri: resource.uri,
|
||||
mimeType: 'text/html;profile=mcp-app',
|
||||
getContent: () => this.loadUIResource(resource.file),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load UI resource from build directory
|
||||
*/
|
||||
private loadUIResource(filename: string): string {
|
||||
const filePath = path.join(this.uiBuildPath, filename);
|
||||
try {
|
||||
return fs.readFileSync(filePath, 'utf-8');
|
||||
} catch (error) {
|
||||
process.stderr.write(`[MCP Apps] UI resource not found: ${filePath}\n`);
|
||||
return this.getFallbackHTML(filename);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate fallback HTML when UI resource is not built
|
||||
*/
|
||||
private getFallbackHTML(filename: string): string {
|
||||
const componentName = filename.replace('.html', '');
|
||||
return `
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>GHL ${componentName}</title>
|
||||
<style>
|
||||
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; padding: 20px; }
|
||||
.fallback { text-align: center; color: #666; }
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="fallback">
|
||||
<p>UI component "${componentName}" is loading...</p>
|
||||
<p>Run <code>npm run build:ui</code> to build UI components.</p>
|
||||
</div>
|
||||
<script>
|
||||
window.addEventListener('message', (e) => {
|
||||
if (e.data?.type === 'mcp-app-init') {
|
||||
console.log('MCP App data:', e.data.data);
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
`.trim();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get tool definitions for all app tools
|
||||
*/
|
||||
getToolDefinitions(): Tool[] {
|
||||
return [
|
||||
// 1. Contact Grid - search and display contacts
|
||||
{
|
||||
name: 'view_contact_grid',
|
||||
description: 'Display contact search results in a data grid with sorting and pagination. Returns a visual UI component.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
query: { type: 'string', description: 'Search query string' },
|
||||
limit: { type: 'number', description: 'Maximum results (default: 25)' }
|
||||
}
|
||||
},
|
||||
_meta: {
|
||||
ui: { resourceUri: 'ui://ghl/contact-grid' }
|
||||
}
|
||||
},
|
||||
// 2. Pipeline Board - Kanban view of opportunities
|
||||
{
|
||||
name: 'view_pipeline_board',
|
||||
description: 'Display a pipeline as an interactive Kanban board with opportunities. Returns a visual UI component.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
pipelineId: { type: 'string', description: 'Pipeline ID to display' }
|
||||
},
|
||||
required: ['pipelineId']
|
||||
},
|
||||
_meta: {
|
||||
ui: { resourceUri: 'ui://ghl/pipeline-board' }
|
||||
}
|
||||
},
|
||||
// 3. Quick Book - appointment booking
|
||||
{
|
||||
name: 'view_quick_book',
|
||||
description: 'Display a quick booking interface for scheduling appointments. Returns a visual UI component.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
calendarId: { type: 'string', description: 'Calendar ID for booking' },
|
||||
contactId: { type: 'string', description: 'Optional contact ID to pre-fill' }
|
||||
},
|
||||
required: ['calendarId']
|
||||
},
|
||||
_meta: {
|
||||
ui: { resourceUri: 'ui://ghl/quick-book' }
|
||||
}
|
||||
},
|
||||
// 4. Opportunity Card - single opportunity details
|
||||
{
|
||||
name: 'view_opportunity_card',
|
||||
description: 'Display a single opportunity with details, value, and stage info. Returns a visual UI component.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
opportunityId: { type: 'string', description: 'Opportunity ID to display' }
|
||||
},
|
||||
required: ['opportunityId']
|
||||
},
|
||||
_meta: {
|
||||
ui: { resourceUri: 'ui://ghl/opportunity-card' }
|
||||
}
|
||||
},
|
||||
// 5. Calendar View - calendar with events
|
||||
{
|
||||
name: 'view_calendar',
|
||||
description: 'Display a calendar with events and appointments. Returns a visual UI component.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
calendarId: { type: 'string', description: 'Calendar ID to display' },
|
||||
startDate: { type: 'string', description: 'Start date (ISO format)' },
|
||||
endDate: { type: 'string', description: 'End date (ISO format)' }
|
||||
},
|
||||
required: ['calendarId']
|
||||
},
|
||||
_meta: {
|
||||
ui: { resourceUri: 'ui://ghl/calendar-view' }
|
||||
}
|
||||
},
|
||||
// 6. Invoice Preview - invoice details
|
||||
{
|
||||
name: 'view_invoice',
|
||||
description: 'Display an invoice preview with line items and payment status. Returns a visual UI component.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
invoiceId: { type: 'string', description: 'Invoice ID to display' }
|
||||
},
|
||||
required: ['invoiceId']
|
||||
},
|
||||
_meta: {
|
||||
ui: { resourceUri: 'ui://ghl/invoice-preview' }
|
||||
}
|
||||
},
|
||||
// 7. Campaign Stats - campaign performance metrics
|
||||
{
|
||||
name: 'view_campaign_stats',
|
||||
description: 'Display campaign statistics and performance metrics. Returns a visual UI component.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
campaignId: { type: 'string', description: 'Campaign ID to display stats for' }
|
||||
},
|
||||
required: ['campaignId']
|
||||
},
|
||||
_meta: {
|
||||
ui: { resourceUri: 'ui://ghl/campaign-stats' }
|
||||
}
|
||||
},
|
||||
// 8. Agent Stats - agent/user performance
|
||||
{
|
||||
name: 'view_agent_stats',
|
||||
description: 'Display agent/user performance statistics and metrics. Returns a visual UI component.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
userId: { type: 'string', description: 'User/Agent ID to display stats for' },
|
||||
dateRange: { type: 'string', description: 'Date range (e.g., "last7days", "last30days")' }
|
||||
}
|
||||
},
|
||||
_meta: {
|
||||
ui: { resourceUri: 'ui://ghl/agent-stats' }
|
||||
}
|
||||
},
|
||||
// 9. Contact Timeline - activity history for a contact
|
||||
{
|
||||
name: 'view_contact_timeline',
|
||||
description: 'Display a contact\'s activity timeline with all interactions. Returns a visual UI component.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
contactId: { type: 'string', description: 'Contact ID to display timeline for' }
|
||||
},
|
||||
required: ['contactId']
|
||||
},
|
||||
_meta: {
|
||||
ui: { resourceUri: 'ui://ghl/contact-timeline' }
|
||||
}
|
||||
},
|
||||
// 10. Workflow Status - workflow execution status
|
||||
{
|
||||
name: 'view_workflow_status',
|
||||
description: 'Display workflow execution status and history. Returns a visual UI component.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {
|
||||
workflowId: { type: 'string', description: 'Workflow ID to display status for' }
|
||||
},
|
||||
required: ['workflowId']
|
||||
},
|
||||
_meta: {
|
||||
ui: { resourceUri: 'ui://ghl/workflow-status' }
|
||||
}
|
||||
},
|
||||
// 11. MCP App - generic/main dashboard
|
||||
{
|
||||
name: 'view_dashboard',
|
||||
description: 'Display the main GHL dashboard overview. Returns a visual UI component.',
|
||||
inputSchema: {
|
||||
type: 'object',
|
||||
properties: {}
|
||||
},
|
||||
_meta: {
|
||||
ui: { resourceUri: 'ui://ghl/mcp-app' }
|
||||
}
|
||||
}
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get app tool names for routing
|
||||
*/
|
||||
getAppToolNames(): string[] {
|
||||
return [
|
||||
'view_contact_grid',
|
||||
'view_pipeline_board',
|
||||
'view_quick_book',
|
||||
'view_opportunity_card',
|
||||
'view_calendar',
|
||||
'view_invoice',
|
||||
'view_campaign_stats',
|
||||
'view_agent_stats',
|
||||
'view_contact_timeline',
|
||||
'view_workflow_status',
|
||||
'view_dashboard'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a tool is an app tool
|
||||
*/
|
||||
isAppTool(toolName: string): boolean {
|
||||
return this.getAppToolNames().includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute an app tool
|
||||
*/
|
||||
async executeTool(toolName: string, args: Record<string, any>): Promise<AppToolResult> {
|
||||
process.stderr.write(`[MCP Apps] Executing app tool: ${toolName}\n`);
|
||||
|
||||
switch (toolName) {
|
||||
case 'view_contact_grid':
|
||||
return await this.viewContactGrid(args.query, args.limit);
|
||||
case 'view_pipeline_board':
|
||||
return await this.viewPipelineBoard(args.pipelineId);
|
||||
case 'view_quick_book':
|
||||
return await this.viewQuickBook(args.calendarId, args.contactId);
|
||||
case 'view_opportunity_card':
|
||||
return await this.viewOpportunityCard(args.opportunityId);
|
||||
case 'view_calendar':
|
||||
return await this.viewCalendar(args.calendarId, args.startDate, args.endDate);
|
||||
case 'view_invoice':
|
||||
return await this.viewInvoice(args.invoiceId);
|
||||
case 'view_campaign_stats':
|
||||
return await this.viewCampaignStats(args.campaignId);
|
||||
case 'view_agent_stats':
|
||||
return await this.viewAgentStats(args.userId, args.dateRange);
|
||||
case 'view_contact_timeline':
|
||||
return await this.viewContactTimeline(args.contactId);
|
||||
case 'view_workflow_status':
|
||||
return await this.viewWorkflowStatus(args.workflowId);
|
||||
case 'view_dashboard':
|
||||
return await this.viewDashboard();
|
||||
default:
|
||||
throw new Error(`Unknown app tool: ${toolName}`);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* View contact grid (search results)
|
||||
*/
|
||||
private async viewContactGrid(query?: string, limit?: number): Promise<AppToolResult> {
|
||||
const response = await this.ghlClient.searchContacts({
|
||||
locationId: this.ghlClient.getConfig().locationId,
|
||||
query: query,
|
||||
limit: limit || 25
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
throw new Error(response.error?.message || 'Failed to search contacts');
|
||||
}
|
||||
|
||||
const data = response.data;
|
||||
const resourceHandler = this.resourceHandlers.get('ui://ghl/contact-grid')!;
|
||||
|
||||
return this.createAppResult(
|
||||
`Found ${data?.contacts?.length || 0} contacts`,
|
||||
resourceHandler.uri,
|
||||
resourceHandler.mimeType,
|
||||
resourceHandler.getContent(),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View pipeline board (Kanban)
|
||||
*/
|
||||
private async viewPipelineBoard(pipelineId: string): Promise<AppToolResult> {
|
||||
const [pipelinesResponse, opportunitiesResponse] = await Promise.all([
|
||||
this.ghlClient.getPipelines(),
|
||||
this.ghlClient.searchOpportunities({
|
||||
location_id: this.ghlClient.getConfig().locationId,
|
||||
pipeline_id: pipelineId
|
||||
})
|
||||
]);
|
||||
|
||||
if (!pipelinesResponse.success) {
|
||||
throw new Error(pipelinesResponse.error?.message || 'Failed to get pipeline');
|
||||
}
|
||||
|
||||
const pipeline = pipelinesResponse.data?.pipelines?.find((p: any) => p.id === pipelineId);
|
||||
const opportunities = opportunitiesResponse.data?.opportunities || [];
|
||||
|
||||
const data = {
|
||||
pipeline,
|
||||
opportunities,
|
||||
stages: pipeline?.stages || []
|
||||
};
|
||||
|
||||
const resourceHandler = this.resourceHandlers.get('ui://ghl/pipeline-board')!;
|
||||
|
||||
return this.createAppResult(
|
||||
`Pipeline: ${pipeline?.name || 'Unknown'} (${opportunities.length} opportunities)`,
|
||||
resourceHandler.uri,
|
||||
resourceHandler.mimeType,
|
||||
resourceHandler.getContent(),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View quick book interface
|
||||
*/
|
||||
private async viewQuickBook(calendarId: string, contactId?: string): Promise<AppToolResult> {
|
||||
const [calendarResponse, contactResponse] = await Promise.all([
|
||||
this.ghlClient.getCalendar(calendarId),
|
||||
contactId ? this.ghlClient.getContact(contactId) : Promise.resolve({ success: true, data: null })
|
||||
]);
|
||||
|
||||
if (!calendarResponse.success) {
|
||||
throw new Error(calendarResponse.error?.message || 'Failed to get calendar');
|
||||
}
|
||||
|
||||
const data = {
|
||||
calendar: calendarResponse.data,
|
||||
contact: contactResponse.data,
|
||||
locationId: this.ghlClient.getConfig().locationId
|
||||
};
|
||||
|
||||
const resourceHandler = this.resourceHandlers.get('ui://ghl/quick-book')!;
|
||||
|
||||
return this.createAppResult(
|
||||
`Quick booking for calendar: ${(calendarResponse.data as any)?.name || calendarId}`,
|
||||
resourceHandler.uri,
|
||||
resourceHandler.mimeType,
|
||||
resourceHandler.getContent(),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View opportunity card
|
||||
*/
|
||||
private async viewOpportunityCard(opportunityId: string): Promise<AppToolResult> {
|
||||
const response = await this.ghlClient.getOpportunity(opportunityId);
|
||||
|
||||
if (!response.success) {
|
||||
throw new Error(response.error?.message || 'Failed to get opportunity');
|
||||
}
|
||||
|
||||
const opportunity = response.data;
|
||||
const resourceHandler = this.resourceHandlers.get('ui://ghl/opportunity-card')!;
|
||||
|
||||
return this.createAppResult(
|
||||
`Opportunity: ${(opportunity as any)?.name || opportunityId}`,
|
||||
resourceHandler.uri,
|
||||
resourceHandler.mimeType,
|
||||
resourceHandler.getContent(),
|
||||
opportunity
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View calendar
|
||||
*/
|
||||
private async viewCalendar(calendarId: string, startDate?: string, endDate?: string): Promise<AppToolResult> {
|
||||
const now = new Date();
|
||||
const start = startDate || new Date(now.getFullYear(), now.getMonth(), 1).toISOString();
|
||||
const end = endDate || new Date(now.getFullYear(), now.getMonth() + 1, 0).toISOString();
|
||||
|
||||
const [calendarResponse, eventsResponse] = await Promise.all([
|
||||
this.ghlClient.getCalendar(calendarId),
|
||||
this.ghlClient.getCalendarEvents({
|
||||
calendarId: calendarId,
|
||||
startTime: start,
|
||||
endTime: end,
|
||||
locationId: this.ghlClient.getConfig().locationId
|
||||
})
|
||||
]);
|
||||
|
||||
if (!calendarResponse.success) {
|
||||
throw new Error(calendarResponse.error?.message || 'Failed to get calendar');
|
||||
}
|
||||
|
||||
const calendar = calendarResponse.data as any;
|
||||
const data = {
|
||||
calendar: calendarResponse.data,
|
||||
events: eventsResponse.data?.events || [],
|
||||
startDate: start,
|
||||
endDate: end
|
||||
};
|
||||
|
||||
const resourceHandler = this.resourceHandlers.get('ui://ghl/calendar-view')!;
|
||||
|
||||
return this.createAppResult(
|
||||
`Calendar: ${calendar?.name || 'Unknown'} (${data.events.length} events)`,
|
||||
resourceHandler.uri,
|
||||
resourceHandler.mimeType,
|
||||
resourceHandler.getContent(),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View campaign stats
|
||||
*/
|
||||
private async viewCampaignStats(campaignId: string): Promise<AppToolResult> {
|
||||
// Get email campaigns
|
||||
const response = await this.ghlClient.getEmailCampaigns({});
|
||||
|
||||
const campaigns = response.data?.schedules || [];
|
||||
const campaign = campaigns.find((c: any) => c.id === campaignId) || { id: campaignId };
|
||||
|
||||
const data = {
|
||||
campaign,
|
||||
campaigns,
|
||||
campaignId,
|
||||
locationId: this.ghlClient.getConfig().locationId
|
||||
};
|
||||
|
||||
const resourceHandler = this.resourceHandlers.get('ui://ghl/campaign-stats')!;
|
||||
|
||||
return this.createAppResult(
|
||||
`Campaign stats: ${(campaign as any)?.name || campaignId}`,
|
||||
resourceHandler.uri,
|
||||
resourceHandler.mimeType,
|
||||
resourceHandler.getContent(),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View agent stats
|
||||
*/
|
||||
private async viewAgentStats(userId?: string, dateRange?: string): Promise<AppToolResult> {
|
||||
// Get location info which may include user data
|
||||
const locationResponse = await this.ghlClient.getLocationById(this.ghlClient.getConfig().locationId);
|
||||
|
||||
const data = {
|
||||
userId,
|
||||
dateRange: dateRange || 'last30days',
|
||||
location: locationResponse.data,
|
||||
locationId: this.ghlClient.getConfig().locationId
|
||||
};
|
||||
|
||||
const resourceHandler = this.resourceHandlers.get('ui://ghl/agent-stats')!;
|
||||
|
||||
return this.createAppResult(
|
||||
userId ? `Agent stats: ${userId}` : 'Agent overview',
|
||||
resourceHandler.uri,
|
||||
resourceHandler.mimeType,
|
||||
resourceHandler.getContent(),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View contact timeline
|
||||
*/
|
||||
private async viewContactTimeline(contactId: string): Promise<AppToolResult> {
|
||||
const [contactResponse, notesResponse, tasksResponse] = await Promise.all([
|
||||
this.ghlClient.getContact(contactId),
|
||||
this.ghlClient.getContactNotes(contactId),
|
||||
this.ghlClient.getContactTasks(contactId)
|
||||
]);
|
||||
|
||||
if (!contactResponse.success) {
|
||||
throw new Error(contactResponse.error?.message || 'Failed to get contact');
|
||||
}
|
||||
|
||||
const contact = contactResponse.data as any;
|
||||
const data = {
|
||||
contact: contactResponse.data,
|
||||
notes: notesResponse.data || [],
|
||||
tasks: tasksResponse.data || []
|
||||
};
|
||||
|
||||
const resourceHandler = this.resourceHandlers.get('ui://ghl/contact-timeline')!;
|
||||
|
||||
return this.createAppResult(
|
||||
`Timeline for ${contact?.firstName || ''} ${contact?.lastName || ''}`,
|
||||
resourceHandler.uri,
|
||||
resourceHandler.mimeType,
|
||||
resourceHandler.getContent(),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View workflow status
|
||||
*/
|
||||
private async viewWorkflowStatus(workflowId: string): Promise<AppToolResult> {
|
||||
const response = await this.ghlClient.getWorkflows({
|
||||
locationId: this.ghlClient.getConfig().locationId
|
||||
});
|
||||
|
||||
const workflows = response.data?.workflows || [];
|
||||
const workflow = workflows.find((w: any) => w.id === workflowId) || { id: workflowId };
|
||||
|
||||
const data = {
|
||||
workflow,
|
||||
workflows,
|
||||
workflowId,
|
||||
locationId: this.ghlClient.getConfig().locationId
|
||||
};
|
||||
|
||||
const resourceHandler = this.resourceHandlers.get('ui://ghl/workflow-status')!;
|
||||
|
||||
return this.createAppResult(
|
||||
`Workflow: ${(workflow as any)?.name || workflowId}`,
|
||||
resourceHandler.uri,
|
||||
resourceHandler.mimeType,
|
||||
resourceHandler.getContent(),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View main dashboard
|
||||
*/
|
||||
private async viewDashboard(): Promise<AppToolResult> {
|
||||
const [contactsResponse, pipelinesResponse, calendarsResponse] = await Promise.all([
|
||||
this.ghlClient.searchContacts({ locationId: this.ghlClient.getConfig().locationId, limit: 10 }),
|
||||
this.ghlClient.getPipelines(),
|
||||
this.ghlClient.getCalendars()
|
||||
]);
|
||||
|
||||
const data = {
|
||||
recentContacts: contactsResponse.data?.contacts || [],
|
||||
pipelines: pipelinesResponse.data?.pipelines || [],
|
||||
calendars: calendarsResponse.data?.calendars || [],
|
||||
locationId: this.ghlClient.getConfig().locationId
|
||||
};
|
||||
|
||||
const resourceHandler = this.resourceHandlers.get('ui://ghl/mcp-app')!;
|
||||
|
||||
return this.createAppResult(
|
||||
'GHL Dashboard Overview',
|
||||
resourceHandler.uri,
|
||||
resourceHandler.mimeType,
|
||||
resourceHandler.getContent(),
|
||||
data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* View invoice
|
||||
*/
|
||||
private async viewInvoice(invoiceId: string): Promise<AppToolResult> {
|
||||
const response = await this.ghlClient.getInvoice(invoiceId, {
|
||||
altId: this.ghlClient.getConfig().locationId,
|
||||
altType: 'location'
|
||||
});
|
||||
|
||||
if (!response.success) {
|
||||
throw new Error(response.error?.message || 'Failed to get invoice');
|
||||
}
|
||||
|
||||
const invoice = response.data;
|
||||
const resourceHandler = this.resourceHandlers.get('ui://ghl/invoice-preview')!;
|
||||
|
||||
return this.createAppResult(
|
||||
`Invoice #${invoice?.invoiceNumber || invoiceId} - ${invoice?.status || 'Unknown status'}`,
|
||||
resourceHandler.uri,
|
||||
resourceHandler.mimeType,
|
||||
resourceHandler.getContent(),
|
||||
invoice
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create app tool result with structuredContent
|
||||
*/
|
||||
private createAppResult(
|
||||
textSummary: string,
|
||||
resourceUri: string,
|
||||
mimeType: string,
|
||||
htmlContent: string,
|
||||
data: any
|
||||
): AppToolResult {
|
||||
// Inject the data into the HTML
|
||||
const htmlWithData = this.injectDataIntoHTML(htmlContent, data);
|
||||
|
||||
return {
|
||||
content: [{ type: 'text', text: textSummary }],
|
||||
structuredContent: {
|
||||
type: 'resource',
|
||||
resource: {
|
||||
uri: resourceUri,
|
||||
mimeType: mimeType,
|
||||
text: htmlWithData
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Inject data into HTML as a script tag
|
||||
*/
|
||||
private injectDataIntoHTML(html: string, data: any): string {
|
||||
const dataScript = `<script>window.__MCP_APP_DATA__ = ${JSON.stringify(data)};</script>`;
|
||||
|
||||
// Insert before </head> or at the beginning of <body>
|
||||
if (html.includes('</head>')) {
|
||||
return html.replace('</head>', `${dataScript}</head>`);
|
||||
} else if (html.includes('<body>')) {
|
||||
return html.replace('<body>', `<body>${dataScript}`);
|
||||
} else {
|
||||
return dataScript + html;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get resource handler by URI
|
||||
*/
|
||||
getResourceHandler(uri: string): AppResourceHandler | undefined {
|
||||
return this.resourceHandlers.get(uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all registered resource URIs
|
||||
*/
|
||||
getResourceURIs(): string[] {
|
||||
return Array.from(this.resourceHandlers.keys());
|
||||
}
|
||||
}
|
||||
442
src/server.ts
442
src/server.ts
@ -5,11 +5,13 @@
|
||||
|
||||
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
||||
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
||||
import {
|
||||
import {
|
||||
CallToolRequestSchema,
|
||||
ErrorCode,
|
||||
ListToolsRequestSchema,
|
||||
McpError
|
||||
ListResourcesRequestSchema,
|
||||
ReadResourceRequestSchema,
|
||||
McpError
|
||||
} from '@modelcontextprotocol/sdk/types.js';
|
||||
import * as dotenv from 'dotenv';
|
||||
|
||||
@ -34,6 +36,28 @@ import { GHLConfig } from './types/ghl-types';
|
||||
import { ProductsTools } from './tools/products-tools.js';
|
||||
import { PaymentsTools } from './tools/payments-tools.js';
|
||||
import { InvoicesTools } from './tools/invoices-tools.js';
|
||||
// New tools
|
||||
import { FormsTools } from './tools/forms-tools.js';
|
||||
import { UsersTools } from './tools/users-tools.js';
|
||||
import { FunnelsTools } from './tools/funnels-tools.js';
|
||||
import { BusinessesTools } from './tools/businesses-tools.js';
|
||||
import { LinksTools } from './tools/links-tools.js';
|
||||
import { CompaniesTools } from './tools/companies-tools.js';
|
||||
import { SaasTools } from './tools/saas-tools.js';
|
||||
import { SnapshotsTools } from './tools/snapshots-tools.js';
|
||||
// Additional comprehensive tools
|
||||
import { CoursesTools } from './tools/courses-tools.js';
|
||||
import { CampaignsTools } from './tools/campaigns-tools.js';
|
||||
import { ReportingTools } from './tools/reporting-tools.js';
|
||||
import { OAuthTools } from './tools/oauth-tools.js';
|
||||
import { WebhooksTools } from './tools/webhooks-tools.js';
|
||||
import { PhoneTools } from './tools/phone-tools.js';
|
||||
import { ReputationTools } from './tools/reputation-tools.js';
|
||||
import { AffiliatesTools } from './tools/affiliates-tools.js';
|
||||
import { TemplatesTools } from './tools/templates-tools.js';
|
||||
import { SmartListsTools } from './tools/smartlists-tools.js';
|
||||
import { TriggersTools } from './tools/triggers-tools.js';
|
||||
import { MCPAppsManager } from './apps/index.js';
|
||||
|
||||
// Load environment variables
|
||||
dotenv.config();
|
||||
@ -63,6 +87,28 @@ class GHLMCPServer {
|
||||
private productsTools: ProductsTools;
|
||||
private paymentsTools: PaymentsTools;
|
||||
private invoicesTools: InvoicesTools;
|
||||
// New tools
|
||||
private formsTools: FormsTools;
|
||||
private usersTools: UsersTools;
|
||||
private funnelsTools: FunnelsTools;
|
||||
private businessesTools: BusinessesTools;
|
||||
private linksTools: LinksTools;
|
||||
private companiesTools: CompaniesTools;
|
||||
private saasTools: SaasTools;
|
||||
private snapshotsTools: SnapshotsTools;
|
||||
// Additional comprehensive tools
|
||||
private coursesTools: CoursesTools;
|
||||
private campaignsTools: CampaignsTools;
|
||||
private reportingTools: ReportingTools;
|
||||
private oauthTools: OAuthTools;
|
||||
private webhooksTools: WebhooksTools;
|
||||
private phoneTools: PhoneTools;
|
||||
private reputationTools: ReputationTools;
|
||||
private affiliatesTools: AffiliatesTools;
|
||||
private templatesTools: TemplatesTools;
|
||||
private smartListsTools: SmartListsTools;
|
||||
private triggersTools: TriggersTools;
|
||||
private mcpAppsManager: MCPAppsManager;
|
||||
|
||||
constructor() {
|
||||
// Initialize MCP server with capabilities
|
||||
@ -74,6 +120,7 @@ class GHLMCPServer {
|
||||
{
|
||||
capabilities: {
|
||||
tools: {},
|
||||
resources: {},
|
||||
},
|
||||
}
|
||||
);
|
||||
@ -101,6 +148,30 @@ class GHLMCPServer {
|
||||
this.productsTools = new ProductsTools(this.ghlClient);
|
||||
this.paymentsTools = new PaymentsTools(this.ghlClient);
|
||||
this.invoicesTools = new InvoicesTools(this.ghlClient);
|
||||
// New tools
|
||||
this.formsTools = new FormsTools(this.ghlClient);
|
||||
this.usersTools = new UsersTools(this.ghlClient);
|
||||
this.funnelsTools = new FunnelsTools(this.ghlClient);
|
||||
this.businessesTools = new BusinessesTools(this.ghlClient);
|
||||
this.linksTools = new LinksTools(this.ghlClient);
|
||||
this.companiesTools = new CompaniesTools(this.ghlClient);
|
||||
this.saasTools = new SaasTools(this.ghlClient);
|
||||
this.snapshotsTools = new SnapshotsTools(this.ghlClient);
|
||||
// Additional comprehensive tools
|
||||
this.coursesTools = new CoursesTools(this.ghlClient);
|
||||
this.campaignsTools = new CampaignsTools(this.ghlClient);
|
||||
this.reportingTools = new ReportingTools(this.ghlClient);
|
||||
this.oauthTools = new OAuthTools(this.ghlClient);
|
||||
this.webhooksTools = new WebhooksTools(this.ghlClient);
|
||||
this.phoneTools = new PhoneTools(this.ghlClient);
|
||||
this.reputationTools = new ReputationTools(this.ghlClient);
|
||||
this.affiliatesTools = new AffiliatesTools(this.ghlClient);
|
||||
this.templatesTools = new TemplatesTools(this.ghlClient);
|
||||
this.smartListsTools = new SmartListsTools(this.ghlClient);
|
||||
this.triggersTools = new TriggersTools(this.ghlClient);
|
||||
|
||||
// Initialize MCP Apps Manager for rich UI components
|
||||
this.mcpAppsManager = new MCPAppsManager(this.ghlClient);
|
||||
|
||||
// Setup MCP handlers
|
||||
this.setupHandlers();
|
||||
@ -139,6 +210,41 @@ class GHLMCPServer {
|
||||
* Setup MCP request handlers
|
||||
*/
|
||||
private setupHandlers(): void {
|
||||
// Handle list resources requests (for MCP Apps)
|
||||
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
|
||||
process.stderr.write('[GHL MCP] Listing resources...\n');
|
||||
const resourceUris = this.mcpAppsManager.getResourceURIs();
|
||||
return {
|
||||
resources: resourceUris.map(uri => {
|
||||
const handler = this.mcpAppsManager.getResourceHandler(uri);
|
||||
return {
|
||||
uri,
|
||||
name: uri.replace('ui://ghl/', ''),
|
||||
mimeType: handler?.mimeType || 'text/html;profile=mcp-app'
|
||||
};
|
||||
})
|
||||
};
|
||||
});
|
||||
|
||||
// Handle read resource requests (for MCP Apps)
|
||||
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
|
||||
const { uri } = request.params;
|
||||
process.stderr.write(`[GHL MCP] Reading resource: ${uri}\n`);
|
||||
|
||||
const handler = this.mcpAppsManager.getResourceHandler(uri);
|
||||
if (!handler) {
|
||||
throw new McpError(ErrorCode.InvalidRequest, `Resource not found: ${uri}`);
|
||||
}
|
||||
|
||||
return {
|
||||
contents: [{
|
||||
uri,
|
||||
mimeType: handler.mimeType,
|
||||
text: handler.getContent()
|
||||
}]
|
||||
};
|
||||
});
|
||||
|
||||
// Handle list tools requests
|
||||
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
|
||||
process.stderr.write('[GHL MCP] Listing available tools...\n');
|
||||
@ -163,7 +269,29 @@ class GHLMCPServer {
|
||||
const productsToolDefinitions = this.productsTools.getTools();
|
||||
const paymentsToolDefinitions = this.paymentsTools.getTools();
|
||||
const invoicesToolDefinitions = this.invoicesTools.getTools();
|
||||
|
||||
// New tools
|
||||
const formsToolDefinitions = this.formsTools.getToolDefinitions();
|
||||
const usersToolDefinitions = this.usersTools.getToolDefinitions();
|
||||
const funnelsToolDefinitions = this.funnelsTools.getToolDefinitions();
|
||||
const businessesToolDefinitions = this.businessesTools.getToolDefinitions();
|
||||
const linksToolDefinitions = this.linksTools.getToolDefinitions();
|
||||
const companiesToolDefinitions = this.companiesTools.getToolDefinitions();
|
||||
const saasToolDefinitions = this.saasTools.getToolDefinitions();
|
||||
const snapshotsToolDefinitions = this.snapshotsTools.getToolDefinitions();
|
||||
// Additional comprehensive tools
|
||||
const coursesToolDefinitions = this.coursesTools.getToolDefinitions();
|
||||
const campaignsToolDefinitions = this.campaignsTools.getToolDefinitions();
|
||||
const reportingToolDefinitions = this.reportingTools.getToolDefinitions();
|
||||
const oauthToolDefinitions = this.oauthTools.getToolDefinitions();
|
||||
const webhooksToolDefinitions = this.webhooksTools.getToolDefinitions();
|
||||
const phoneToolDefinitions = this.phoneTools.getToolDefinitions();
|
||||
const reputationToolDefinitions = this.reputationTools.getToolDefinitions();
|
||||
const affiliatesToolDefinitions = this.affiliatesTools.getToolDefinitions();
|
||||
const templatesToolDefinitions = this.templatesTools.getToolDefinitions();
|
||||
const smartListsToolDefinitions = this.smartListsTools.getToolDefinitions();
|
||||
const triggersToolDefinitions = this.triggersTools.getToolDefinitions();
|
||||
const appToolDefinitions = this.mcpAppsManager.getToolDefinitions();
|
||||
|
||||
const allTools = [
|
||||
...contactToolDefinitions,
|
||||
...conversationToolDefinitions,
|
||||
@ -183,7 +311,30 @@ class GHLMCPServer {
|
||||
...storeToolDefinitions,
|
||||
...productsToolDefinitions,
|
||||
...paymentsToolDefinitions,
|
||||
...invoicesToolDefinitions
|
||||
...invoicesToolDefinitions,
|
||||
// New tools
|
||||
...formsToolDefinitions,
|
||||
...usersToolDefinitions,
|
||||
...funnelsToolDefinitions,
|
||||
...businessesToolDefinitions,
|
||||
...linksToolDefinitions,
|
||||
...companiesToolDefinitions,
|
||||
...saasToolDefinitions,
|
||||
...snapshotsToolDefinitions,
|
||||
// Additional comprehensive tools
|
||||
...coursesToolDefinitions,
|
||||
...campaignsToolDefinitions,
|
||||
...reportingToolDefinitions,
|
||||
...oauthToolDefinitions,
|
||||
...webhooksToolDefinitions,
|
||||
...phoneToolDefinitions,
|
||||
...reputationToolDefinitions,
|
||||
...affiliatesToolDefinitions,
|
||||
...templatesToolDefinitions,
|
||||
...smartListsToolDefinitions,
|
||||
...triggersToolDefinitions,
|
||||
// MCP Apps (rich UI components)
|
||||
...appToolDefinitions
|
||||
];
|
||||
|
||||
process.stderr.write(`[GHL MCP] Registered ${allTools.length} tools total:\n`);
|
||||
@ -206,7 +357,29 @@ class GHLMCPServer {
|
||||
process.stderr.write(`[GHL MCP] - ${productsToolDefinitions.length} products tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${paymentsToolDefinitions.length} payments tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${invoicesToolDefinitions.length} invoices tools\n`);
|
||||
|
||||
// New tools logging
|
||||
process.stderr.write(`[GHL MCP] - ${formsToolDefinitions.length} forms tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${usersToolDefinitions.length} users tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${funnelsToolDefinitions.length} funnels tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${businessesToolDefinitions.length} businesses tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${linksToolDefinitions.length} links tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${companiesToolDefinitions.length} companies tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${saasToolDefinitions.length} saas tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${snapshotsToolDefinitions.length} snapshots tools\n`);
|
||||
// Additional comprehensive tools logging
|
||||
process.stderr.write(`[GHL MCP] - ${coursesToolDefinitions.length} courses tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${campaignsToolDefinitions.length} campaigns tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${reportingToolDefinitions.length} reporting tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${oauthToolDefinitions.length} oauth tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${webhooksToolDefinitions.length} webhooks tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${phoneToolDefinitions.length} phone tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${reputationToolDefinitions.length} reputation tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${affiliatesToolDefinitions.length} affiliates tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${templatesToolDefinitions.length} templates tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${smartListsToolDefinitions.length} smart lists tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${triggersToolDefinitions.length} triggers tools\n`);
|
||||
process.stderr.write(`[GHL MCP] - ${appToolDefinitions.length} MCP App tools (rich UI)\n`);
|
||||
|
||||
return {
|
||||
tools: allTools
|
||||
};
|
||||
@ -229,6 +402,13 @@ class GHLMCPServer {
|
||||
try {
|
||||
let result: any;
|
||||
|
||||
// Check if this is an MCP App tool (returns structuredContent)
|
||||
if (this.mcpAppsManager.isAppTool(name)) {
|
||||
const appResult = await this.mcpAppsManager.executeTool(name, args || {});
|
||||
process.stderr.write(`[GHL MCP] App tool ${name} executed successfully\n`);
|
||||
return appResult;
|
||||
}
|
||||
|
||||
// Route to appropriate tool handler
|
||||
if (this.isContactTool(name)) {
|
||||
result = await this.contactTools.executeTool(name, args || {});
|
||||
@ -268,6 +448,46 @@ class GHLMCPServer {
|
||||
result = await this.paymentsTools.handleToolCall(name, args || {});
|
||||
} else if (this.isInvoicesTool(name)) {
|
||||
result = await this.invoicesTools.handleToolCall(name, args || {});
|
||||
// New tools
|
||||
} else if (this.isFormsTool(name)) {
|
||||
result = await this.formsTools.handleToolCall(name, args || {});
|
||||
} else if (this.isUsersTool(name)) {
|
||||
result = await this.usersTools.handleToolCall(name, args || {});
|
||||
} else if (this.isFunnelsTool(name)) {
|
||||
result = await this.funnelsTools.handleToolCall(name, args || {});
|
||||
} else if (this.isBusinessesTool(name)) {
|
||||
result = await this.businessesTools.handleToolCall(name, args || {});
|
||||
} else if (this.isLinksTool(name)) {
|
||||
result = await this.linksTools.handleToolCall(name, args || {});
|
||||
} else if (this.isCompaniesTool(name)) {
|
||||
result = await this.companiesTools.handleToolCall(name, args || {});
|
||||
} else if (this.isSaasTool(name)) {
|
||||
result = await this.saasTools.handleToolCall(name, args || {});
|
||||
} else if (this.isSnapshotsTool(name)) {
|
||||
result = await this.snapshotsTools.handleToolCall(name, args || {});
|
||||
// Additional comprehensive tools
|
||||
} else if (this.isCoursesTool(name)) {
|
||||
result = await this.coursesTools.handleToolCall(name, args || {});
|
||||
} else if (this.isCampaignsTool(name)) {
|
||||
result = await this.campaignsTools.handleToolCall(name, args || {});
|
||||
} else if (this.isReportingTool(name)) {
|
||||
result = await this.reportingTools.handleToolCall(name, args || {});
|
||||
} else if (this.isOAuthTool(name)) {
|
||||
result = await this.oauthTools.handleToolCall(name, args || {});
|
||||
} else if (this.isWebhooksTool(name)) {
|
||||
result = await this.webhooksTools.handleToolCall(name, args || {});
|
||||
} else if (this.isPhoneTool(name)) {
|
||||
result = await this.phoneTools.handleToolCall(name, args || {});
|
||||
} else if (this.isReputationTool(name)) {
|
||||
result = await this.reputationTools.handleToolCall(name, args || {});
|
||||
} else if (this.isAffiliatesTool(name)) {
|
||||
result = await this.affiliatesTools.handleToolCall(name, args || {});
|
||||
} else if (this.isTemplatesTool(name)) {
|
||||
result = await this.templatesTools.handleToolCall(name, args || {});
|
||||
} else if (this.isSmartListsTool(name)) {
|
||||
result = await this.smartListsTools.handleToolCall(name, args || {});
|
||||
} else if (this.isTriggersTool(name)) {
|
||||
result = await this.triggersTools.handleToolCall(name, args || {});
|
||||
} else {
|
||||
throw new Error(`Unknown tool: ${name}`);
|
||||
}
|
||||
@ -598,7 +818,219 @@ class GHLMCPServer {
|
||||
return invoicesToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to forms tools
|
||||
*/
|
||||
private isFormsTool(toolName: string): boolean {
|
||||
const formsToolNames = ['get_forms', 'get_form_submissions', 'get_form_by_id'];
|
||||
return formsToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to users tools
|
||||
*/
|
||||
private isUsersTool(toolName: string): boolean {
|
||||
const usersToolNames = ['get_users', 'get_user', 'create_user', 'update_user', 'delete_user', 'search_users'];
|
||||
return usersToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to funnels tools
|
||||
*/
|
||||
private isFunnelsTool(toolName: string): boolean {
|
||||
const funnelsToolNames = [
|
||||
'get_funnels', 'get_funnel', 'get_funnel_pages', 'count_funnel_pages',
|
||||
'create_funnel_redirect', 'update_funnel_redirect', 'delete_funnel_redirect', 'get_funnel_redirects'
|
||||
];
|
||||
return funnelsToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to businesses tools
|
||||
*/
|
||||
private isBusinessesTool(toolName: string): boolean {
|
||||
const businessesToolNames = ['get_businesses', 'get_business', 'create_business', 'update_business', 'delete_business'];
|
||||
return businessesToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to links tools
|
||||
*/
|
||||
private isLinksTool(toolName: string): boolean {
|
||||
const linksToolNames = ['get_links', 'get_link', 'create_link', 'update_link', 'delete_link'];
|
||||
return linksToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to companies tools
|
||||
*/
|
||||
private isCompaniesTool(toolName: string): boolean {
|
||||
const companiesToolNames = ['get_companies', 'get_company', 'create_company', 'update_company', 'delete_company'];
|
||||
return companiesToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to saas tools
|
||||
*/
|
||||
private isSaasTool(toolName: string): boolean {
|
||||
const saasToolNames = [
|
||||
'get_saas_locations', 'get_saas_location', 'update_saas_subscription',
|
||||
'pause_saas_location', 'enable_saas_location', 'rebilling_update'
|
||||
];
|
||||
return saasToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to snapshots tools
|
||||
*/
|
||||
private isSnapshotsTool(toolName: string): boolean {
|
||||
const snapshotsToolNames = [
|
||||
'get_snapshots', 'get_snapshot', 'create_snapshot',
|
||||
'get_snapshot_push_status', 'get_latest_snapshot_push', 'push_snapshot_to_subaccounts'
|
||||
];
|
||||
return snapshotsToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to courses tools
|
||||
*/
|
||||
private isCoursesTool(toolName: string): boolean {
|
||||
const coursesToolNames = [
|
||||
'get_courses', 'get_course', 'create_course', 'update_course', 'delete_course',
|
||||
'publish_course', 'unpublish_course', 'get_course_products', 'get_course_offers',
|
||||
'create_course_offer', 'update_course_offer', 'delete_course_offer',
|
||||
'get_course_instructors', 'add_course_instructor', 'remove_course_instructor',
|
||||
'get_course_categories', 'create_course_category', 'update_course_category', 'delete_course_category',
|
||||
'get_course_lessons', 'get_course_lesson', 'create_course_lesson', 'update_course_lesson', 'delete_course_lesson',
|
||||
'reorder_lessons', 'get_course_students', 'enroll_student', 'unenroll_student',
|
||||
'get_student_progress', 'update_student_progress', 'reset_student_progress',
|
||||
'complete_lesson', 'uncomplete_lesson'
|
||||
];
|
||||
return coursesToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to campaigns tools
|
||||
*/
|
||||
private isCampaignsTool(toolName: string): boolean {
|
||||
const campaignsToolNames = [
|
||||
'get_campaigns', 'get_campaign', 'create_campaign', 'update_campaign', 'delete_campaign',
|
||||
'get_campaign_stats', 'get_campaign_contacts', 'add_campaign_contacts', 'remove_campaign_contacts',
|
||||
'pause_campaign', 'resume_campaign'
|
||||
];
|
||||
return campaignsToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to reporting tools
|
||||
*/
|
||||
private isReportingTool(toolName: string): boolean {
|
||||
const reportingToolNames = [
|
||||
'get_dashboard_stats', 'get_conversion_report', 'get_attribution_report',
|
||||
'get_call_report', 'get_appointment_report', 'get_email_report', 'get_sms_report',
|
||||
'get_pipeline_report', 'get_revenue_report', 'get_ad_report'
|
||||
];
|
||||
return reportingToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to oauth tools
|
||||
*/
|
||||
private isOAuthTool(toolName: string): boolean {
|
||||
const oauthToolNames = [
|
||||
'get_installed_locations', 'get_location_access_token', 'generate_location_token',
|
||||
'refresh_access_token', 'get_oauth_config', 'get_token_info'
|
||||
];
|
||||
return oauthToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to webhooks tools
|
||||
*/
|
||||
private isWebhooksTool(toolName: string): boolean {
|
||||
const webhooksToolNames = [
|
||||
'get_webhooks', 'get_webhook', 'create_webhook', 'update_webhook', 'delete_webhook',
|
||||
'get_webhook_events', 'test_webhook'
|
||||
];
|
||||
return webhooksToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to phone tools
|
||||
*/
|
||||
private isPhoneTool(toolName: string): boolean {
|
||||
const phoneToolNames = [
|
||||
'get_phone_numbers', 'get_phone_number', 'search_available_numbers', 'purchase_phone_number',
|
||||
'update_phone_number', 'release_phone_number', 'get_call_forwarding_settings', 'update_call_forwarding',
|
||||
'get_ivr_menus', 'create_ivr_menu', 'update_ivr_menu', 'delete_ivr_menu',
|
||||
'get_voicemail_settings', 'update_voicemail_settings', 'get_voicemails', 'delete_voicemail',
|
||||
'get_caller_ids', 'add_caller_id', 'verify_caller_id', 'delete_caller_id'
|
||||
];
|
||||
return phoneToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to reputation tools
|
||||
*/
|
||||
private isReputationTool(toolName: string): boolean {
|
||||
const reputationToolNames = [
|
||||
'get_reviews', 'get_review', 'reply_to_review', 'update_review_reply', 'delete_review_reply',
|
||||
'get_review_stats', 'send_review_request', 'get_review_requests',
|
||||
'get_connected_review_platforms', 'connect_google_business', 'disconnect_review_platform',
|
||||
'get_review_links', 'update_review_links', 'get_review_widget_settings', 'update_review_widget_settings'
|
||||
];
|
||||
return reputationToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to affiliates tools
|
||||
*/
|
||||
private isAffiliatesTool(toolName: string): boolean {
|
||||
const affiliatesToolNames = [
|
||||
'get_affiliate_campaigns', 'get_affiliate_campaign', 'create_affiliate_campaign',
|
||||
'update_affiliate_campaign', 'delete_affiliate_campaign',
|
||||
'get_affiliates', 'get_affiliate', 'create_affiliate', 'update_affiliate',
|
||||
'approve_affiliate', 'reject_affiliate', 'delete_affiliate',
|
||||
'get_affiliate_commissions', 'get_affiliate_stats', 'create_payout', 'get_payouts', 'get_referrals'
|
||||
];
|
||||
return affiliatesToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to templates tools
|
||||
*/
|
||||
private isTemplatesTool(toolName: string): boolean {
|
||||
const templatesToolNames = [
|
||||
'get_sms_templates', 'get_sms_template', 'create_sms_template', 'update_sms_template', 'delete_sms_template',
|
||||
'get_voicemail_templates', 'create_voicemail_template', 'delete_voicemail_template',
|
||||
'get_social_templates', 'create_social_template', 'delete_social_template',
|
||||
'get_whatsapp_templates', 'create_whatsapp_template', 'delete_whatsapp_template',
|
||||
'get_snippets', 'create_snippet', 'update_snippet', 'delete_snippet'
|
||||
];
|
||||
return templatesToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to smart lists tools
|
||||
*/
|
||||
private isSmartListsTool(toolName: string): boolean {
|
||||
const smartListsToolNames = [
|
||||
'get_smart_lists', 'get_smart_list', 'create_smart_list', 'update_smart_list', 'delete_smart_list',
|
||||
'get_smart_list_contacts', 'get_smart_list_count', 'duplicate_smart_list'
|
||||
];
|
||||
return smartListsToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if tool name belongs to triggers tools
|
||||
*/
|
||||
private isTriggersTool(toolName: string): boolean {
|
||||
const triggersToolNames = [
|
||||
'get_triggers', 'get_trigger', 'create_trigger', 'update_trigger', 'delete_trigger',
|
||||
'enable_trigger', 'disable_trigger', 'get_trigger_types', 'get_trigger_logs', 'test_trigger', 'duplicate_trigger'
|
||||
];
|
||||
return triggersToolNames.includes(toolName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Test GHL API connection
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user