173 lines
4.8 KiB
TypeScript
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);
|
|
});
|