inboxassure-mcp-server
Version:
Comprehensive MCP server for InboxAssure email marketing platform with full API coverage including campaigns, replies, and email account management.
566 lines (543 loc) • 25.9 kB
JavaScript
import fetch from 'node-fetch';
import readline from 'readline';
// The server URL - point directly to the API server
const SERVER_URL = 'https://bison.imnodev.com/api';
export function startMcpBridge(apiKey) {
if (!apiKey) {
console.error('[MCPX] Error: No API key provided');
process.exit(1);
}
// Create readline interface for stdio
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout,
terminal: false
});
console.error(`[MCPX] Bridge initialized and waiting for messages...`);
// Listen for input from Claude
rl.on('line', async (line) => {
try {
console.error(`[MCPX] Received message: ${line.substring(0, 50)}...`);
// Parse the incoming JSON-RPC message
const message = JSON.parse(line);
// Handle different MCP methods
if (message.method === 'initialize') {
console.error(`[MCPX] Handling initialize request with id: ${message.id}`);
// Send initialization response
console.log(JSON.stringify({
jsonrpc: '2.0',
id: message.id,
result: {
protocolVersion: '2024-11-05',
capabilities: {
tools: { listChanged: true }
},
serverInfo: {
name: 'InboxAssure MCP Server',
version: '2.1.0',
description: 'Comprehensive MCP server for InboxAssure email marketing platform'
}
}
}));
}
else if (message.method === 'notifications/initialized') {
// For notifications, simply log but don't respond
// Notifications don't require a response according to JSON-RPC spec
console.error(`[MCPX] Handling initialized notification`);
// No response needed for notifications
}
else if (message.method === 'tools/list') {
console.error(`[MCPX] Handling tools/list request with id: ${message.id}`);
// List all 23 available tools
console.log(JSON.stringify({
jsonrpc: '2.0',
id: message.id,
result: {
tools: [
// Original tool
{
name: 'get_bison_hello',
description: 'Test endpoint to verify API connectivity',
inputSchema: {
type: 'object',
properties: {
random_string: { type: 'string', description: 'Dummy parameter for no-parameter tools' }
},
additionalProperties: false
}
},
// Campaigns API (11 tools)
{
name: 'list_campaigns',
description: 'List all campaigns in a workspace with optional filtering and pagination',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID to list campaigns for' },
params: {
type: 'object',
description: 'Optional query parameters',
properties: {
search: { type: 'string', description: 'Search term for campaign names' },
status: { type: 'string', description: 'Filter by status (active, paused, draft)' },
page: { type: 'number', description: 'Page number for pagination' },
per_page: { type: 'number', description: 'Items per page (max 100)' }
}
}
},
required: ['workspace_id'],
additionalProperties: false
}
},
{
name: 'create_campaign',
description: 'Create a new email marketing campaign',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID to create the campaign in' },
name: { type: 'string', description: 'Name of the campaign' },
type: { type: 'string', description: 'Type of campaign (default: outbound)', enum: ['outbound', 'inbound'] }
},
required: ['workspace_id', 'name'],
additionalProperties: false
}
},
{
name: 'get_campaign_details',
description: 'Get detailed information about a specific campaign',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
campaign_id: { type: 'string', description: 'The campaign ID to get details for' }
},
required: ['workspace_id', 'campaign_id'],
additionalProperties: false
}
},
{
name: 'pause_campaign',
description: 'Pause a running campaign temporarily',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
campaign_id: { type: 'string', description: 'The campaign ID to pause' }
},
required: ['workspace_id', 'campaign_id'],
additionalProperties: false
}
},
{
name: 'resume_campaign',
description: 'Resume a paused campaign',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
campaign_id: { type: 'string', description: 'The campaign ID to resume' }
},
required: ['workspace_id', 'campaign_id'],
additionalProperties: false
}
},
{
name: 'get_campaign_stats',
description: 'Get detailed performance metrics for a campaign within a date range',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
campaign_id: { type: 'string', description: 'The campaign ID to get stats for' },
start_date: { type: 'string', description: 'Start date in YYYY-MM-DD format' },
end_date: { type: 'string', description: 'End date in YYYY-MM-DD format' }
},
required: ['workspace_id', 'campaign_id', 'start_date', 'end_date'],
additionalProperties: false
}
},
{
name: 'get_campaign_leads',
description: 'View all leads in a campaign with their status and progress',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
campaign_id: { type: 'string', description: 'The campaign ID to get leads for' },
params: {
type: 'object',
description: 'Optional query parameters',
properties: {
page: { type: 'number', description: 'Page number for pagination' },
per_page: { type: 'number', description: 'Items per page' },
status: { type: 'string', description: 'Filter by lead status' }
}
}
},
required: ['workspace_id', 'campaign_id'],
additionalProperties: false
}
},
{
name: 'create_campaign_schedule',
description: 'Set up when your campaign sends emails (days, times, timezone)',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
campaign_id: { type: 'string', description: 'The campaign ID to create schedule for' },
monday: { type: 'boolean', description: 'Send emails on Monday' },
tuesday: { type: 'boolean', description: 'Send emails on Tuesday' },
wednesday: { type: 'boolean', description: 'Send emails on Wednesday' },
thursday: { type: 'boolean', description: 'Send emails on Thursday' },
friday: { type: 'boolean', description: 'Send emails on Friday' },
saturday: { type: 'boolean', description: 'Send emails on Saturday' },
sunday: { type: 'boolean', description: 'Send emails on Sunday' },
start_time: { type: 'string', description: 'Start time in HH:MM format (e.g., 09:00)' },
end_time: { type: 'string', description: 'End time in HH:MM format (e.g., 17:00)' },
timezone: { type: 'string', description: 'Timezone (e.g., America/New_York)' }
},
required: ['workspace_id', 'campaign_id', 'start_time', 'end_time', 'timezone'],
additionalProperties: false
}
},
{
name: 'get_schedule_templates',
description: 'Retrieve predefined schedule templates for quick campaign setup',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' }
},
required: ['workspace_id'],
additionalProperties: false
}
},
{
name: 'create_sequence_steps',
description: 'Define the series of emails that will be sent to leads over time',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
campaign_id: { type: 'string', description: 'The campaign ID to create sequence for' },
title: { type: 'string', description: 'Title for the email sequence' },
sequence_steps: {
type: 'array',
description: 'Array of email steps in the sequence',
items: {
type: 'object',
properties: {
email_subject: { type: 'string', description: 'Subject line for the email' },
email_body: { type: 'string', description: 'Body content of the email' },
wait_in_days: { type: 'number', description: 'Days to wait before sending this email' },
order: { type: 'number', description: 'Order of this step in the sequence' }
},
required: ['email_subject', 'email_body', 'wait_in_days', 'order']
}
}
},
required: ['workspace_id', 'campaign_id', 'title', 'sequence_steps'],
additionalProperties: false
}
},
{
name: 'attach_lead_list',
description: 'Add an entire existing lead list to your campaign',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
campaign_id: { type: 'string', description: 'The campaign ID to attach leads to' },
lead_list_id: { type: 'string', description: 'The ID of the lead list to attach' }
},
required: ['workspace_id', 'campaign_id', 'lead_list_id'],
additionalProperties: false
}
},
// Replies API (5 tools)
{
name: 'list_replies',
description: 'Retrieve all email replies across campaigns with filtering options',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
params: {
type: 'object',
description: 'Optional query parameters',
properties: {
search: { type: 'string', description: 'Search term for emails, subjects' },
status: { type: 'string', description: 'Filter by status (interested, not_interested, automated_reply)' },
folder: { type: 'string', description: 'Email folder (inbox, sent, spam, bounced, all)' },
read: { type: 'boolean', description: 'Filter by read status' },
campaign_id: { type: 'string', description: 'Filter by campaign ID' },
page: { type: 'number', description: 'Page number for pagination' },
per_page: { type: 'number', description: 'Items per page' }
}
}
},
required: ['workspace_id'],
additionalProperties: false
}
},
{
name: 'get_reply_details',
description: 'Get complete details of a specific reply including full message content',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
reply_id: { type: 'string', description: 'The reply ID to get details for' }
},
required: ['workspace_id', 'reply_id'],
additionalProperties: false
}
},
{
name: 'compose_new_email',
description: 'Send a standalone email outside of campaign sequences',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
sender_email_id: { type: 'string', description: 'ID of the sender email account' },
to_emails: { type: 'array', items: { type: 'string' }, description: 'Array of recipient email addresses' },
message: { type: 'string', description: 'The email message content' },
content_type: { type: 'string', description: 'Content type (text/plain or text/html)', enum: ['text/plain', 'text/html'] },
cc_emails: { type: 'array', items: { type: 'string' }, description: 'Array of CC email addresses' },
bcc_emails: { type: 'array', items: { type: 'string' }, description: 'Array of BCC email addresses' }
},
required: ['workspace_id', 'sender_email_id', 'to_emails', 'message'],
additionalProperties: false
}
},
{
name: 'reply_to_email',
description: 'Respond to an incoming email reply, maintaining conversation thread',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
reply_id: { type: 'string', description: 'The reply ID to respond to' },
sender_email_id: { type: 'string', description: 'ID of the sender email account' },
to_emails: { type: 'array', items: { type: 'string' }, description: 'Array of recipient email addresses' },
message: { type: 'string', description: 'The reply message content' },
content_type: { type: 'string', description: 'Content type (text/plain or text/html)', enum: ['text/plain', 'text/html'] }
},
required: ['workspace_id', 'reply_id', 'sender_email_id', 'to_emails', 'message'],
additionalProperties: false
}
},
{
name: 'get_conversation_thread',
description: 'Retrieve the complete email conversation history for context',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
reply_id: { type: 'string', description: 'The reply ID to get conversation thread for' }
},
required: ['workspace_id', 'reply_id'],
additionalProperties: false
}
},
// Email Accounts API (6 tools)
{
name: 'list_email_accounts',
description: 'Get all email accounts configured in your workspace with their settings',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
params: {
type: 'object',
description: 'Optional query parameters',
properties: {
search: { type: 'string', description: 'Search term for email addresses, names' },
page: { type: 'number', description: 'Page number for pagination' },
per_page: { type: 'number', description: 'Items per page' }
}
}
},
required: ['workspace_id'],
additionalProperties: false
}
},
{
name: 'get_email_account_details',
description: 'Retrieve detailed configuration and statistics for a specific email account',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
email_id: { type: 'string', description: 'The email account ID to get details for' }
},
required: ['workspace_id', 'email_id'],
additionalProperties: false
}
},
{
name: 'update_email_account',
description: 'Modify email account configuration like daily limits and signatures',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
email_id: { type: 'string', description: 'The email account ID to update' },
daily_limit: { type: 'number', description: 'New daily email sending limit' },
name: { type: 'string', description: 'New display name for the email account' },
email_signature: { type: 'string', description: 'New email signature' }
},
required: ['workspace_id', 'email_id'],
additionalProperties: false
}
},
{
name: 'get_account_campaigns',
description: 'See which campaigns are using this email account for sending',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
email_id: { type: 'string', description: 'The email account ID to get campaigns for' }
},
required: ['workspace_id', 'email_id'],
additionalProperties: false
}
},
{
name: 'get_account_replies',
description: 'View all replies received by this specific email account',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
email_id: { type: 'string', description: 'The email account ID to get replies for' }
},
required: ['workspace_id', 'email_id'],
additionalProperties: false
}
},
{
name: 'bulk_update_email_signatures',
description: 'Update email signatures across multiple accounts simultaneously',
inputSchema: {
type: 'object',
properties: {
workspace_id: { type: 'string', description: 'The workspace ID' },
sender_email_ids: { type: 'array', items: { type: 'string' }, description: 'Array of email account IDs to update' },
email_signature: { type: 'string', description: 'New email signature to apply to all selected accounts' }
},
required: ['workspace_id', 'sender_email_ids', 'email_signature'],
additionalProperties: false
}
}
]
}
}));
}
else if (message.method === 'tools/call') {
const toolName = message.params?.name;
console.error(`[MCPX] Handling tools/call for ${toolName} with id: ${message.id}`);
try {
// Call the appropriate API endpoint based on the tool
console.error(`[MCPX] Calling ${toolName} on ${SERVER_URL}`);
const controller = new AbortController();
const timeout = setTimeout(() => controller.abort(), 10000); // 10 second timeout
let response;
const args = message.params.arguments || {};
try {
// Route to the correct API endpoint based on tool name
if (toolName === 'get_bison_hello') {
response = await fetch(`${SERVER_URL}/hello`, {
method: 'GET',
headers: {
'X-API-Key': apiKey
},
signal: controller.signal
});
} else if (toolName === 'list_campaigns') {
const queryParams = new URLSearchParams(args.params || {}).toString();
const url = `${SERVER_URL}/campaigns/${args.workspace_id}${queryParams ? '?' + queryParams : ''}`;
response = await fetch(url, {
method: 'GET',
headers: {
'X-API-Key': apiKey
},
signal: controller.signal
});
} else {
throw new Error(`Tool ${toolName} not implemented yet in bridge`);
}
clearTimeout(timeout);
if (!response.ok) {
throw new Error(`API returned ${response.status}: ${response.statusText}`);
}
const data = await response.json();
console.error(`[MCPX] Received response from API: ${JSON.stringify(data).substring(0, 100)}...`);
// Send the response back to Claude
console.log(JSON.stringify({
jsonrpc: '2.0',
id: message.id,
result: {
content: [{ type: "text", text: JSON.stringify(data, null, 2) }]
}
}));
} catch (fetchError) {
clearTimeout(timeout);
throw fetchError;
}
} catch (error) {
const errorMessage = error.name === 'AbortError'
? 'Request timed out'
: error.message;
console.error(`[MCPX] Error calling remote server: ${errorMessage}`);
console.log(JSON.stringify({
jsonrpc: '2.0',
id: message.id,
error: {
code: -32603,
message: `Server error: ${errorMessage}`
}
}));
}
}
else {
// Handle unknown methods
console.error(`[MCPX] Unknown method: ${message.method}`);
console.log(JSON.stringify({
jsonrpc: '2.0',
id: message.id,
error: {
code: -32601,
message: 'Method not found'
}
}));
}
} catch (error) {
console.error(`[MCPX] Error parsing message: ${error.message}`);
// Return parse error
console.log(JSON.stringify({
jsonrpc: '2.0',
id: null,
error: {
code: -32700,
message: `Parse error: ${error.message}`
}
}));
}
});
// Handle process termination
process.on('SIGINT', () => {
console.error(`[MCPX] Received SIGINT, shutting down...`);
rl.close();
process.exit(0);
});
process.on('SIGTERM', () => {
console.error(`[MCPX] Received SIGTERM, shutting down...`);
rl.close();
process.exit(0);
});
}