UNPKG

inboxassure-mcp-server

Version:

Comprehensive MCP server for InboxAssure email marketing platform with full API coverage including campaigns, replies, and email account management.

208 lines (163 loc) 8.82 kB
export class BisonService { constructor(apiKey) { this.id = Math.random().toString(36).substring(2, 8); console.error(`[DEBUG:BISON:${this.id}] Creating BisonService instance`); if (!apiKey) { console.error(`[DEBUG:BISON:${this.id}] Error: No API key provided to constructor`); throw new Error("API key is required for BisonService."); } // Log detailed info about the API key console.error(`[DEBUG:BISON:${this.id}] API key type: ${typeof apiKey}`); console.error(`[DEBUG:BISON:${this.id}] API key length: ${apiKey.length}`); // If the API key contains a comma, it might be a duplicated header value // Take only the first value in that case if (apiKey.includes(',')) { console.error(`[DEBUG:BISON:${this.id}] API key contains commas, likely a duplicated header value. Taking first value.`); apiKey = apiKey.split(',')[0].trim(); console.error(`[DEBUG:BISON:${this.id}] Extracted first API key: ${apiKey}`); } // Trim any whitespace from the API key this.apiKey = apiKey.trim(); console.error(`[DEBUG:BISON:${this.id}] API key format validation: ${this.apiKey.startsWith('iak_') ? 'valid prefix' : 'invalid prefix'}, length: ${this.apiKey.length}`); // Validate the API key has the expected format if (!this.apiKey.startsWith('iak_')) { console.error(`[DEBUG:BISON:${this.id}] Warning: API key does not start with expected prefix 'iak_'`); } if (this.apiKey.length < 10) { console.error(`[DEBUG:BISON:${this.id}] Warning: API key seems too short. Expected length > 20`); } this.baseUrl = "https://bison.imnodev.com/api"; console.error(`[DEBUG:BISON:${this.id}] Instance created with API key: ${this.apiKey.substring(0, 8)}... and baseUrl: ${this.baseUrl}`); } async makeRequest(endpoint, method = 'GET', body = null) { const callId = Math.random().toString(36).substring(2, 8); console.error(`[DEBUG:BISON:${this.id}:${callId}] Starting ${method} request to ${endpoint}`); try { const url = `${this.baseUrl}${endpoint}`; console.error(`[DEBUG:BISON:${this.id}:${callId}] Fetching ${url}`); console.error(`[DEBUG:BISON:${this.id}:${callId}] Using API key: ${this.apiKey.substring(0, 8)}...`); const options = { method, headers: { 'X-API-Key': this.apiKey, 'Content-Type': 'application/json' } }; if (body && (method === 'POST' || method === 'PATCH')) { options.body = JSON.stringify(body); console.error(`[DEBUG:BISON:${this.id}:${callId}] Request body: ${JSON.stringify(body)}`); } const fetchStart = Date.now(); const response = await fetch(url, options); const fetchDuration = Date.now() - fetchStart; console.error(`[DEBUG:BISON:${this.id}:${callId}] Response received in ${fetchDuration}ms with status: ${response.status}`); console.error(`[DEBUG:BISON:${this.id}:${callId}] Response headers: ${JSON.stringify(Object.fromEntries([...response.headers]))}`); if (!response.ok) { const errorBody = await response.text(); console.error(`[DEBUG:BISON:${this.id}:${callId}] Error response body: ${errorBody}`); // Try to parse errorBody as JSON if possible for more structured error, otherwise use text let details = errorBody; try { details = JSON.stringify(JSON.parse(errorBody)); console.error(`[DEBUG:BISON:${this.id}:${callId}] Parsed error body as JSON`); } catch (e) { // not JSON, use as is console.error(`[DEBUG:BISON:${this.id}:${callId}] Error body is not valid JSON`); } const error = new Error(`API error: ${response.status} - ${details}`); console.error(`[DEBUG:BISON:${this.id}:${callId}] Throwing error: ${error.message}`); throw error; } const parseStart = Date.now(); const data = await response.json(); const parseDuration = Date.now() - parseStart; console.error(`[DEBUG:BISON:${this.id}:${callId}] Response parsed in ${parseDuration}ms`); console.error(`[DEBUG:BISON:${this.id}:${callId}] Response data: ${JSON.stringify(data)}`); return data; } catch (error) { console.error(`[DEBUG:BISON:${this.id}:${callId}] Error in ${method} ${endpoint}: ${error.message}`); console.error(`[DEBUG:BISON:${this.id}:${callId}] Error stack: ${error.stack}`); throw error; } } async getHello() { return this.makeRequest('/hello'); } // ==================== CAMPAIGNS API ==================== async listCampaigns(workspaceId, params = {}) { const queryString = new URLSearchParams(params).toString(); const endpoint = `/campaigns/${workspaceId}${queryString ? '?' + queryString : ''}`; return this.makeRequest(endpoint); } async createCampaign(workspaceId, campaignData) { return this.makeRequest(`/campaigns/${workspaceId}`, 'POST', campaignData); } async getCampaignDetails(workspaceId, campaignId) { return this.makeRequest(`/campaigns/${workspaceId}/${campaignId}`); } async pauseCampaign(workspaceId, campaignId) { return this.makeRequest(`/campaigns/${workspaceId}/${campaignId}/pause`, 'PATCH'); } async resumeCampaign(workspaceId, campaignId) { return this.makeRequest(`/campaigns/${workspaceId}/${campaignId}/resume`, 'PATCH'); } async createCampaignSchedule(workspaceId, campaignId, scheduleData) { return this.makeRequest(`/campaigns/${workspaceId}/${campaignId}/schedule`, 'POST', scheduleData); } async getScheduleTemplates(workspaceId) { return this.makeRequest(`/campaigns/${workspaceId}/schedule/templates`); } async createSequenceSteps(workspaceId, campaignId, sequenceData) { return this.makeRequest(`/campaigns/${workspaceId}/${campaignId}/sequence-steps`, 'POST', sequenceData); } async attachLeadList(workspaceId, campaignId, leadListData) { return this.makeRequest(`/campaigns/${workspaceId}/${campaignId}/leads/attach-lead-list`, 'POST', leadListData); } async getCampaignLeads(workspaceId, campaignId, params = {}) { const queryString = new URLSearchParams(params).toString(); const endpoint = `/campaigns/${workspaceId}/${campaignId}/leads${queryString ? '?' + queryString : ''}`; return this.makeRequest(endpoint); } async getCampaignStats(workspaceId, campaignId, dateRange) { return this.makeRequest(`/campaigns/${workspaceId}/${campaignId}/stats`, 'POST', dateRange); } // ==================== REPLIES API ==================== async listReplies(workspaceId, params = {}) { const queryString = new URLSearchParams(params).toString(); const endpoint = `/replies/${workspaceId}${queryString ? '?' + queryString : ''}`; return this.makeRequest(endpoint); } async getReplyDetails(workspaceId, replyId) { return this.makeRequest(`/replies/${workspaceId}/${replyId}`); } async composeNewEmail(workspaceId, emailData) { return this.makeRequest(`/replies/${workspaceId}/new`, 'POST', emailData); } async replyToEmail(workspaceId, replyId, replyData) { return this.makeRequest(`/replies/${workspaceId}/${replyId}/reply`, 'POST', replyData); } async getConversationThread(workspaceId, replyId) { return this.makeRequest(`/replies/${workspaceId}/${replyId}/conversation-thread`); } // ==================== EMAIL ACCOUNTS API ==================== async listEmailAccounts(workspaceId, params = {}) { const queryString = new URLSearchParams(params).toString(); const endpoint = `/email-accounts/${workspaceId}/sender-emails${queryString ? '?' + queryString : ''}`; return this.makeRequest(endpoint); } async getEmailAccountDetails(workspaceId, emailId) { return this.makeRequest(`/email-accounts/${workspaceId}/sender-emails/${emailId}`); } async updateEmailAccount(workspaceId, emailId, updateData) { return this.makeRequest(`/email-accounts/${workspaceId}/sender-emails/${emailId}`, 'PATCH', updateData); } async getAccountCampaigns(workspaceId, emailId) { return this.makeRequest(`/email-accounts/${workspaceId}/sender-emails/${emailId}/campaigns`); } async getAccountReplies(workspaceId, emailId) { return this.makeRequest(`/email-accounts/${workspaceId}/sender-emails/${emailId}/replies`); } async bulkUpdateEmailSignatures(workspaceId, bulkData) { return this.makeRequest(`/email-accounts/${workspaceId}/sender-emails/signatures/bulk`, 'PATCH', bulkData); } }