2026-01-30 23:00:51 -05:00

173 lines
4.8 KiB
TypeScript

/**
* GoHighLevel MCP Apps Server (Slimmed Down)
* Only includes MCP Apps - no other tools
*/
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
import {
CallToolRequestSchema,
ErrorCode,
ListToolsRequestSchema,
ListResourcesRequestSchema,
ReadResourceRequestSchema,
McpError
} from '@modelcontextprotocol/sdk/types.js';
import * as dotenv from 'dotenv';
import { GHLApiClient } from './clients/ghl-api-client.js';
import { MCPAppsManager } from './apps/index.js';
import { GHLConfig } from './types/ghl-types.js';
// Load environment variables
dotenv.config();
/**
* MCP Apps Only Server
*/
class GHLMCPAppsServer {
private server: Server;
private ghlClient: GHLApiClient;
private mcpAppsManager: MCPAppsManager;
constructor() {
// Initialize MCP server with capabilities
this.server = new Server(
{
name: 'ghl-mcp-apps-only',
version: '1.0.0',
},
{
capabilities: {
tools: {},
resources: {},
},
}
);
// Initialize GHL API client
this.ghlClient = this.initializeGHLClient();
// Initialize MCP Apps Manager
this.mcpAppsManager = new MCPAppsManager(this.ghlClient);
this.setupHandlers();
this.setupErrorHandling();
}
/**
* Initialize the GHL API client with config from environment
*/
private initializeGHLClient(): GHLApiClient {
const config: GHLConfig = {
accessToken: process.env.GHL_API_KEY || '',
locationId: process.env.GHL_LOCATION_ID || '',
baseUrl: process.env.GHL_BASE_URL || 'https://services.leadconnectorhq.com',
version: '2021-07-28'
};
if (!config.accessToken) {
process.stderr.write('Warning: GHL_API_KEY not set in environment\n');
}
if (!config.locationId) {
process.stderr.write('Warning: GHL_LOCATION_ID not set in environment\n');
}
return new GHLApiClient(config);
}
/**
* Setup request handlers
*/
private setupHandlers(): void {
// List tools - only MCP App tools
this.server.setRequestHandler(ListToolsRequestSchema, async () => {
const appTools = this.mcpAppsManager.getToolDefinitions();
process.stderr.write(`[MCP Apps Only] Listing ${appTools.length} app tools\n`);
return { tools: appTools };
});
// List resources - MCP App UI resources
this.server.setRequestHandler(ListResourcesRequestSchema, async () => {
const resourceUris = this.mcpAppsManager.getResourceURIs();
const resources = resourceUris.map(uri => {
const handler = this.mcpAppsManager.getResourceHandler(uri);
return {
uri: uri,
name: uri,
mimeType: handler?.mimeType || 'text/html;profile=mcp-app'
};
});
process.stderr.write(`[MCP Apps Only] Listing ${resources.length} UI resources\n`);
return { resources };
});
// Read resource - serve UI HTML
this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => {
const uri = request.params.uri;
process.stderr.write(`[MCP Apps Only] Reading resource: ${uri}\n`);
const handler = this.mcpAppsManager.getResourceHandler(uri);
if (!handler) {
throw new McpError(ErrorCode.InvalidRequest, `Resource not found: ${uri}`);
}
return {
contents: [{
uri: uri,
mimeType: handler.mimeType,
text: handler.getContent()
}]
};
});
// Call tool - execute MCP App tools
this.server.setRequestHandler(CallToolRequestSchema, async (request) => {
const { name, arguments: args } = request.params;
process.stderr.write(`[MCP Apps Only] Calling tool: ${name}\n`);
if (!this.mcpAppsManager.isAppTool(name)) {
throw new McpError(ErrorCode.MethodNotFound, `Unknown tool: ${name}`);
}
try {
const result = await this.mcpAppsManager.executeTool(name, args || {});
return result;
} catch (error: any) {
process.stderr.write(`[MCP Apps Only] Tool error: ${error.message}\n`);
throw new McpError(ErrorCode.InternalError, error.message);
}
});
}
/**
* Setup error handling
*/
private setupErrorHandling(): void {
this.server.onerror = (error) => {
process.stderr.write(`[MCP Apps Only] Server error: ${error}\n`);
};
process.on('SIGINT', async () => {
await this.server.close();
process.exit(0);
});
}
/**
* Start the server
*/
async run(): Promise<void> {
const transport = new StdioServerTransport();
await this.server.connect(transport);
process.stderr.write('[MCP Apps Only] Server started - Apps only mode\n');
}
}
// Start server
const server = new GHLMCPAppsServer();
server.run().catch((error) => {
process.stderr.write(`Failed to start server: ${error}\n`);
process.exit(1);
});