#!/usr/bin/env node /** * ActiveCampaign MCP Server * Complete integration with 60+ tools and 16 apps */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js'; import { CallToolRequestSchema, ListToolsRequestSchema, ListResourcesRequestSchema, ReadResourceRequestSchema, } from '@modelcontextprotocol/sdk/types.js'; import { ActiveCampaignClient } from './client/index.js'; import { createContactTools } from './tools/contacts.js'; import { createDealTools } from './tools/deals.js'; import { createListTools } from './tools/lists.js'; import { createCampaignTools } from './tools/campaigns.js'; import { createAutomationTools } from './tools/automations.js'; import { createFormTools } from './tools/forms.js'; import { createTagTools } from './tools/tags.js'; import { createTaskTools } from './tools/tasks.js'; import { createNoteTools } from './tools/notes.js'; import { createPipelineTools } from './tools/pipelines.js'; import { createAccountTools } from './tools/accounts.js'; import { createWebhookTools } from './tools/webhooks.js'; // Available app resources const APPS = [ 'contact-manager', 'deal-pipeline', 'list-builder', 'campaign-dashboard', 'automation-builder', 'form-manager', 'tag-organizer', 'task-center', 'notes-viewer', 'pipeline-settings', 'account-directory', 'webhook-manager', 'email-analytics', 'segment-viewer', 'site-tracking', 'score-dashboard', ]; class ActiveCampaignServer { private server: Server; private client: ActiveCampaignClient; private allTools: Record = {}; constructor() { const account = process.env.ACTIVECAMPAIGN_ACCOUNT; const apiKey = process.env.ACTIVECAMPAIGN_API_KEY; if (!account || !apiKey) { throw new Error( 'Missing required environment variables: ACTIVECAMPAIGN_ACCOUNT and ACTIVECAMPAIGN_API_KEY' ); } this.client = new ActiveCampaignClient(account, apiKey); this.server = new Server( { name: 'activecampaign-server', version: '1.0.0', }, { capabilities: { tools: {}, resources: {}, }, } ); this.setupTools(); this.setupHandlers(); } private setupTools() { // Aggregate all tools from different modules this.allTools = { ...createContactTools(this.client), ...createDealTools(this.client), ...createListTools(this.client), ...createCampaignTools(this.client), ...createAutomationTools(this.client), ...createFormTools(this.client), ...createTagTools(this.client), ...createTaskTools(this.client), ...createNoteTools(this.client), ...createPipelineTools(this.client), ...createAccountTools(this.client), ...createWebhookTools(this.client), }; } private setupHandlers() { // List available tools this.server.setRequestHandler(ListToolsRequestSchema, async () => { return { tools: Object.entries(this.allTools).map(([name, tool]) => ({ name, description: tool.description, inputSchema: tool.inputSchema, })), }; }); // Execute tool this.server.setRequestHandler(CallToolRequestSchema, async (request) => { const toolName = request.params.name; const tool = this.allTools[toolName]; if (!tool) { throw new Error(`Unknown tool: ${toolName}`); } try { const result = await tool.handler(request.params.arguments || {}); return { content: [ { type: 'text', text: JSON.stringify(result, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }); // List app resources this.server.setRequestHandler(ListResourcesRequestSchema, async () => { return { resources: APPS.map((app) => ({ uri: `activecampaign://app/${app}`, mimeType: 'text/html', name: app .split('-') .map((w) => w.charAt(0).toUpperCase() + w.slice(1)) .join(' '), })), }; }); // Read app resource this.server.setRequestHandler(ReadResourceRequestSchema, async (request) => { const uri = request.params.uri; const match = uri.match(/^activecampaign:\/\/app\/(.+)$/); if (!match) { throw new Error(`Invalid resource URI: ${uri}`); } const appName = match[1]; if (!APPS.includes(appName)) { throw new Error(`Unknown app: ${appName}`); } try { // Dynamically import the app const appModule = await import(`./apps/${appName}/index.js`); const html = appModule.default(); return { contents: [ { uri, mimeType: 'text/html', text: html, }, ], }; } catch (error) { throw new Error(`Failed to load app ${appName}: ${error}`); } }); } async run() { const transport = new StdioServerTransport(); await this.server.connect(transport); console.error('ActiveCampaign MCP Server running on stdio'); } } const server = new ActiveCampaignServer(); server.run().catch(console.error);