Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 15 additions & 6 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

14 changes: 6 additions & 8 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,23 +46,21 @@
},
"dependencies": {
"@modelcontextprotocol/sdk": "^1.15.1",
"@toon-format/toon": "^1.0.0",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/node": "^24.10.1",
"cors": "^2.8.5",
"express": "^4.21.2",
"node-fetch": "^3.3.2",
"zod": "^3.25.0",
"typescript": "^5.3.0",
"@types/cors": "^2.8.19",
"@types/express": "^5.0.3",
"@types/node": "^20.0.0"
"zod": "^3.25.0"
},
"devDependencies": {
"@babel/parser": "^7.27.5",
"@babel/traverse": "^7.27.4",
"@babel/types": "^7.27.6",
"@types/babel__traverse": "^7.20.7",



"tsx": "^4.7.0"
},
"engines": {
Expand All @@ -72,4 +70,4 @@
"compatible": true,
"version": "0.1"
}
}
}
42 changes: 11 additions & 31 deletions src/handlers/lead-handler.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
import { makeInstantlyRequest } from '../api/client.js';
import { ENDPOINTS } from '../api/endpoints.js';
import { createMCPResponse } from '../utils/response-formatter.js';

/**
* Handle all lead-related tool executions
Expand Down Expand Up @@ -167,14 +168,7 @@ async function handleListLeads(args: any, apiKey: string) {
response.client_side_filters_applied = filtersApplied;
}

return {
content: [
{
type: 'text',
text: JSON.stringify(response, null, 2),
},
],
};
return createMCPResponse(response);
} catch (error: any) {
const elapsed = Date.now() - startTime;
console.error(`[Instantly MCP] ❌ Request failed after ${elapsed}ms: ${error.message}`);
Expand All @@ -196,14 +190,7 @@ async function handleGetLead(args: any, apiKey: string) {

const result = await makeInstantlyRequest(`/leads/${args.lead_id}`, {}, apiKey);

return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
return createMCPResponse(result);
}

/**
Expand Down Expand Up @@ -503,21 +490,14 @@ async function handleListLeadLists(args: any, apiKey: string) {
const items = listsResult.items || listsResult;
const nextStartingAfter = listsResult.next_starting_after;

return {
content: [
{
type: 'text',
text: JSON.stringify({
success: true,
lead_lists: items,
next_starting_after: nextStartingAfter,
total_returned: Array.isArray(items) ? items.length : 0,
has_more: !!nextStartingAfter,
message: 'Lead lists retrieved successfully'
}, null, 2)
}
]
};
return createMCPResponse({
success: true,
lead_lists: items,
next_starting_after: nextStartingAfter,
total_returned: Array.isArray(items) ? items.length : 0,
has_more: !!nextStartingAfter,
message: 'Lead lists retrieved successfully'
});
}

/**
Expand Down
127 changes: 40 additions & 87 deletions src/handlers/tool-executor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { ErrorCode, McpError } from '@modelcontextprotocol/sdk/types.js';
import { makeInstantlyRequest } from '../api/client.js';
import { ENDPOINTS } from '../api/endpoints.js';
import { handleLeadTool } from './lead-handler.js';
import { createMCPResponse } from '../utils/response-formatter.js';
import {
getAllAccounts,
getEligibleSenderAccounts,
Expand Down Expand Up @@ -136,19 +137,13 @@ export async function executeToolDirectly(name: string, args: any, apiKey?: stri
const result = await getAllAccounts(apiKey, paginationParams);

// Return single page with clear pagination metadata
return {
content: [
{
type: 'text',
text: JSON.stringify({
data: result.data,
pagination: result.pagination,
metadata: result.metadata,
success: true
}, null, 2)
}
]
};
// Using TOON format for token efficiency (30-60% reduction for tabular data)
return createMCPResponse({
data: result.data,
pagination: result.pagination,
metadata: result.metadata,
success: true
});
} catch (error: any) {
console.error('[Instantly MCP] ❌ Error in list_accounts:', error.message);
throw error;
Expand Down Expand Up @@ -218,32 +213,25 @@ export async function executeToolDirectly(name: string, args: any, apiKey?: stri
if (args?.tag_ids) filtersApplied.tag_ids = args.tag_ids;

// Return single page with clear pagination metadata
return {
content: [
{
type: 'text',
text: JSON.stringify({
data: campaignsWithReadableStatus,
pagination: {
returned_count: campaignsWithReadableStatus.length,
has_more: hasMore,
next_starting_after: nextCursor,
limit: queryParams.limit,
current_page_note: hasMore
? `Retrieved ${campaignsWithReadableStatus.length} campaigns. More results available. To get next page, call list_campaigns again with starting_after='${nextCursor}'`
: `Retrieved all available campaigns (${campaignsWithReadableStatus.length} items).`
},
filters_applied: Object.keys(filtersApplied).length > 0 ? filtersApplied : undefined,
metadata: {
request_time_ms: elapsed,
success: true,
status_mapping_note: 'All campaigns include status_label (human-readable) and status_code (numeric) fields'
},
success: true
}, null, 2)
}
]
};
return createMCPResponse({
data: campaignsWithReadableStatus,
pagination: {
returned_count: campaignsWithReadableStatus.length,
has_more: hasMore,
next_starting_after: nextCursor,
limit: queryParams.limit,
current_page_note: hasMore
? `Retrieved ${campaignsWithReadableStatus.length} campaigns. More results available. To get next page, call list_campaigns again with starting_after='${nextCursor}'`
: `Retrieved all available campaigns (${campaignsWithReadableStatus.length} items).`
},
filters_applied: Object.keys(filtersApplied).length > 0 ? filtersApplied : undefined,
metadata: {
request_time_ms: elapsed,
success: true,
status_mapping_note: 'All campaigns include status_label (human-readable) and status_code (numeric) fields'
},
success: true
});
} catch (error: any) {
console.error('[Instantly MCP] ❌ Error in list_campaigns:', error.message);
throw error;
Expand All @@ -257,14 +245,7 @@ export async function executeToolDirectly(name: string, args: any, apiKey?: stri

const result = await makeInstantlyRequest(`/campaigns/${args.campaign_id}`, {}, apiKey);

return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
return createMCPResponse(result);
}

case 'get_campaign_analytics': {
Expand Down Expand Up @@ -319,14 +300,7 @@ export async function executeToolDirectly(name: string, args: any, apiKey?: stri
}
} : result;

return {
content: [
{
type: 'text',
text: JSON.stringify(enhancedResult, null, 2),
},
],
};
return createMCPResponse(enhancedResult);
} catch (error: any) {
// Enhanced error handling for campaign analytics with detailed debugging
console.error(`[Instantly MCP] get_campaign_analytics ERROR:`, error);
Expand Down Expand Up @@ -373,18 +347,11 @@ export async function executeToolDirectly(name: string, args: any, apiKey?: stri

const result = await makeInstantlyRequest('/campaigns/analytics/daily', { params }, apiKey);

return {
content: [
{
type: 'text',
text: JSON.stringify({
success: true,
daily_analytics: result,
message: 'Daily campaign analytics retrieved successfully'
}, null, 2)
}
]
};
return createMCPResponse({
success: true,
daily_analytics: result,
message: 'Daily campaign analytics retrieved successfully'
});
}

case 'create_campaign': {
Expand Down Expand Up @@ -770,14 +737,7 @@ export async function executeToolDirectly(name: string, args: any, apiKey?: stri
body: requestBody
}, apiKey);

return {
content: [
{
type: 'text',
text: JSON.stringify(result, null, 2),
},
],
};
return createMCPResponse(result);
}

case 'verify_email': {
Expand Down Expand Up @@ -982,18 +942,11 @@ export async function executeToolDirectly(name: string, args: any, apiKey?: stri
metadata.note += ' All results retrieved (no more pages available).';
}

return {
content: [
{
type: 'text',
text: JSON.stringify({
...emailsResult,
metadata,
success: true
}, null, 2)
}
]
};
return createMCPResponse({
...emailsResult,
metadata,
success: true
});
}

case 'get_email': {
Expand Down
Loading