#
tokens: 47592/50000 42/54 files (page 1/3)
lines: on (toggle) GitHub
raw markdown copy reset
This is page 1 of 3. Use http://codebase.md/jean-technologies/smartlead-mcp-server-local?lines=true&page={x} to view the full context.

# Directory Structure

```
├── .env.example
├── .gitignore
├── DEVELOPER_ONBOARDING.md
├── Dockerfile
├── jest.config.js
├── llms-install.md
├── mcp_settings_example.json
├── package-lock.json
├── package.json
├── README.md
├── server
│   └── license-server.js
├── smithery.yaml
├── src
│   ├── cli.ts
│   ├── config
│   │   └── feature-config.ts
│   ├── handlers
│   │   ├── campaign.ts
│   │   ├── clientManagement.ts
│   │   ├── email.ts
│   │   ├── lead.ts
│   │   ├── smartDelivery.ts
│   │   ├── smartSenders.ts
│   │   ├── statistics.ts
│   │   └── webhooks.ts
│   ├── index.ts
│   ├── licensing
│   │   ├── index.ts
│   │   └── stripe-integration.js
│   ├── n8n
│   │   └── index.ts
│   ├── registry
│   │   └── tool-registry.ts
│   ├── supergateway-mock.ts
│   ├── supergateway.ts
│   ├── tools
│   │   ├── campaign.ts
│   │   ├── clientManagement.ts
│   │   ├── email.d.ts
│   │   ├── email.ts
│   │   ├── lead.d.ts
│   │   ├── lead.ts
│   │   ├── smartDelivery.d.ts
│   │   ├── smartDelivery.ts
│   │   ├── smartSenders.ts
│   │   ├── statistics.d.ts
│   │   ├── statistics.ts
│   │   └── webhooks.ts
│   ├── types
│   │   ├── campaign.ts
│   │   ├── clientManagement.ts
│   │   ├── common.ts
│   │   ├── email.d.ts
│   │   ├── email.ts
│   │   ├── lead.ts
│   │   ├── smartDelivery.ts
│   │   ├── smartSenders.ts
│   │   ├── statistics.d.ts
│   │   ├── statistics.ts
│   │   ├── supergateway.d.ts
│   │   └── webhooks.ts
│   └── utils
│       └── download-tracker.ts
└── tsconfig.json
```

# Files

--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------

```
 1 | # Dependency directories
 2 | node_modules/
 3 | 
 4 | # Build output
 5 | dist/
 6 | 
 7 | # Environment variables
 8 | .env
 9 | .env.local
10 | .env.development.local
11 | .env.test.local
12 | .env.production.local
13 | 
14 | # Logs
15 | logs
16 | *.log
17 | npm-debug.log*
18 | yarn-debug.log*
19 | yarn-error.log*
20 | 
21 | # Coverage directory used by tools like istanbul
22 | coverage/
23 | 
24 | # IDE files
25 | .idea/
26 | .vscode/
27 | *.swp
28 | *.swo
29 | 
30 | # OS files
31 | .DS_Store
32 | Thumbs.db
33 | 
```

--------------------------------------------------------------------------------
/.env.example:
--------------------------------------------------------------------------------

```
 1 | # Smartlead API Key (required)
 2 | SMARTLEAD_API_KEY=your_api_key_here
 3 | 
 4 | # Optional: Custom API URL (defaults to https://server.smartlead.ai/api/v1)
 5 | # SMARTLEAD_API_URL=https://custom-server.smartlead.ai/api/v1
 6 | 
 7 | # Retry configuration
 8 | SMARTLEAD_RETRY_MAX_ATTEMPTS=3
 9 | SMARTLEAD_RETRY_INITIAL_DELAY=1000
10 | SMARTLEAD_RETRY_MAX_DELAY=10000
11 | SMARTLEAD_RETRY_BACKOFF_FACTOR=2
12 | 
13 | # Supergateway Integration
14 | # Set to 'true' to enable Supergateway integration
15 | USE_SUPERGATEWAY=false
16 | # Required if USE_SUPERGATEWAY is true
17 | 
18 | # Download Tracking Configuration (optional)
19 | # DOWNLOAD_LOG_PATH=/custom/path/to/downloads.json
20 | 
21 | # Enable Features
22 | # All features are enabled by default. No license key required.
23 | 
```

--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------

```markdown
  1 | [![MseeP.ai Security Assessment Badge](https://mseep.net/pr/jean-technologies-smartlead-mcp-server-local-badge.png)](https://mseep.ai/app/jean-technologies-smartlead-mcp-server-local)
  2 | 
  3 | # Smartlead Simplified MCP Server
  4 | 
  5 | [![smithery badge](https://smithery.ai/badge/@jean-technologies/smartlead-mcp-server-local)](https://smithery.ai/server/@jean-technologies/smartlead-mcp-server-local)
  6 | 
  7 | This application provides a simplified interface to the Smartlead API, allowing AI assistants and automation tools to interact with Smartlead's email marketing features. We welcome contribution from the community.
  8 | 
  9 | **Licensing:** All features are now enabled by default with maximum permissiveness! No license key required.
 10 | 
 11 | > **For developer details:** See [DEVELOPER_ONBOARDING.md](./DEVELOPER_ONBOARDING.md)
 12 | 
 13 | ## Quick Start
 14 | 
 15 | ### Installation
 16 | ```bash
 17 | npm install [email protected]
 18 | ```
 19 | 
 20 | or use directly with npx (no installation needed):
 21 | 
 22 | 
 23 | ### Installing via Smithery
 24 | 
 25 | To install Smartlead Campaign Management Server for Claude Desktop automatically via [Smithery](https://smithery.ai/server/@jean-technologies/smartlead-mcp-server-local):
 26 | 
 27 | ```bash
 28 | npx -y @smithery/cli install @jean-technologies/smartlead-mcp-server-local --client claude
 29 | ```
 30 | 
 31 | ### With Claude:
 32 | ```bash
 33 | npx smartlead-mcp-server start
 34 | ```
 35 | 
 36 | ### With n8n:
 37 | ```bash
 38 | npx smartlead-mcp-server sse
 39 | ```
 40 | 
 41 | First run will prompt for your Smartlead API Key. No license key is required.
 42 | 
 43 | ## Integration Examples
 44 | 
 45 | ### Claude Extension:
 46 | ```json
 47 | {
 48 |   "mcpServers": {
 49 |     "smartlead": {
 50 |       "command": "npx",
 51 |       "args": ["smartlead-mcp-server", "start"],
 52 |       "env": {
 53 |         "SMARTLEAD_API_KEY": "your_api_key_here"
 54 |       }
 55 |     }
 56 |   }
 57 | }
 58 | ```
 59 | 
 60 | ### n8n Setup:
 61 | 1. Start the server: `npx smartlead-mcp-server sse`
 62 | 2. Configure n8n MCP Client node with:
 63 |    - SSE URL: `http://localhost:3000/sse`
 64 |    - Message URL: `http://localhost:3000/message`
 65 | 
 66 | ## Available Features
 67 | 
 68 | **All features are now enabled by default, including:**
 69 | - Campaign & Lead Management
 70 | - Statistics and Analytics
 71 | - Smart Delivery & Webhooks
 72 | - n8n Integration
 73 | - Client Management
 74 | - Smart Senders
 75 | - Download Tracking and Analytics
 76 | 
 77 | ## New Download Tracking Features
 78 | 
 79 | This release adds new download tracking capabilities:
 80 | 
 81 | ### Download Campaign Data
 82 | Download campaign data with tracking using the `smartlead_download_campaign_data` tool:
 83 | ```json
 84 | {
 85 |   "campaign_id": 12345,
 86 |   "download_type": "analytics", // "analytics", "leads", "sequence", "full_export"
 87 |   "format": "json", // "json" or "csv"
 88 |   "user_id": "optional-user-identifier"
 89 | }
 90 | ```
 91 | 
 92 | ### View Download Statistics
 93 | View download statistics using the `smartlead_view_download_statistics` tool:
 94 | ```json
 95 | {
 96 |   "time_period": "all", // "all", "today", "week", "month"
 97 |   "group_by": "type" // "type", "format", "campaign", "date"
 98 | }
 99 | ```
100 | 
101 | All downloads are tracked in `~/.smartlead-mcp/downloads.json` for analytics.
102 | 
103 | ## Need Help?
104 | 
105 | - Run `npx smartlead-mcp-server config` to set up credentials
106 | - Use `--api-key` option for non-interactive setup
107 | - Contact: [email protected]
108 | - Website: [jeantechnologies.com](https://jeantechnologies.com)
109 | 
110 | ## License
111 | 
112 | This software is proprietary and confidential. Unauthorized copying, redistribution, or use of this software, in whole or in part, via any medium, is strictly prohibited without the express permission of Jean Technologies.
113 | 
114 | Copyright © 2025 Jean Technologies. All rights reserved.
115 | 
```

--------------------------------------------------------------------------------
/jest.config.js:
--------------------------------------------------------------------------------

```javascript
 1 | export default {
 2 |   transform: {},
 3 |   extensionsToTreatAsEsm: ['.ts'],
 4 |   moduleNameMapper: {
 5 |     '^(\\.{1,2}/.*)\\.js$': '$1',
 6 |   },
 7 |   testEnvironment: 'node',
 8 |   verbose: true,
 9 |   testTimeout: 10000
10 | }; 
```

--------------------------------------------------------------------------------
/mcp_settings_example.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "mcpServers": {
 3 |     "smartlead": {
 4 |       "command": "node",
 5 |       "args": ["E:/mcp-servers/smartlead/dist/index.js"],
 6 |       "env": {
 7 |         "SMARTLEAD_API_KEY": "your_api_key_here"
 8 |       },
 9 |       "disabled": false,
10 |       "autoApprove": [],
11 |       "name": "@jean-technologies/smartlead-mcp"
12 |     }
13 |   }
14 | }
15 | 
16 | 
17 | 
18 | 
```

--------------------------------------------------------------------------------
/src/types/statistics.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | export interface CampaignMailboxStatisticsParams {
 2 |   campaign_id: number;
 3 | }
 4 | 
 5 | export interface DownloadCampaignDataParams {
 6 |   campaign_id: number;
 7 |   download_type: 'analytics' | 'leads' | 'sequence' | 'full_export';
 8 |   format: 'json' | 'csv';
 9 |   user_id?: string;
10 | }
11 | 
12 | export interface ViewDownloadStatisticsParams {
13 |   time_period?: 'all' | 'today' | 'week' | 'month';
14 |   group_by?: 'type' | 'format' | 'campaign' | 'date';
15 | } 
```

--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "compilerOptions": {
 3 |     "target": "ES2022",
 4 |     "module": "NodeNext",
 5 |     "moduleResolution": "NodeNext",
 6 |     "esModuleInterop": true,
 7 |     "strict": true,
 8 |     "outDir": "dist",
 9 |     "declaration": true,
10 |     "sourceMap": true,
11 |     "skipLibCheck": true,
12 |     "forceConsistentCasingInFileNames": true,
13 |     "typeRoots": ["./node_modules/@types", "./src/types"]
14 |   },
15 |   "include": ["src/**/*"],
16 |   "exclude": ["node_modules", "dist", "**/*.test.ts"]
17 | }
18 | 
```

--------------------------------------------------------------------------------
/Dockerfile:
--------------------------------------------------------------------------------

```dockerfile
 1 | # Generated by https://smithery.ai. See: https://smithery.ai/docs/build/project-config
 2 | FROM node:lts-alpine
 3 | WORKDIR /app
 4 | 
 5 | # Install build tools and dependencies
 6 | COPY package.json package-lock.json tsconfig.json ./
 7 | COPY src ./src
 8 | 
 9 | RUN apk add --no-cache python3 make g++ \
10 |     && npm ci --ignore-scripts \
11 |     && npm run build \
12 |     && npm prune --production \
13 |     && apk del python3 make g++
14 | 
15 | # Default command for stdio usage
16 | CMD ["node", "dist/index.js"]
17 | 
```

--------------------------------------------------------------------------------
/src/tools/lead.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Type declarations for Lead tools
 2 | declare module './tools/lead.js' {
 3 |   import { CategoryTool } from '../types/common.js';
 4 |   
 5 |   export const LIST_LEADS_TOOL: CategoryTool;
 6 |   export const GET_LEAD_TOOL: CategoryTool;
 7 |   export const ADD_LEAD_TO_CAMPAIGN_TOOL: CategoryTool;
 8 |   export const UPDATE_LEAD_TOOL: CategoryTool;
 9 |   export const UPDATE_LEAD_STATUS_TOOL: CategoryTool;
10 |   export const BULK_IMPORT_LEADS_TOOL: CategoryTool;
11 |   export const DELETE_LEAD_TOOL: CategoryTool;
12 |   
13 |   export const leadTools: CategoryTool[];
14 | } 
```

--------------------------------------------------------------------------------
/src/types/common.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { Tool } from '@modelcontextprotocol/sdk/types.js';
 2 | 
 3 | // Extended Tool type with category information
 4 | export interface CategoryTool extends Tool {
 5 |   category: string;
 6 | }
 7 | 
 8 | // Categories enum
 9 | export enum ToolCategory {
10 |   CAMPAIGN_MANAGEMENT = 'campaignManagement',
11 |   EMAIL_ACCOUNT_MANAGEMENT = 'emailAccountManagement',
12 |   LEAD_MANAGEMENT = 'leadManagement',
13 |   CAMPAIGN_STATISTICS = 'campaignStatistics',
14 |   SMART_DELIVERY = 'smartDelivery',
15 |   WEBHOOKS = 'webhooks',
16 |   CLIENT_MANAGEMENT = 'clientManagement',
17 |   SMART_SENDERS = 'smartSenders'
18 | } 
```

--------------------------------------------------------------------------------
/src/tools/statistics.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Type declarations for Statistics tools
 2 | declare module './tools/statistics.js' {
 3 |   import { CategoryTool } from '../types/common.js';
 4 |   
 5 |   export const CAMPAIGN_STATISTICS_TOOL: CategoryTool;
 6 |   export const CAMPAIGN_STATISTICS_BY_DATE_TOOL: CategoryTool;
 7 |   export const WARMUP_STATS_BY_EMAIL_TOOL: CategoryTool;
 8 |   export const CAMPAIGN_TOP_LEVEL_ANALYTICS_TOOL: CategoryTool;
 9 |   export const CAMPAIGN_TOP_LEVEL_ANALYTICS_BY_DATE_TOOL: CategoryTool;
10 |   export const CAMPAIGN_LEAD_STATISTICS_TOOL: CategoryTool;
11 |   export const CAMPAIGN_MAILBOX_STATISTICS_TOOL: CategoryTool;
12 |   
13 |   export const statisticsTools: CategoryTool[];
14 | } 
```

--------------------------------------------------------------------------------
/src/tools/email.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Type declarations for Email tools
 2 | declare module './tools/email.js' {
 3 |   import { CategoryTool } from '../types/common.js';
 4 |   
 5 |   export const LIST_EMAIL_ACCOUNTS_CAMPAIGN_TOOL: CategoryTool;
 6 |   export const ADD_EMAIL_TO_CAMPAIGN_TOOL: CategoryTool;
 7 |   export const REMOVE_EMAIL_FROM_CAMPAIGN_TOOL: CategoryTool;
 8 |   export const FETCH_EMAIL_ACCOUNTS_TOOL: CategoryTool;
 9 |   export const CREATE_EMAIL_ACCOUNT_TOOL: CategoryTool;
10 |   export const UPDATE_EMAIL_ACCOUNT_TOOL: CategoryTool;
11 |   export const FETCH_EMAIL_ACCOUNT_BY_ID_TOOL: CategoryTool;
12 |   export const UPDATE_EMAIL_WARMUP_TOOL: CategoryTool;
13 |   export const RECONNECT_EMAIL_ACCOUNT_TOOL: CategoryTool;
14 |   export const UPDATE_EMAIL_ACCOUNT_TAG_TOOL: CategoryTool;
15 |   
16 |   export const emailTools: CategoryTool[];
17 | } 
```

--------------------------------------------------------------------------------
/src/types/supergateway.d.ts:
--------------------------------------------------------------------------------

```typescript
 1 | /**
 2 |  * Type definitions for Supergateway
 3 |  */
 4 | 
 5 | declare module 'supergateway' {
 6 |   export class SuperGateway {
 7 |     /**
 8 |      * Create a new SuperGateway instance
 9 |      * @param options Configuration options including API key
10 |      */
11 |     constructor(options?: { apiKey?: string, [key: string]: any });
12 |   
13 |     /**
14 |      * Process a request
15 |      * @param input Input text to process
16 |      * @param options Processing options
17 |      * @returns Processed text
18 |      */
19 |     process(input: string, options?: Record<string, any>): Promise<string>;
20 |   
21 |     /**
22 |      * Stream a request response
23 |      * @param input Input text to process
24 |      * @param options Processing options
25 |      * @returns Readable stream with response chunks
26 |      */
27 |     stream(input: string, options?: Record<string, any>): Promise<ReadableStream>;
28 |   
29 |     /**
30 |      * Close the client connection
31 |      */
32 |     close(): Promise<void>;
33 |   }
34 | }
```

--------------------------------------------------------------------------------
/smithery.yaml:
--------------------------------------------------------------------------------

```yaml
 1 | # Smithery configuration file: https://smithery.ai/docs/build/project-config
 2 | 
 3 | startCommand:
 4 |   type: stdio
 5 |   commandFunction:
 6 |     # A JS function that produces the CLI command based on the given config to start the MCP on stdio.
 7 |     |-
 8 |     (config) => ({ command: 'node', args: ['dist/index.js'], env: { SMARTLEAD_API_KEY: config.smartleadApiKey, JEAN_LICENSE_KEY: config.jeanLicenseKey || 'JEANPARTNER', ...(config.smartleadApiUrl ? { SMARTLEAD_API_URL: config.smartleadApiUrl } : {}) } })
 9 |   configSchema:
10 |     # JSON Schema defining the configuration options for the MCP.
11 |     type: object
12 |     required:
13 |       - smartleadApiKey
14 |     properties:
15 |       smartleadApiKey:
16 |         type: string
17 |         description: Smartlead API Key
18 |       jeanLicenseKey:
19 |         type: string
20 |         default: JEANPARTNER
21 |         description: Jean License Key
22 |       smartleadApiUrl:
23 |         type: string
24 |         default: https://server.smartlead.ai/api/v1
25 |         description: Optional Smartlead API URL
26 |   exampleConfig:
27 |     smartleadApiKey: YOUR_SMARTLEAD_API_KEY
28 |     jeanLicenseKey: JEANPARTNER
29 |     smartleadApiUrl: https://server.smartlead.ai/api/v1
30 | 
```

--------------------------------------------------------------------------------
/src/types/clientManagement.ts:
--------------------------------------------------------------------------------

```typescript
 1 | // Type definitions for Client Management functionality
 2 | 
 3 | // Client permission types
 4 | export type ClientPermission = 'reply_master_inbox' | 'full_access' | string;
 5 | 
 6 | // Add Client To System
 7 | export interface AddClientParams {
 8 |   name: string;
 9 |   email: string;
10 |   permission: ClientPermission[];
11 |   logo?: string;
12 |   logo_url?: string | null;
13 |   password: string;
14 | }
15 | 
16 | // Fetch all clients
17 | export interface FetchAllClientsParams {
18 |   // This endpoint doesn't require specific parameters beyond the API key
19 |   // which is handled at the API client level
20 | }
21 | 
22 | // Type guards
23 | export function isAddClientParams(args: unknown): args is AddClientParams {
24 |   if (typeof args !== 'object' || args === null) return false;
25 |   
26 |   const params = args as Partial<AddClientParams>;
27 |   
28 |   return (
29 |     typeof params.name === 'string' &&
30 |     typeof params.email === 'string' &&
31 |     Array.isArray(params.permission) &&
32 |     params.permission.every(perm => typeof perm === 'string') &&
33 |     typeof params.password === 'string' &&
34 |     (params.logo === undefined || typeof params.logo === 'string') &&
35 |     (params.logo_url === undefined || params.logo_url === null || typeof params.logo_url === 'string')
36 |   );
37 | }
38 | 
39 | export function isFetchAllClientsParams(args: unknown): args is FetchAllClientsParams {
40 |   // Since this endpoint doesn't require specific parameters beyond the API key
41 |   // Any object is valid
42 |   return typeof args === 'object' && args !== null;
43 | } 
```

--------------------------------------------------------------------------------
/src/tools/clientManagement.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { CategoryTool, ToolCategory } from '../types/common.js';
 2 | 
 3 | // Client Management Tools
 4 | 
 5 | export const ADD_CLIENT_TOOL: CategoryTool = {
 6 |   name: 'smartlead_add_client',
 7 |   description: 'Add a new client to the system, optionally with white-label settings.',
 8 |   category: ToolCategory.CLIENT_MANAGEMENT,
 9 |   inputSchema: {
10 |     type: 'object',
11 |     properties: {
12 |       name: {
13 |         type: 'string',
14 |         description: 'Name of the client',
15 |       },
16 |       email: {
17 |         type: 'string',
18 |         description: 'Email address of the client',
19 |       },
20 |       permission: {
21 |         type: 'array',
22 |         items: { type: 'string' },
23 |         description: 'Array of permissions to grant to the client. Use ["full_access"] for full permissions.',
24 |       },
25 |       logo: {
26 |         type: 'string',
27 |         description: 'Logo text or identifier',
28 |       },
29 |       logo_url: {
30 |         type: ['string', 'null'],
31 |         description: 'URL to the client\'s logo image',
32 |       },
33 |       password: {
34 |         type: 'string',
35 |         description: 'Password for the client\'s account',
36 |       },
37 |     },
38 |     required: ['name', 'email', 'permission', 'password'],
39 |   },
40 | };
41 | 
42 | export const FETCH_ALL_CLIENTS_TOOL: CategoryTool = {
43 |   name: 'smartlead_fetch_all_clients',
44 |   description: 'Retrieve a list of all clients in the system.',
45 |   category: ToolCategory.CLIENT_MANAGEMENT,
46 |   inputSchema: {
47 |     type: 'object',
48 |     properties: {
49 |       // This endpoint doesn't require specific parameters beyond the API key
50 |       // which is handled at the API client level
51 |     },
52 |     required: [],
53 |   },
54 | };
55 | 
56 | // Export all tools as an array for easy registration
57 | export const clientManagementTools = [
58 |   ADD_CLIENT_TOOL,
59 |   FETCH_ALL_CLIENTS_TOOL,
60 | ]; 
```

--------------------------------------------------------------------------------
/src/config/feature-config.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { isCategoryEnabled } from '../licensing/index.js';
 2 | 
 3 | // Configuration for enabling/disabling feature categories
 4 | // These are the default values when license validation is unavailable
 5 | export const enabledCategories = {
 6 |   campaignManagement: true,
 7 |   emailAccountManagement: true,
 8 |   leadManagement: true,
 9 |   campaignStatistics: true,
10 |   smartDelivery: true,
11 |   webhooks: true,
12 |   clientManagement: true,
13 |   smartSenders: true
14 | };
15 | 
16 | // Configuration for enabling/disabling individual tools
17 | // This overrides category settings for specific tools
18 | export const enabledTools: Record<string, boolean> = {
19 |   // Override specific tools if needed
20 |   // Example: To enable a specific tool in a disabled category:
21 |   // smartlead_fetch_campaign_sequence: true,
22 | };
23 | 
24 | // Feature flags for experimental features
25 | export const featureFlags = {
26 |   betaFeatures: process.env.ENABLE_BETA_FEATURES === 'true',
27 |   extendedLogging: process.env.EXTENDED_LOGGING === 'true',
28 |   n8nIntegration: false // Will be set by license validation
29 | };
30 | 
31 | // Helper function to check if a tool should be enabled
32 | export async function isToolEnabled(toolName: string, category: string): Promise<boolean> {
33 |   // Always enable all tools
34 |   return true;
35 |   
36 |   // The following code is kept for reference but will never execute
37 |   // // Check if the tool has a specific override
38 |   // if (enabledTools[toolName] !== undefined) {
39 |   //   return enabledTools[toolName];
40 |   // }
41 |   // 
42 |   // // Otherwise, check if the category is enabled by the license
43 |   // try {
44 |   //   return await isCategoryEnabled(category);
45 |   // } catch (error) {
46 |   //   // Fallback to default configuration if license check fails
47 |   //   console.error(`License validation failed, using default configuration: ${error}`);
48 |   //   const categoryKey = category as keyof typeof enabledCategories;
49 |   //   return enabledCategories[categoryKey] || false;
50 |   // }
51 | } 
```

--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------

```json
 1 | {
 2 |   "name": "smartlead-mcp-server",
 3 |   "version": "1.2.1",
 4 |   "description": "MCP server for Smartlead campaign management integration. Features include creating campaigns, updating campaign settings, and managing campaign sequences.",
 5 |   "author": "Jonathan Politzki",
 6 |   "type": "module",
 7 |   "bin": {
 8 |     "smartlead-mcp": "dist/cli.js"
 9 |   },
10 |   "files": [
11 |     "dist"
12 |   ],
13 |   "scripts": {
14 |     "build": "tsc",
15 |     "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js",
16 |     "test:supergateway": "node test_supergateway.js",
17 |     "start": "node dist/index.js",
18 |     "start:supergateway": "USE_SUPERGATEWAY=true SUPERGATEWAY_API_KEY=test_key node dist/index.js",
19 |     "start:sse": "npx -y supergateway --stdio \"node dist/index.js\" --port 3000",
20 |     "start:sse-supergateway": "npx -y supergateway --stdio \"USE_SUPERGATEWAY=true SUPERGATEWAY_API_KEY=test_key node dist/index.js\" --port 3000",
21 |     "dev": "npm run build && npm start",
22 |     "dev:supergateway": "npm run build && npm run start:supergateway",
23 |     "dev:sse": "npm run build && npm run start:sse",
24 |     "dev:sse-supergateway": "npm run build && npm run start:sse-supergateway",
25 |     "lint": "eslint src/**/*.ts",
26 |     "lint:fix": "eslint src/**/*.ts --fix",
27 |     "format": "prettier --write .",
28 |     "prepare": "npm run build"
29 |   },
30 |   "license": "MIT",
31 |   "dependencies": {
32 |     "@modelcontextprotocol/sdk": "^1.4.1",
33 |     "axios": "^1.6.2",
34 |     "commander": "^13.1.0",
35 |     "dotenv": "^16.4.7",
36 |     "mcp-proxy-auth": "^1.0.2",
37 |     "p-queue": "^8.0.1",
38 |     "uuid": "^11.1.0"
39 |   },
40 |   "devDependencies": {
41 |     "@jest/globals": "^29.7.0",
42 |     "@types/jest": "^29.5.14",
43 |     "@types/node": "^20.10.5",
44 |     "@types/uuid": "^10.0.0",
45 |     "@typescript-eslint/eslint-plugin": "^7.0.0",
46 |     "@typescript-eslint/parser": "^7.0.0",
47 |     "eslint": "^8.56.0",
48 |     "eslint-config-prettier": "^9.1.0",
49 |     "jest": "^29.7.0",
50 |     "jest-mock-extended": "^4.0.0-beta1",
51 |     "prettier": "^3.1.1",
52 |     "ts-jest": "^29.1.1",
53 |     "typescript": "^5.3.3"
54 |   },
55 |   "engines": {
56 |     "node": ">=18.0.0"
57 |   },
58 |   "keywords": [
59 |     "mcp",
60 |     "smartlead",
61 |     "campaign-management",
62 |     "email-marketing"
63 |   ]
64 | }
65 | 
```

--------------------------------------------------------------------------------
/src/supergateway-mock.ts:
--------------------------------------------------------------------------------

```typescript
 1 |  /**
 2 |  * Mock implementation of the SuperGateway client
 3 |  * This is used as a fallback when the real SuperGateway package is not available
 4 |  */
 5 | 
 6 | /**
 7 |  * SuperGateway client mock implementation
 8 |  */
 9 | export class SuperGateway {
10 |   private apiKey: string | undefined;
11 |   private options: Record<string, any>;
12 | 
13 |   /**
14 |    * Create a new SuperGateway instance
15 |    * @param options Configuration options
16 |    */
17 |   constructor(options: { apiKey?: string, [key: string]: any } = {}) {
18 |     console.error('[Supergateway] Initialized with API key:', options.apiKey ? '[REDACTED]' : 'undefined');
19 |     this.apiKey = options.apiKey;
20 |     this.options = { ...options };
21 |     
22 |     // Remove apiKey from options to avoid logging it
23 |     delete this.options.apiKey;
24 |   }
25 | 
26 |   /**
27 |    * Process a request
28 |    * @param input Input text to process
29 |    * @param options Processing options
30 |    * @returns Processed text
31 |    */
32 |   async process(input: string, options?: Record<string, any>): Promise<string> {
33 |     console.error('[Supergateway] Processing request');
34 |     console.error('[Supergateway] Input:', input);
35 |     console.error('[Supergateway] Options:', options);
36 |     
37 |     // Simulate processing delay
38 |     await new Promise(resolve => setTimeout(resolve, 500));
39 |     
40 |     // Return a processed response
41 |     return `[Supergateway Mock] Processed: ${input.substring(0, 30)}...`;
42 |   }
43 | 
44 |   /**
45 |    * Stream a request response
46 |    * @param input Input text to process
47 |    * @param options Processing options
48 |    * @returns Readable stream with response chunks
49 |    */
50 |   async stream(input: string, options?: Record<string, any>): Promise<ReadableStream> {
51 |     console.error('[Supergateway] Streaming request');
52 |     console.error('[Supergateway] Input:', input);
53 |     console.error('[Supergateway] Options:', options);
54 |     
55 |     // Create a readable stream for the response
56 |     return new ReadableStream({
57 |       start(controller) {
58 |         // Simulate streaming with delays
59 |         const encoder = new TextEncoder();
60 |         
61 |         // Send chunks with delays
62 |         setTimeout(() => {
63 |           controller.enqueue(encoder.encode('[Supergateway] Stream started\n\n'));
64 |         }, 100);
65 |         
66 |         setTimeout(() => {
67 |           controller.enqueue(encoder.encode('Processing input...\n\n'));
68 |         }, 500);
69 |         
70 |         setTimeout(() => {
71 |           controller.enqueue(encoder.encode('Generating response...\n\n'));
72 |         }, 1000);
73 |         
74 |         setTimeout(() => {
75 |           controller.enqueue(encoder.encode('Completed processing\n\n'));
76 |           controller.close();
77 |         }, 1500);
78 |       }
79 |     });
80 |   }
81 | 
82 |   /**
83 |    * Close the client connection
84 |    */
85 |   async close(): Promise<void> {
86 |     console.error('[Supergateway] Connection closed');
87 |   }
88 | }
```

--------------------------------------------------------------------------------
/llms-install.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Smartlead MCP Server - Installation Guide for AI Assistants
  2 | 
  3 | This guide helps AI assistants like Cline set up the Smartlead MCP Server. This server allows you to interact with Smartlead's email marketing API through the Model Context Protocol (MCP).
  4 | 
  5 | ## Prerequisites
  6 | 
  7 | - Node.js (v18 or higher)
  8 | - npm (comes with Node.js)
  9 | - A Smartlead API Key (user will need to provide this)
 10 | - Optional: A License Key (free tier is available, paid tiers have more features)
 11 | 
 12 | ## One-Click Installation Method
 13 | 
 14 | The easiest way to install this MCP server is using the npx command:
 15 | 
 16 | ```bash
 17 | # Create a directory for configurations if desired (recommended)
 18 | mkdir -p ~/.config/smartlead-mcp
 19 | cd ~/.config/smartlead-mcp
 20 | 
 21 | # Run the configuration helper
 22 | npx smartlead-mcp-server config
 23 | ```
 24 | 
 25 | This will guide you through an interactive setup process to configure the Smartlead API key and license key. The user will need to provide their Smartlead API key when prompted.
 26 | 
 27 | ## Start the Server
 28 | 
 29 | After installation and configuration, you can start the server in different modes depending on the intended use:
 30 | 
 31 | ### For Claude and other AI assistants (STDIO mode):
 32 | 
 33 | ```bash
 34 | npx smartlead-mcp-server start
 35 | ```
 36 | 
 37 | ### For n8n automation (SSE mode):
 38 | 
 39 | ```bash
 40 | npx smartlead-mcp-server sse
 41 | ```
 42 | 
 43 | ## Integration with Cline
 44 | 
 45 | To set up Cline to use this MCP server:
 46 | 
 47 | 1. You'll need to add it to Cline's MCP settings:
 48 | 
 49 | ```json
 50 | {
 51 |   "mcpServers": {
 52 |     "smartlead": {
 53 |       "command": "npx",
 54 |       "args": ["smartlead-mcp-server", "start"],
 55 |       "env": {
 56 |         "SMARTLEAD_API_KEY": "user_provides_api_key_here",
 57 |         "JEAN_LICENSE_KEY": "optional_license_key_here"
 58 |       }
 59 |     }
 60 |   }
 61 | }
 62 | ```
 63 | 
 64 | 2. Ask the user for their Smartlead API key and update the configuration accordingly.
 65 | 
 66 | 3. For the license key, you can use "JEANPARTNER" for the free tier or ask the user if they have a paid license key.
 67 | 
 68 | ## Features and Capabilities
 69 | 
 70 | This MCP server provides tools for:
 71 | 
 72 | - **FREE Tier (20+ tools):**
 73 |   - Campaign Management
 74 |   - Lead Management
 75 | 
 76 | - **BASIC Tier (50+ tools):**
 77 |   - All FREE tier features
 78 |   - Campaign Statistics
 79 |   - Smart Delivery (Spam Tests, DNS Checks)
 80 |   - Webhooks
 81 |   - n8n Integration
 82 | 
 83 | - **PREMIUM Tier (All tools):**
 84 |   - All BASIC tier features
 85 |   - Client Management
 86 |   - Smart Senders (Domain/Mailbox Purchase)
 87 |   - Advanced Features
 88 | 
 89 | ## Troubleshooting
 90 | 
 91 | - If you encounter issues with configuration, run: `npx smartlead-mcp-server config`
 92 | - For license-related issues, use "JEANPARTNER" as the license key for free tier access
 93 | - If you need more tools, direct the user to [https://sea-turtle-app-64etr.ondigitalocean.app/](https://sea-turtle-app-64etr.ondigitalocean.app/) to purchase a license
 94 | 
 95 | ## License Information
 96 | 
 97 | This MCP server is available under the MIT license. The number of machines allowed varies by license tier:
 98 | - FREE tier: 1 machine
 99 | - BASIC tier: 2 machines
100 | - PREMIUM tier: 5 machines 
```

--------------------------------------------------------------------------------
/src/supergateway.ts:
--------------------------------------------------------------------------------

```typescript
 1 | import { SuperGateway as MockSuperGateway } from './supergateway-mock.js';
 2 | import { isFeatureEnabled, LicenseLevel } from './licensing/index.js';
 3 | 
 4 | /**
 5 |  * Interface for SupergateWay options
 6 |  */
 7 | export interface SuperGatewayOptions {
 8 |   apiKey?: string;
 9 |   [key: string]: any;
10 | }
11 | 
12 | /**
13 |  * Interface for SuperGateway API
14 |  */
15 | export interface SuperGateway {
16 |   process(input: string, options?: Record<string, any>): Promise<string>;
17 |   stream(input: string, options?: Record<string, any>): Promise<ReadableStream>;
18 |   close(): Promise<void>;
19 | }
20 | 
21 | /**
22 |  * Try to dynamically import Supergateway package
23 |  */
24 | export async function tryImportSupergateway(): Promise<any> {
25 |   try {
26 |     // First try to import the real package
27 |     return await import('supergateway');
28 |   } catch (error) {
29 |     console.error(`Failed to import Supergateway: ${error instanceof Error ? error.message : String(error)}`);
30 |     console.error('Falling back to mock Supergateway implementation');
31 |     
32 |     // Return our mock implementation as a fallback
33 |     return {
34 |       SuperGateway: MockSuperGateway
35 |     };
36 |   }
37 | }
38 | 
39 | /**
40 |  * Create a Supergateway instance
41 |  */
42 | export async function createSupergateway(apiKey?: string): Promise<SuperGateway | null> {
43 |   try {
44 |     // Check if the current license allows n8n integration
45 |     const n8nIntegrationEnabled = await isFeatureEnabled('n8nIntegration');
46 |     
47 |     if (!n8nIntegrationEnabled) {
48 |       console.error('=============================================================');
49 |       console.error('ERROR: Your license does not include n8n integration features');
50 |       console.error('This feature requires a Basic or Premium license subscription.');
51 |       console.error('Visit https://yourservice.com/pricing to upgrade your plan.');
52 |       console.error('');
53 |       console.error('For testing purposes, you can obtain a Basic license from');
54 |       console.error('https://yourservice.com/pricing');
55 |       console.error('=============================================================');
56 |       return null;
57 |     }
58 |     
59 |     // Try to dynamically import the Supergateway module
60 |     const supergateModule = await tryImportSupergateway();
61 |     
62 |     if (!supergateModule) {
63 |       console.error('Supergateway module not found.');
64 |       return null;
65 |     }
66 |     
67 |     // Check if API key is provided
68 |     if (!apiKey) {
69 |       console.error('SUPERGATEWAY_API_KEY not provided');
70 |       console.error('Please set the SUPERGATEWAY_API_KEY environment variable in your .env file.');
71 |       return null;
72 |     }
73 |     
74 |     // Create Supergateway instance
75 |     const { SuperGateway } = supergateModule;
76 |     const gateway = new SuperGateway({
77 |       apiKey,
78 |       // Additional configuration options can be added here
79 |     });
80 |     
81 |     console.error('Supergateway initialized successfully');
82 |     return gateway;
83 |   } catch (error) {
84 |     console.error(`Error initializing Supergateway: ${error instanceof Error ? error.message : String(error)}`);
85 |     return null;
86 |   }
87 | }
```

--------------------------------------------------------------------------------
/DEVELOPER_ONBOARDING.md:
--------------------------------------------------------------------------------

```markdown
  1 | # Smartlead MCP Server - Developer Guide
  2 | 
  3 | ## Overview
  4 | 
  5 | Smartlead MCP Server provides an organized interface to the Smartlead API using the Model Context Protocol (MCP), enabling AI assistants and automation tools to manage email marketing campaigns.
  6 | 
  7 | ## Prerequisites
  8 | 
  9 | - Node.js (v18+)
 10 | - A Smartlead API Key
 11 | 
 12 | ## Quick Start Options
 13 | 
 14 | ### Option 1: Use npx (Recommended)
 15 | 
 16 | ```bash
 17 | # For Claude
 18 | npx smartlead-mcp-server start
 19 | 
 20 | # For n8n
 21 | npx smartlead-mcp-server sse
 22 | ```
 23 | 
 24 | ### Option 2: Development Setup
 25 | 
 26 | ```bash
 27 | # Clone and install
 28 | git clone https://github.com/jean-technologies/smartlead-mcp-server-local.git
 29 | cd smartlead-mcp-server-local
 30 | npm install
 31 | 
 32 | # Configure and build
 33 | cp .env.example .env  # Then edit with your API key
 34 | npm run build
 35 | 
 36 | # Run
 37 | npm start  # For Claude
 38 | # OR
 39 | npm run start:sse  # For n8n
 40 | ```
 41 | 
 42 | ## Two Integration Pathways
 43 | 
 44 | ### 1. Claude Integration
 45 | 
 46 | Add to Claude settings JSON:
 47 | ```json
 48 | {
 49 |   "mcp": {
 50 |     "name": "smartlead",
 51 |     "command": "npx",
 52 |     "args": ["smartlead-mcp-server", "start"],
 53 |     "env": {
 54 |       "SMARTLEAD_API_KEY": "your_api_key_here"
 55 |     }
 56 |   }
 57 | }
 58 | ```
 59 | 
 60 | ### 2. n8n Integration
 61 | 
 62 | #### Local n8n:
 63 | 1. Run server: `npx smartlead-mcp-server sse`
 64 | 2. Configure n8n MCP node with:
 65 |    - SSE URL: `http://localhost:3000/sse`
 66 |    - Message URL: `http://localhost:3000/message`
 67 | 
 68 | #### n8n Cloud:
 69 | 1. Run server: `npx smartlead-mcp-server sse`
 70 | 2. Create tunnel: `npx ngrok http 3000`
 71 | 3. Use ngrok URL in n8n MCP node
 72 | 
 73 | ## Available Features
 74 | 
 75 | All features are now enabled by default, including:
 76 | - Campaign & Lead Management
 77 | - Statistics and Analytics
 78 | - Smart Delivery & Webhooks
 79 | - n8n Integration
 80 | - Client Management
 81 | - Smart Senders
 82 | - Download Tracking and Analytics
 83 | 
 84 | ## Download Tracking System
 85 | 
 86 | ### Implementation Details
 87 | 
 88 | The download tracking system stores records in `~/.smartlead-mcp/downloads.json` with the following structure:
 89 | 
 90 | ```json
 91 | {
 92 |   "downloads": [
 93 |     {
 94 |       "id": "unique-download-id",
 95 |       "timestamp": "2023-06-15T12:34:56.789Z",
 96 |       "campaignId": 12345,
 97 |       "downloadType": "analytics",
 98 |       "format": "json",
 99 |       "userId": "optional-user-id",
100 |       "machineId": "machine-identifier"
101 |     }
102 |   ]
103 | }
104 | ```
105 | 
106 | ### Available Tools
107 | 
108 | 1. **Download Campaign Data**: `smartlead_download_campaign_data`
109 |    - Fetches data from Smartlead API
110 |    - Converts to CSV if requested
111 |    - Automatically tracks download details
112 | 
113 | 2. **View Download Statistics**: `smartlead_view_download_statistics`
114 |    - Filter by time period (all, today, week, month)
115 |    - Group by various dimensions (type, format, campaign, date)
116 |    - Get usage insights and recent downloads
117 | 
118 | ## Troubleshooting
119 | 
120 | ### Common Solutions
121 | - Configure settings: `npx smartlead-mcp-server config`
122 | - Set API key directly: `npx smartlead-mcp-server sse --api-key=YOUR_API_KEY`
123 | - Debug mode: `DEBUG=smartlead:* npx smartlead-mcp-server start`
124 | 
125 | ## Resources
126 | 
127 | - [Smartlead API Docs](https://docs.smartlead.ai)
128 | - [MCP Specification](https://github.com/modelcontextprotocol/spec)
129 | - [n8n Integration Guide](https://docs.n8n.io) 
```

--------------------------------------------------------------------------------
/src/handlers/clientManagement.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { AxiosInstance } from 'axios';
  2 | import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
  3 | import {
  4 |   isAddClientParams,
  5 |   isFetchAllClientsParams
  6 | } from '../types/clientManagement.js';
  7 | 
  8 | // SmartLead API base URL
  9 | const SMARTLEAD_API_URL = 'https://server.smartlead.ai/api/v1';
 10 | 
 11 | // Handler for Client Management-related tools
 12 | export async function handleClientManagementTool(
 13 |   toolName: string,
 14 |   args: unknown,
 15 |   apiClient: AxiosInstance,
 16 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
 17 | ) {
 18 |   switch (toolName) {
 19 |     case 'smartlead_add_client': {
 20 |       return handleAddClient(args, apiClient, withRetry);
 21 |     }
 22 |     case 'smartlead_fetch_all_clients': {
 23 |       return handleFetchAllClients(args, apiClient, withRetry);
 24 |     }
 25 |     default:
 26 |       throw new Error(`Unknown Client Management tool: ${toolName}`);
 27 |   }
 28 | }
 29 | 
 30 | // Create a modified client for SmartLead API with the correct base URL
 31 | function createSmartLeadClient(apiClient: AxiosInstance) {
 32 |   return {
 33 |     get: (url: string, config?: any) => 
 34 |       apiClient.get(`${SMARTLEAD_API_URL}${url}`, config),
 35 |     post: (url: string, data?: any, config?: any) => 
 36 |       apiClient.post(`${SMARTLEAD_API_URL}${url}`, data, config),
 37 |     put: (url: string, data?: any, config?: any) => 
 38 |       apiClient.put(`${SMARTLEAD_API_URL}${url}`, data, config),
 39 |     delete: (url: string, config?: any) => 
 40 |       apiClient.delete(`${SMARTLEAD_API_URL}${url}`, config)
 41 |   };
 42 | }
 43 | 
 44 | // Individual handlers for each tool
 45 | async function handleAddClient(
 46 |   args: unknown,
 47 |   apiClient: AxiosInstance,
 48 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
 49 | ) {
 50 |   if (!isAddClientParams(args)) {
 51 |     throw new McpError(
 52 |       ErrorCode.InvalidParams,
 53 |       'Invalid arguments for smartlead_add_client'
 54 |     );
 55 |   }
 56 | 
 57 |   try {
 58 |     const smartLeadClient = createSmartLeadClient(apiClient);
 59 |     
 60 |     const response = await withRetry(
 61 |       async () => smartLeadClient.post('/client/save', args),
 62 |       'add client'
 63 |     );
 64 | 
 65 |     return {
 66 |       content: [
 67 |         {
 68 |           type: 'text',
 69 |           text: JSON.stringify(response.data, null, 2),
 70 |         },
 71 |       ],
 72 |       isError: false,
 73 |     };
 74 |   } catch (error: any) {
 75 |     return {
 76 |       content: [{ 
 77 |         type: 'text', 
 78 |         text: `API Error: ${error.response?.data?.message || error.message}` 
 79 |       }],
 80 |       isError: true,
 81 |     };
 82 |   }
 83 | }
 84 | 
 85 | async function handleFetchAllClients(
 86 |   args: unknown,
 87 |   apiClient: AxiosInstance,
 88 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
 89 | ) {
 90 |   if (!isFetchAllClientsParams(args)) {
 91 |     throw new McpError(
 92 |       ErrorCode.InvalidParams,
 93 |       'Invalid arguments for smartlead_fetch_all_clients'
 94 |     );
 95 |   }
 96 | 
 97 |   try {
 98 |     const smartLeadClient = createSmartLeadClient(apiClient);
 99 |     
100 |     const response = await withRetry(
101 |       async () => smartLeadClient.get('/client/'),
102 |       'fetch all clients'
103 |     );
104 | 
105 |     return {
106 |       content: [
107 |         {
108 |           type: 'text',
109 |           text: JSON.stringify(response.data, null, 2),
110 |         },
111 |       ],
112 |       isError: false,
113 |     };
114 |   } catch (error: any) {
115 |     return {
116 |       content: [{ 
117 |         type: 'text', 
118 |         text: `API Error: ${error.response?.data?.message || error.message}` 
119 |       }],
120 |       isError: true,
121 |     };
122 |   }
123 | } 
```

--------------------------------------------------------------------------------
/src/registry/tool-registry.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { CategoryTool } from '../types/common.js';
  2 | import { isToolEnabled } from '../config/feature-config.js';
  3 | import { validateLicense, LicenseLevel } from '../licensing/index.js';
  4 | 
  5 | /**
  6 |  * Tool Registry manages the registration and querying of all available tools.
  7 |  * It provides a central place to register, filter, and retrieve tools by various criteria.
  8 |  */
  9 | export class ToolRegistry {
 10 |   private tools: Map<string, CategoryTool> = new Map();
 11 |   private cachedEnabledTools: CategoryTool[] | null = null;
 12 |   private lastCacheTime = 0;
 13 |   private readonly CACHE_TTL = 60000; // 1 minute
 14 |   
 15 |   /**
 16 |    * Register a single tool in the registry
 17 |    */
 18 |   register(tool: CategoryTool): void {
 19 |     this.tools.set(tool.name, tool);
 20 |     // Invalidate cache when tools change
 21 |     this.cachedEnabledTools = null;
 22 |   }
 23 |   
 24 |   /**
 25 |    * Register multiple tools at once
 26 |    */
 27 |   registerMany(tools: CategoryTool[]): void {
 28 |     tools.forEach(tool => this.register(tool));
 29 |   }
 30 |   
 31 |   /**
 32 |    * Get a tool by its name
 33 |    */
 34 |   getByName(name: string): CategoryTool | undefined {
 35 |     return this.tools.get(name);
 36 |   }
 37 |   
 38 |   /**
 39 |    * Get all tools that belong to a specific category
 40 |    */
 41 |   getByCategory(category: string): CategoryTool[] {
 42 |     return Array.from(this.tools.values())
 43 |       .filter(tool => tool.category === category);
 44 |   }
 45 |   
 46 |   /**
 47 |    * Get all registered tools
 48 |    */
 49 |   getAllTools(): CategoryTool[] {
 50 |     return Array.from(this.tools.values());
 51 |   }
 52 |   
 53 |   /**
 54 |    * Get all tools that are enabled based on the license and configuration
 55 |    * This method now returns a subset based on the current license
 56 |    */
 57 |   async getEnabledToolsAsync(): Promise<CategoryTool[]> {
 58 |     const now = Date.now();
 59 |     
 60 |     // Use cache if available and not expired
 61 |     if (this.cachedEnabledTools && (now - this.lastCacheTime < this.CACHE_TTL)) {
 62 |       return this.cachedEnabledTools;
 63 |     }
 64 |     
 65 |     // Get license to check allowed categories
 66 |     const license = await validateLicense();
 67 |     
 68 |     // Filter tools based on license-allowed categories
 69 |     const enabledTools = this.getAllTools().filter(tool => 
 70 |       license.features.allowedCategories.includes(tool.category)
 71 |     );
 72 |     
 73 |     // Cache results
 74 |     this.cachedEnabledTools = enabledTools;
 75 |     this.lastCacheTime = now;
 76 |     
 77 |     return enabledTools;
 78 |   }
 79 |   
 80 |   /**
 81 |    * Get enabled tools (synchronous version, falls back to configuration)
 82 |    * This is used for backward compatibility
 83 |    */
 84 |   getEnabledTools(): CategoryTool[] {
 85 |     // If we have a cache, use it
 86 |     if (this.cachedEnabledTools) {
 87 |       return this.cachedEnabledTools;
 88 |     }
 89 |     
 90 |     // Otherwise fall back to config-based filtering
 91 |     // This uses the local configuration as a fallback
 92 |     return this.getAllTools().filter(tool => {
 93 |       try {
 94 |         return isToolEnabled(tool.name, tool.category);
 95 |       } catch (e) {
 96 |         // If async check fails, use default behavior
 97 |         return false;
 98 |       }
 99 |     });
100 |   }
101 |   
102 |   /**
103 |    * Check if a tool with the given name exists in the registry
104 |    */
105 |   hasToolWithName(name: string): boolean {
106 |     return this.tools.has(name);
107 |   }
108 |   
109 |   /**
110 |    * Check if a tool belongs to the specified category
111 |    */
112 |   isToolInCategory(name: string, category: string): boolean {
113 |     const tool = this.getByName(name);
114 |     return !!tool && tool.category === category;
115 |   }
116 | }
117 | 
118 | // Create a singleton instance
119 | export const toolRegistry = new ToolRegistry(); 
```

--------------------------------------------------------------------------------
/src/n8n/index.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import axios from 'axios';
  2 | import { LicenseLevel, validateLicense, getFeatureToken } from '../licensing/index.js';
  3 | 
  4 | const N8N_CONFIG = {
  5 |   apiUrl: process.env.N8N_API_URL || 'https://n8n.yourservice.com/api/v1',
  6 | };
  7 | 
  8 | /**
  9 |  * Get workflows from n8n
 10 |  * This is a premium feature that requires server-side validation
 11 |  */
 12 | export async function getWorkflows() {
 13 |   // First check if n8n integration is available based on license
 14 |   const licenseInfo = await validateLicense();
 15 |   if (licenseInfo.level !== LicenseLevel.PREMIUM) {
 16 |     throw new Error(
 17 |       `N8n integration requires a Premium license. Your current license level is ${licenseInfo.level}. ` +
 18 |       'Please upgrade to access this feature.'
 19 |     );
 20 |   }
 21 |   
 22 |   // Get a feature token for server-side validation
 23 |   const featureToken = await getFeatureToken();
 24 |   if (!featureToken) {
 25 |     throw new Error('Unable to validate premium feature access. Please try again later.');
 26 |   }
 27 |   
 28 |   try {
 29 |     // Make the API call with the feature token
 30 |     const response = await axios.get(`${N8N_CONFIG.apiUrl}/workflows`, {
 31 |       headers: {
 32 |         'Authorization': `Bearer ${process.env.JEAN_LICENSE_KEY}`,
 33 |         'X-Feature-Token': featureToken.token
 34 |       }
 35 |     });
 36 |     
 37 |     return response.data;
 38 |   } catch (error) {
 39 |     // Handle API errors
 40 |     if (axios.isAxiosError(error) && error.response) {
 41 |       // If server rejected the feature token
 42 |       if (error.response.status === 403) {
 43 |         throw new Error('Premium feature access denied. Please check your license status.');
 44 |       }
 45 |       
 46 |       // Other API errors
 47 |       throw new Error(`Failed to fetch n8n workflows: ${error.response.data?.message || error.message}`);
 48 |     }
 49 |     
 50 |     // Generic error
 51 |     throw new Error(`Error accessing n8n integration: ${error instanceof Error ? error.message : String(error)}`);
 52 |   }
 53 | }
 54 | 
 55 | /**
 56 |  * Execute a workflow in n8n
 57 |  * This is a premium feature that requires server-side validation
 58 |  */
 59 | export async function executeWorkflow(workflowId: string, data: any) {
 60 |   // First check if n8n integration is available based on license
 61 |   const licenseInfo = await validateLicense();
 62 |   if (licenseInfo.level !== LicenseLevel.PREMIUM) {
 63 |     throw new Error(
 64 |       `N8n integration requires a Premium license. Your current license level is ${licenseInfo.level}. ` +
 65 |       'Please upgrade to access this feature.'
 66 |     );
 67 |   }
 68 |   
 69 |   // Get a feature token for server-side validation
 70 |   const featureToken = await getFeatureToken();
 71 |   if (!featureToken) {
 72 |     throw new Error('Unable to validate premium feature access. Please try again later.');
 73 |   }
 74 |   
 75 |   try {
 76 |     // Make the API call with the feature token
 77 |     const response = await axios.post(
 78 |       `${N8N_CONFIG.apiUrl}/workflows/${workflowId}/execute`, 
 79 |       data,
 80 |       {
 81 |         headers: {
 82 |           'Authorization': `Bearer ${process.env.JEAN_LICENSE_KEY}`,
 83 |           'X-Feature-Token': featureToken.token,
 84 |           'Content-Type': 'application/json'
 85 |         }
 86 |       }
 87 |     );
 88 |     
 89 |     return response.data;
 90 |   } catch (error) {
 91 |     // Handle API errors
 92 |     if (axios.isAxiosError(error) && error.response) {
 93 |       // If server rejected the feature token
 94 |       if (error.response.status === 403) {
 95 |         throw new Error('Premium feature access denied. Please check your license status.');
 96 |       }
 97 |       
 98 |       // Other API errors
 99 |       throw new Error(`Failed to execute n8n workflow: ${error.response.data?.message || error.message}`);
100 |     }
101 |     
102 |     // Generic error
103 |     throw new Error(`Error accessing n8n integration: ${error instanceof Error ? error.message : String(error)}`);
104 |   }
105 | } 
```

--------------------------------------------------------------------------------
/src/types/webhooks.ts:
--------------------------------------------------------------------------------

```typescript
  1 | // Type definitions for Webhooks functionality
  2 | 
  3 | // Webhook event types
  4 | export enum WebhookEventType {
  5 |   EMAIL_SENT = 'EMAIL_SENT',
  6 |   EMAIL_OPEN = 'EMAIL_OPEN',
  7 |   EMAIL_LINK_CLICK = 'EMAIL_LINK_CLICK',
  8 |   EMAIL_REPLY = 'EMAIL_REPLY',
  9 |   LEAD_UNSUBSCRIBED = 'LEAD_UNSUBSCRIBED',
 10 |   LEAD_CATEGORY_UPDATED = 'LEAD_CATEGORY_UPDATED'
 11 | }
 12 | 
 13 | // Fetch Webhooks By Campaign ID
 14 | export interface FetchWebhooksByCampaignParams {
 15 |   campaign_id: string;
 16 | }
 17 | 
 18 | // Add / Update Campaign Webhook
 19 | export interface UpsertCampaignWebhookParams {
 20 |   campaign_id: string;
 21 |   id?: number | null; // Set to null to create a new webhook
 22 |   name: string;
 23 |   webhook_url: string;
 24 |   event_types: WebhookEventType[];
 25 |   categories?: string[];
 26 | }
 27 | 
 28 | // Delete Campaign Webhook
 29 | export interface DeleteCampaignWebhookParams {
 30 |   campaign_id: string;
 31 |   id: number; // Webhook ID to delete
 32 | }
 33 | 
 34 | // Get Webhooks Publish Summary [Private Beta]
 35 | export interface GetWebhooksPublishSummaryParams {
 36 |   campaign_id: string;
 37 |   fromTime?: string; // ISO 8601 date-time string
 38 |   toTime?: string; // ISO 8601 date-time string
 39 | }
 40 | 
 41 | // Retrigger Failed Events [Private Beta]
 42 | export interface RetriggerFailedEventsParams {
 43 |   campaign_id: string;
 44 |   fromTime: string; // ISO 8601 date-time string
 45 |   toTime: string; // ISO 8601 date-time string
 46 | }
 47 | 
 48 | // Type guards
 49 | export function isFetchWebhooksByCampaignParams(args: unknown): args is FetchWebhooksByCampaignParams {
 50 |   return (
 51 |     typeof args === 'object' &&
 52 |     args !== null &&
 53 |     'campaign_id' in args &&
 54 |     typeof (args as FetchWebhooksByCampaignParams).campaign_id === 'string'
 55 |   );
 56 | }
 57 | 
 58 | export function isUpsertCampaignWebhookParams(args: unknown): args is UpsertCampaignWebhookParams {
 59 |   if (typeof args !== 'object' || args === null) return false;
 60 |   
 61 |   const params = args as Partial<UpsertCampaignWebhookParams>;
 62 |   
 63 |   return (
 64 |     typeof params.campaign_id === 'string' &&
 65 |     typeof params.name === 'string' &&
 66 |     typeof params.webhook_url === 'string' &&
 67 |     Array.isArray(params.event_types) &&
 68 |     params.event_types.every(type => 
 69 |       Object.values(WebhookEventType).includes(type as WebhookEventType)
 70 |     ) &&
 71 |     (params.categories === undefined || 
 72 |       (Array.isArray(params.categories) && 
 73 |        params.categories.every(category => typeof category === 'string')
 74 |       )
 75 |     ) &&
 76 |     (params.id === undefined || params.id === null || typeof params.id === 'number')
 77 |   );
 78 | }
 79 | 
 80 | export function isDeleteCampaignWebhookParams(args: unknown): args is DeleteCampaignWebhookParams {
 81 |   return (
 82 |     typeof args === 'object' &&
 83 |     args !== null &&
 84 |     'campaign_id' in args &&
 85 |     typeof (args as DeleteCampaignWebhookParams).campaign_id === 'string' &&
 86 |     'id' in args &&
 87 |     typeof (args as DeleteCampaignWebhookParams).id === 'number'
 88 |   );
 89 | }
 90 | 
 91 | export function isGetWebhooksPublishSummaryParams(args: unknown): args is GetWebhooksPublishSummaryParams {
 92 |   if (typeof args !== 'object' || args === null) return false;
 93 |   
 94 |   const params = args as Partial<GetWebhooksPublishSummaryParams>;
 95 |   
 96 |   return (
 97 |     typeof params.campaign_id === 'string' &&
 98 |     (params.fromTime === undefined || typeof params.fromTime === 'string') &&
 99 |     (params.toTime === undefined || typeof params.toTime === 'string')
100 |   );
101 | }
102 | 
103 | export function isRetriggerFailedEventsParams(args: unknown): args is RetriggerFailedEventsParams {
104 |   if (typeof args !== 'object' || args === null) return false;
105 |   
106 |   const params = args as Partial<RetriggerFailedEventsParams>;
107 |   
108 |   return (
109 |     typeof params.campaign_id === 'string' &&
110 |     typeof params.fromTime === 'string' &&
111 |     typeof params.toTime === 'string'
112 |   );
113 | } 
```

--------------------------------------------------------------------------------
/src/types/email.d.ts:
--------------------------------------------------------------------------------

```typescript
  1 | // Type declarations for Email Account parameters
  2 | declare module '../types/email.js' {
  3 |   export function isListEmailAccountsParams(args: unknown): args is ListEmailAccountsParams;
  4 |   export function isAddEmailToCampaignParams(args: unknown): args is AddEmailToCampaignParams;
  5 |   export function isRemoveEmailFromCampaignParams(args: unknown): args is RemoveEmailFromCampaignParams;
  6 |   export function isFetchEmailAccountsParams(args: unknown): args is FetchEmailAccountsParams;
  7 |   export function isCreateEmailAccountParams(args: unknown): args is CreateEmailAccountParams;
  8 |   export function isUpdateEmailAccountParams(args: unknown): args is UpdateEmailAccountParams;
  9 |   export function isFetchEmailAccountByIdParams(args: unknown): args is FetchEmailAccountByIdParams;
 10 |   export function isUpdateEmailWarmupParams(args: unknown): args is UpdateEmailWarmupParams;
 11 |   export function isReconnectEmailAccountParams(args: unknown): args is ReconnectEmailAccountParams;
 12 |   export function isUpdateEmailAccountTagParams(args: unknown): args is UpdateEmailAccountTagParams;
 13 | 
 14 |   export interface ListEmailAccountsParams {
 15 |     campaign_id?: number;
 16 |     status?: string;
 17 |     limit?: number;
 18 |     offset?: number;
 19 |   }
 20 | 
 21 |   export interface AddEmailToCampaignParams {
 22 |     campaign_id: number;
 23 |     email_account_id: number;
 24 |   }
 25 | 
 26 |   export interface RemoveEmailFromCampaignParams {
 27 |     campaign_id: number;
 28 |     email_account_id: number;
 29 |   }
 30 | 
 31 |   export interface FetchEmailAccountsParams {
 32 |     status?: string;
 33 |     limit?: number;
 34 |     offset?: number;
 35 |     username?: string;
 36 |     client_id?: number;
 37 |   }
 38 | 
 39 |   export interface CreateEmailAccountParams {
 40 |     from_name: string;
 41 |     from_email: string;
 42 |     user_name: string;
 43 |     password: string;
 44 |     smtp_host: string;
 45 |     smtp_port: number;
 46 |     imap_host: string;
 47 |     imap_port: number;
 48 |     max_email_per_day?: number;
 49 |     custom_tracking_url?: string;
 50 |     bcc?: string;
 51 |     signature?: string;
 52 |     warmup_enabled?: boolean;
 53 |     total_warmup_per_day?: number;
 54 |     daily_rampup?: number;
 55 |     reply_rate_percentage?: number;
 56 |     client_id?: number;
 57 |   }
 58 | 
 59 |   export interface UpdateEmailAccountParams {
 60 |     email_account_id: number;
 61 |     max_email_per_day?: number;
 62 |     custom_tracking_url?: string;
 63 |     bcc?: string;
 64 |     signature?: string;
 65 |     client_id?: number | null;
 66 |     time_to_wait_in_mins?: number;
 67 |   }
 68 | 
 69 |   export interface FetchEmailAccountByIdParams {
 70 |     email_account_id: number;
 71 |   }
 72 | 
 73 |   export interface UpdateEmailWarmupParams {
 74 |     email_account_id: number;
 75 |     warmup_enabled: string;
 76 |     total_warmup_per_day?: number;
 77 |     daily_rampup?: number;
 78 |     reply_rate_percentage?: string;
 79 |     warmup_key_id?: string;
 80 |   }
 81 | 
 82 |   export interface ReconnectEmailAccountParams {
 83 |     email_account_id: number;
 84 |     connection_details?: {
 85 |       smtp_host?: string;
 86 |       smtp_port?: number;
 87 |       smtp_username?: string;
 88 |       smtp_password?: string;
 89 |       imap_host?: string;
 90 |       imap_port?: number;
 91 |       imap_username?: string;
 92 |       imap_password?: string;
 93 |       oauth_token?: string;
 94 |     };
 95 |   }
 96 | 
 97 |   export interface UpdateEmailAccountTagParams {
 98 |     id: number;
 99 |     name: string;
100 |     color: string;
101 |   }
102 | 
103 |   export interface EmailAccount {
104 |     id: number;
105 |     email: string;
106 |     name?: string;
107 |     provider: string;
108 |     status: string;
109 |     created_at: string;
110 |     updated_at: string;
111 |     last_checked_at?: string;
112 |     warmup_enabled: boolean;
113 |     daily_limit?: number;
114 |     tags?: string[];
115 |   }
116 | 
117 |   export interface EmailAccountResponse {
118 |     success: boolean;
119 |     data: EmailAccount;
120 |     message?: string;
121 |   }
122 | 
123 |   export interface EmailAccountListResponse {
124 |     success: boolean;
125 |     data: {
126 |       accounts: EmailAccount[];
127 |       total: number;
128 |     };
129 |     message?: string;
130 |   }
131 | 
132 |   export interface EmailAccountActionResponse {
133 |     success: boolean;
134 |     message: string;
135 |   }
136 | } 
```

--------------------------------------------------------------------------------
/src/types/smartSenders.ts:
--------------------------------------------------------------------------------

```typescript
  1 | // Type definitions for Smart Senders functionality
  2 | 
  3 | // Get Vendors
  4 | export interface GetVendorsParams {
  5 |   // This endpoint doesn't require specific parameters beyond the API key
  6 |   // which is handled at the API client level
  7 | }
  8 | 
  9 | // Search Domain
 10 | export interface SearchDomainParams {
 11 |   domain_name: string;
 12 |   vendor_id: number;
 13 | }
 14 | 
 15 | // Mailbox details for auto-generate and order placement
 16 | export interface MailboxDetail {
 17 |   first_name: string;
 18 |   last_name: string;
 19 |   profile_pic?: string;
 20 |   mailbox?: string; // Required only for place-order
 21 | }
 22 | 
 23 | // Domain with mailbox details for auto-generate
 24 | export interface DomainWithMailboxes {
 25 |   domain_name: string;
 26 |   mailbox_details: MailboxDetail[];
 27 | }
 28 | 
 29 | // Auto-generate Mailboxes
 30 | export interface AutoGenerateMailboxesParams {
 31 |   vendor_id: number;
 32 |   domains: DomainWithMailboxes[];
 33 | }
 34 | 
 35 | // Place order for mailboxes
 36 | export interface PlaceOrderParams {
 37 |   vendor_id: number;
 38 |   forwarding_domain: string;
 39 |   domains: DomainWithMailboxes[];
 40 | }
 41 | 
 42 | // Get Domain List
 43 | export interface GetDomainListParams {
 44 |   // This endpoint doesn't require specific parameters beyond the API key
 45 |   // which is handled at the API client level
 46 | }
 47 | 
 48 | // Type guards
 49 | export function isGetVendorsParams(args: unknown): args is GetVendorsParams {
 50 |   // Since this endpoint doesn't require specific parameters beyond the API key
 51 |   // Any object is valid
 52 |   return typeof args === 'object' && args !== null;
 53 | }
 54 | 
 55 | export function isSearchDomainParams(args: unknown): args is SearchDomainParams {
 56 |   if (typeof args !== 'object' || args === null) return false;
 57 |   
 58 |   const params = args as Partial<SearchDomainParams>;
 59 |   
 60 |   return (
 61 |     typeof params.domain_name === 'string' &&
 62 |     typeof params.vendor_id === 'number'
 63 |   );
 64 | }
 65 | 
 66 | export function isMailboxDetail(obj: unknown): obj is MailboxDetail {
 67 |   if (typeof obj !== 'object' || obj === null) return false;
 68 |   
 69 |   const detail = obj as Partial<MailboxDetail>;
 70 |   
 71 |   return (
 72 |     typeof detail.first_name === 'string' &&
 73 |     typeof detail.last_name === 'string' &&
 74 |     (detail.profile_pic === undefined || typeof detail.profile_pic === 'string') &&
 75 |     (detail.mailbox === undefined || typeof detail.mailbox === 'string')
 76 |   );
 77 | }
 78 | 
 79 | export function isDomainWithMailboxes(obj: unknown): obj is DomainWithMailboxes {
 80 |   if (typeof obj !== 'object' || obj === null) return false;
 81 |   
 82 |   const domain = obj as Partial<DomainWithMailboxes>;
 83 |   
 84 |   return (
 85 |     typeof domain.domain_name === 'string' &&
 86 |     Array.isArray(domain.mailbox_details) &&
 87 |     domain.mailbox_details.every(detail => isMailboxDetail(detail))
 88 |   );
 89 | }
 90 | 
 91 | export function isAutoGenerateMailboxesParams(args: unknown): args is AutoGenerateMailboxesParams {
 92 |   if (typeof args !== 'object' || args === null) return false;
 93 |   
 94 |   const params = args as Partial<AutoGenerateMailboxesParams>;
 95 |   
 96 |   return (
 97 |     typeof params.vendor_id === 'number' &&
 98 |     Array.isArray(params.domains) &&
 99 |     params.domains.every(domain => isDomainWithMailboxes(domain))
100 |   );
101 | }
102 | 
103 | export function isPlaceOrderParams(args: unknown): args is PlaceOrderParams {
104 |   if (typeof args !== 'object' || args === null) return false;
105 |   
106 |   const params = args as Partial<PlaceOrderParams>;
107 |   
108 |   // Check if domains have mailbox property in mailbox_details
109 |   const domainsHaveMailboxes = Array.isArray(params.domains) && 
110 |     params.domains.every(domain => 
111 |       isDomainWithMailboxes(domain) && 
112 |       domain.mailbox_details.every(detail => typeof detail.mailbox === 'string')
113 |     );
114 |   
115 |   return (
116 |     typeof params.vendor_id === 'number' &&
117 |     typeof params.forwarding_domain === 'string' &&
118 |     domainsHaveMailboxes
119 |   );
120 | }
121 | 
122 | export function isGetDomainListParams(args: unknown): args is GetDomainListParams {
123 |   // Since this endpoint doesn't require specific parameters beyond the API key
124 |   // Any object is valid
125 |   return typeof args === 'object' && args !== null;
126 | } 
```

--------------------------------------------------------------------------------
/src/tools/webhooks.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { CategoryTool, ToolCategory } from '../types/common.js';
  2 | import { WebhookEventType } from '../types/webhooks.js';
  3 | 
  4 | // Webhook Tools
  5 | 
  6 | export const FETCH_WEBHOOKS_BY_CAMPAIGN_TOOL: CategoryTool = {
  7 |   name: 'smartlead_fetch_webhooks_by_campaign',
  8 |   description: 'Fetch all the webhooks associated with a campaign using the campaign ID.',
  9 |   category: ToolCategory.WEBHOOKS,
 10 |   inputSchema: {
 11 |     type: 'object',
 12 |     properties: {
 13 |       campaign_id: {
 14 |         type: 'string',
 15 |         description: 'ID of the campaign to fetch webhooks for',
 16 |       },
 17 |     },
 18 |     required: ['campaign_id'],
 19 |   },
 20 | };
 21 | 
 22 | export const UPSERT_CAMPAIGN_WEBHOOK_TOOL: CategoryTool = {
 23 |   name: 'smartlead_upsert_campaign_webhook',
 24 |   description: 'Add or update a webhook for a specific campaign.',
 25 |   category: ToolCategory.WEBHOOKS,
 26 |   inputSchema: {
 27 |     type: 'object',
 28 |     properties: {
 29 |       campaign_id: {
 30 |         type: 'string',
 31 |         description: 'ID of the campaign to add/update webhook for',
 32 |       },
 33 |       id: {
 34 |         type: ['integer', 'null'],
 35 |         description: 'ID of the webhook to update. Set to null to create a new webhook.',
 36 |       },
 37 |       name: {
 38 |         type: 'string',
 39 |         description: 'Name for the webhook',
 40 |       },
 41 |       webhook_url: {
 42 |         type: 'string',
 43 |         description: 'URL to call when the webhook event occurs',
 44 |       },
 45 |       event_types: {
 46 |         type: 'array',
 47 |         items: {
 48 |           type: 'string',
 49 |           enum: Object.values(WebhookEventType),
 50 |         },
 51 |         description: `Types of events to trigger the webhook. Options: ${Object.values(WebhookEventType).join(', ')}`,
 52 |       },
 53 |       categories: {
 54 |         type: 'array',
 55 |         items: { type: 'string' },
 56 |         description: 'Categories for filtering webhook events (e.g. ["Interested", "NotInterested"])',
 57 |       },
 58 |     },
 59 |     required: ['campaign_id', 'name', 'webhook_url', 'event_types'],
 60 |   },
 61 | };
 62 | 
 63 | export const DELETE_CAMPAIGN_WEBHOOK_TOOL: CategoryTool = {
 64 |   name: 'smartlead_delete_campaign_webhook',
 65 |   description: 'Delete a specific webhook from a campaign.',
 66 |   category: ToolCategory.WEBHOOKS,
 67 |   inputSchema: {
 68 |     type: 'object',
 69 |     properties: {
 70 |       campaign_id: {
 71 |         type: 'string',
 72 |         description: 'ID of the campaign containing the webhook',
 73 |       },
 74 |       id: {
 75 |         type: 'integer',
 76 |         description: 'ID of the webhook to delete',
 77 |       },
 78 |     },
 79 |     required: ['campaign_id', 'id'],
 80 |   },
 81 | };
 82 | 
 83 | export const GET_WEBHOOKS_PUBLISH_SUMMARY_TOOL: CategoryTool = {
 84 |   name: 'smartlead_get_webhooks_publish_summary',
 85 |   description: 'Get a summary of webhook publish events (Private Beta feature).',
 86 |   category: ToolCategory.WEBHOOKS,
 87 |   inputSchema: {
 88 |     type: 'object',
 89 |     properties: {
 90 |       campaign_id: {
 91 |         type: 'string',
 92 |         description: 'ID of the campaign to get webhook publish summary for',
 93 |       },
 94 |       fromTime: {
 95 |         type: 'string',
 96 |         description: 'Start date/time in ISO 8601 format (e.g. 2025-03-21T00:00:00Z)',
 97 |       },
 98 |       toTime: {
 99 |         type: 'string',
100 |         description: 'End date/time in ISO 8601 format (e.g. 2025-04-04T23:59:59Z)',
101 |       },
102 |     },
103 |     required: ['campaign_id'],
104 |   },
105 | };
106 | 
107 | export const RETRIGGER_FAILED_EVENTS_TOOL: CategoryTool = {
108 |   name: 'smartlead_retrigger_failed_events',
109 |   description: 'Retrigger failed webhook events (Private Beta feature).',
110 |   category: ToolCategory.WEBHOOKS,
111 |   inputSchema: {
112 |     type: 'object',
113 |     properties: {
114 |       campaign_id: {
115 |         type: 'string',
116 |         description: 'ID of the campaign to retrigger failed webhook events for',
117 |       },
118 |       fromTime: {
119 |         type: 'string',
120 |         description: 'Start date/time in ISO 8601 format (e.g. 2025-03-21T00:00:00Z)',
121 |       },
122 |       toTime: {
123 |         type: 'string',
124 |         description: 'End date/time in ISO 8601 format (e.g. 2025-04-04T23:59:59Z)',
125 |       },
126 |     },
127 |     required: ['campaign_id', 'fromTime', 'toTime'],
128 |   },
129 | };
130 | 
131 | // Export all tools as an array for easy registration
132 | export const webhookTools = [
133 |   FETCH_WEBHOOKS_BY_CAMPAIGN_TOOL,
134 |   UPSERT_CAMPAIGN_WEBHOOK_TOOL,
135 |   DELETE_CAMPAIGN_WEBHOOK_TOOL,
136 |   GET_WEBHOOKS_PUBLISH_SUMMARY_TOOL,
137 |   RETRIGGER_FAILED_EVENTS_TOOL,
138 | ]; 
```

--------------------------------------------------------------------------------
/src/utils/download-tracker.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import fs from 'fs';
  2 | import path from 'path';
  3 | import os from 'os';
  4 | import { v4 as uuidv4 } from 'uuid';
  5 | 
  6 | // Interface for download tracking data
  7 | export interface DownloadRecord {
  8 |   id: string;
  9 |   timestamp: string;
 10 |   campaignId: number;
 11 |   downloadType: string;
 12 |   format: string;
 13 |   userId?: string;
 14 |   machineId: string;
 15 |   ipAddress?: string;
 16 | }
 17 | 
 18 | // Path to store download records
 19 | const DOWNLOAD_LOG_PATH = process.env.DOWNLOAD_LOG_PATH || path.join(os.homedir(), '.smartlead-mcp', 'downloads.json');
 20 | 
 21 | // Ensure directory exists
 22 | const ensureDirectoryExists = (filePath: string) => {
 23 |   const dirname = path.dirname(filePath);
 24 |   if (!fs.existsSync(dirname)) {
 25 |     fs.mkdirSync(dirname, { recursive: true });
 26 |   }
 27 | };
 28 | 
 29 | // Initialize the download log file if it doesn't exist
 30 | const initializeLogFile = () => {
 31 |   ensureDirectoryExists(DOWNLOAD_LOG_PATH);
 32 |   if (!fs.existsSync(DOWNLOAD_LOG_PATH)) {
 33 |     fs.writeFileSync(DOWNLOAD_LOG_PATH, JSON.stringify({ downloads: [] }, null, 2));
 34 |     console.log(`Created download tracking file at: ${DOWNLOAD_LOG_PATH}`);
 35 |   }
 36 | };
 37 | 
 38 | // Get a unique machine identifier
 39 | const getMachineId = (): string => {
 40 |   try {
 41 |     const os = process.platform;
 42 |     const cpus = process.env.NUMBER_OF_PROCESSORS || '';
 43 |     const username = process.env.USER || process.env.USERNAME || '';
 44 |     const hostname = process.env.HOSTNAME || '';
 45 |     
 46 |     // Create a simple hash of these values
 47 |     const combinedString = `${os}-${cpus}-${username}-${hostname}`;
 48 |     let hash = 0;
 49 |     for (let i = 0; i < combinedString.length; i++) {
 50 |       hash = ((hash << 5) - hash) + combinedString.charCodeAt(i);
 51 |       hash |= 0; // Convert to 32bit integer
 52 |     }
 53 |     
 54 |     return Math.abs(hash).toString(16);
 55 |   } catch (e) {
 56 |     // Fallback to a random ID if we can't get system info
 57 |     return Math.random().toString(36).substring(2, 15);
 58 |   }
 59 | };
 60 | 
 61 | /**
 62 |  * Track a download event
 63 |  * @param campaignId The ID of the campaign being downloaded
 64 |  * @param downloadType The type of download (analytics, leads, etc.)
 65 |  * @param format The format of the download (json, csv)
 66 |  * @param userId Optional user identifier
 67 |  * @param ipAddress Optional IP address of the requester
 68 |  * @returns The unique ID of the download record
 69 |  */
 70 | export const trackDownload = (
 71 |   campaignId: number,
 72 |   downloadType: string,
 73 |   format: string,
 74 |   userId?: string,
 75 |   ipAddress?: string
 76 | ): string => {
 77 |   try {
 78 |     // Initialize log file if it doesn't exist
 79 |     initializeLogFile();
 80 |     
 81 |     // Read existing records
 82 |     const data = JSON.parse(fs.readFileSync(DOWNLOAD_LOG_PATH, 'utf8'));
 83 |     
 84 |     // Create new download record
 85 |     const downloadId = uuidv4();
 86 |     const downloadRecord: DownloadRecord = {
 87 |       id: downloadId,
 88 |       timestamp: new Date().toISOString(),
 89 |       campaignId,
 90 |       downloadType,
 91 |       format,
 92 |       userId,
 93 |       machineId: getMachineId(),
 94 |       ipAddress
 95 |     };
 96 |     
 97 |     // Add to records and save
 98 |     data.downloads.push(downloadRecord);
 99 |     fs.writeFileSync(DOWNLOAD_LOG_PATH, JSON.stringify(data, null, 2));
100 |     
101 |     console.log(`Tracked download: ${downloadId} for campaign ${campaignId}`);
102 |     return downloadId;
103 |   } catch (error) {
104 |     console.error('Failed to track download:', error);
105 |     return '';
106 |   }
107 | };
108 | 
109 | /**
110 |  * Get all download records
111 |  * @returns Array of download records
112 |  */
113 | export const getDownloadRecords = (): DownloadRecord[] => {
114 |   try {
115 |     initializeLogFile();
116 |     const data = JSON.parse(fs.readFileSync(DOWNLOAD_LOG_PATH, 'utf8'));
117 |     return data.downloads || [];
118 |   } catch (error) {
119 |     console.error('Failed to get download records:', error);
120 |     return [];
121 |   }
122 | };
123 | 
124 | /**
125 |  * Get download statistics
126 |  * @returns Statistics about downloads
127 |  */
128 | export const getDownloadStats = () => {
129 |   const records = getDownloadRecords();
130 |   
131 |   // Count downloads by type
132 |   const byType: Record<string, number> = {};
133 |   
134 |   // Count downloads by format
135 |   const byFormat: Record<string, number> = {};
136 |   
137 |   // Count downloads by campaign
138 |   const byCampaign: Record<number, number> = {};
139 |   
140 |   // Count unique users
141 |   const uniqueUsers = new Set<string>();
142 |   
143 |   // Count by date (YYYY-MM-DD)
144 |   const byDate: Record<string, number> = {};
145 |   
146 |   records.forEach(record => {
147 |     // Count by type
148 |     byType[record.downloadType] = (byType[record.downloadType] || 0) + 1;
149 |     
150 |     // Count by format
151 |     byFormat[record.format] = (byFormat[record.format] || 0) + 1;
152 |     
153 |     // Count by campaign
154 |     byCampaign[record.campaignId] = (byCampaign[record.campaignId] || 0) + 1;
155 |     
156 |     // Track unique users (either by userId or machineId)
157 |     if (record.userId) {
158 |       uniqueUsers.add(record.userId);
159 |     } else {
160 |       uniqueUsers.add(record.machineId);
161 |     }
162 |     
163 |     // Count by date
164 |     const date = record.timestamp.split('T')[0];
165 |     byDate[date] = (byDate[date] || 0) + 1;
166 |   });
167 |   
168 |   return {
169 |     totalDownloads: records.length,
170 |     uniqueUsers: uniqueUsers.size,
171 |     byType,
172 |     byFormat,
173 |     byCampaign,
174 |     byDate
175 |   };
176 | }; 
```

--------------------------------------------------------------------------------
/src/licensing/stripe-integration.js:
--------------------------------------------------------------------------------

```javascript
  1 | import Stripe from 'stripe';
  2 | import axios from 'axios';
  3 | import { LicenseLevel } from './index.js';
  4 | 
  5 | // Initialize Stripe with your secret key
  6 | const stripe = new Stripe(process.env.STRIPE_SECRET_KEY || '');
  7 | 
  8 | // Your license server URL
  9 | const LICENSE_SERVER_URL = process.env.LICENSE_SERVER_URL || 'https://api.yourservice.com/licensing';
 10 | 
 11 | /**
 12 |  * Check subscription status with Stripe
 13 |  * @param {string} customerId The Stripe customer ID
 14 |  * @returns {Promise<Object>} Subscription information
 15 |  */
 16 | export async function getSubscriptionStatus(customerId) {
 17 |   try {
 18 |     // Get all active subscriptions for this customer
 19 |     const subscriptions = await stripe.subscriptions.list({
 20 |       customer: customerId,
 21 |       status: 'active',
 22 |       expand: ['data.plan.product']
 23 |     });
 24 |     
 25 |     if (subscriptions.data.length === 0) {
 26 |       return {
 27 |         active: false,
 28 |         level: LicenseLevel.FREE,
 29 |         message: 'No active subscription found'
 30 |       };
 31 |     }
 32 |     
 33 |     // Get the highest tier subscription if there are multiple
 34 |     const subscription = subscriptions.data[0];
 35 |     const product = subscription.items.data[0].plan.product;
 36 |     
 37 |     // Determine license level based on product ID or metadata
 38 |     let level = LicenseLevel.FREE;
 39 |     if (product.metadata.license_level) {
 40 |       level = product.metadata.license_level;
 41 |     } else {
 42 |       // Map product IDs to license levels if metadata not available
 43 |       const productMapping = {
 44 |         'prod_basic123': LicenseLevel.BASIC,
 45 |         'prod_premium456': LicenseLevel.PREMIUM
 46 |       };
 47 |       level = productMapping[product.id] || LicenseLevel.FREE;
 48 |     }
 49 |     
 50 |     return {
 51 |       active: true,
 52 |       level,
 53 |       subscriptionId: subscription.id,
 54 |       currentPeriodEnd: new Date(subscription.current_period_end * 1000),
 55 |       cancelAtPeriodEnd: subscription.cancel_at_period_end,
 56 |       message: 'Subscription active'
 57 |     };
 58 |   } catch (error) {
 59 |     console.error('Error checking subscription status:', error);
 60 |     return {
 61 |       active: false,
 62 |       level: LicenseLevel.FREE,
 63 |       message: 'Error checking subscription status'
 64 |     };
 65 |   }
 66 | }
 67 | 
 68 | /**
 69 |  * Generate a new license key for a customer
 70 |  * @param {string} customerId The Stripe customer ID
 71 |  * @param {string} level The license level
 72 |  * @returns {Promise<Object>} The generated license information
 73 |  */
 74 | export async function generateLicense(customerId, level) {
 75 |   try {
 76 |     // Call your license server to generate a new license
 77 |     const response = await axios.post(`${LICENSE_SERVER_URL}/generate`, {
 78 |       customerId,
 79 |       level
 80 |     }, {
 81 |       headers: {
 82 |         'Content-Type': 'application/json',
 83 |         'X-API-Key': process.env.LICENSE_API_KEY
 84 |       }
 85 |     });
 86 |     
 87 |     return response.data;
 88 |   } catch (error) {
 89 |     console.error('Error generating license:', error);
 90 |     throw new Error('Failed to generate license');
 91 |   }
 92 | }
 93 | 
 94 | /**
 95 |  * Handle Stripe webhook events
 96 |  * @param {Object} event The Stripe webhook event
 97 |  * @returns {Promise<Object>} Result of webhook handling
 98 |  */
 99 | export async function handleStripeWebhook(event) {
100 |   try {
101 |     switch (event.type) {
102 |       case 'customer.subscription.created':
103 |       case 'customer.subscription.updated': {
104 |         const subscription = event.data.object;
105 |         const customerId = subscription.customer;
106 |         
107 |         // Get product information to determine license level
108 |         const product = await stripe.products.retrieve(
109 |           subscription.items.data[0].plan.product
110 |         );
111 |         
112 |         const level = product.metadata.license_level || LicenseLevel.BASIC;
113 |         
114 |         // Generate or update license
115 |         const licenseInfo = await generateLicense(customerId, level);
116 |         
117 |         // Update customer metadata with license key
118 |         await stripe.customers.update(customerId, {
119 |           metadata: { 
120 |             license_key: licenseInfo.key,
121 |             license_level: level
122 |           }
123 |         });
124 |         
125 |         return { success: true, message: 'License updated', licenseInfo };
126 |       }
127 |       
128 |       case 'customer.subscription.deleted': {
129 |         const subscription = event.data.object;
130 |         const customerId = subscription.customer;
131 |         
132 |         // Downgrade to free tier or deactivate license
133 |         const response = await axios.post(`${LICENSE_SERVER_URL}/downgrade`, {
134 |           customerId
135 |         }, {
136 |           headers: {
137 |             'Content-Type': 'application/json',
138 |             'X-API-Key': process.env.LICENSE_API_KEY
139 |           }
140 |         });
141 |         
142 |         // Update customer metadata
143 |         await stripe.customers.update(customerId, {
144 |           metadata: { 
145 |             license_level: LicenseLevel.FREE 
146 |           }
147 |         });
148 |         
149 |         return { success: true, message: 'License downgraded', response: response.data };
150 |       }
151 |       
152 |       default:
153 |         return { success: true, message: 'Event ignored' };
154 |     }
155 |   } catch (error) {
156 |     console.error('Error handling webhook:', error);
157 |     return { success: false, message: error.message };
158 |   }
159 | } 
```

--------------------------------------------------------------------------------
/src/tools/smartSenders.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { CategoryTool, ToolCategory } from '../types/common.js';
  2 | 
  3 | // Smart Senders Tools
  4 | 
  5 | export const GET_VENDORS_TOOL: CategoryTool = {
  6 |   name: 'smartlead_get_vendors',
  7 |   description: 'Retrieve all active domain vendors with their corresponding IDs.',
  8 |   category: ToolCategory.SMART_SENDERS,
  9 |   inputSchema: {
 10 |     type: 'object',
 11 |     properties: {
 12 |       // This endpoint doesn't require specific parameters beyond the API key
 13 |       // which is handled at the API client level
 14 |     },
 15 |     required: [],
 16 |   },
 17 | };
 18 | 
 19 | export const SEARCH_DOMAIN_TOOL: CategoryTool = {
 20 |   name: 'smartlead_search_domain',
 21 |   description: 'Search for available domains under $15 that match a given domain name pattern.',
 22 |   category: ToolCategory.SMART_SENDERS,
 23 |   inputSchema: {
 24 |     type: 'object',
 25 |     properties: {
 26 |       domain_name: {
 27 |         type: 'string',
 28 |         description: 'The domain name pattern you want to search for',
 29 |       },
 30 |       vendor_id: {
 31 |         type: 'integer',
 32 |         description: 'ID of the vendor from whom you want to purchase the domain (use Get Vendors API to retrieve this ID)',
 33 |       },
 34 |     },
 35 |     required: ['domain_name', 'vendor_id'],
 36 |   },
 37 | };
 38 | 
 39 | export const AUTO_GENERATE_MAILBOXES_TOOL: CategoryTool = {
 40 |   name: 'smartlead_auto_generate_mailboxes',
 41 |   description: 'Auto-generate mailboxes based on the domain name and personal details provided.',
 42 |   category: ToolCategory.SMART_SENDERS,
 43 |   inputSchema: {
 44 |     type: 'object',
 45 |     properties: {
 46 |       vendor_id: {
 47 |         type: 'integer',
 48 |         description: 'ID of the vendor from whom you want to purchase the domains and mailboxes',
 49 |       },
 50 |       domains: {
 51 |         type: 'array',
 52 |         items: {
 53 |           type: 'object',
 54 |           properties: {
 55 |             domain_name: {
 56 |               type: 'string',
 57 |               description: 'The domain name for which you want to generate mailboxes (e.g., example.com)',
 58 |             },
 59 |             mailbox_details: {
 60 |               type: 'array',
 61 |               items: {
 62 |                 type: 'object',
 63 |                 properties: {
 64 |                   first_name: {
 65 |                     type: 'string',
 66 |                     description: 'First name for the mailbox owner (should be more than 2 characters and without spaces)',
 67 |                   },
 68 |                   last_name: {
 69 |                     type: 'string',
 70 |                     description: 'Last name for the mailbox owner (should be more than 2 characters and without spaces)',
 71 |                   },
 72 |                   profile_pic: {
 73 |                     type: 'string',
 74 |                     description: 'URL or identifier for profile picture (optional)',
 75 |                   },
 76 |                 },
 77 |                 required: ['first_name', 'last_name'],
 78 |               },
 79 |               description: 'Details for each mailbox you want to generate',
 80 |             },
 81 |           },
 82 |           required: ['domain_name', 'mailbox_details'],
 83 |         },
 84 |         description: 'List of domains and associated mailbox details',
 85 |       },
 86 |     },
 87 |     required: ['vendor_id', 'domains'],
 88 |   },
 89 | };
 90 | 
 91 | export const PLACE_ORDER_MAILBOXES_TOOL: CategoryTool = {
 92 |   name: 'smartlead_place_order_mailboxes',
 93 |   description: 'Confirm and place order for domains and mailboxes to be purchased.',
 94 |   category: ToolCategory.SMART_SENDERS,
 95 |   inputSchema: {
 96 |     type: 'object',
 97 |     properties: {
 98 |       vendor_id: {
 99 |         type: 'integer',
100 |         description: 'ID of the vendor from whom you want to purchase the domains and mailboxes',
101 |       },
102 |       forwarding_domain: {
103 |         type: 'string',
104 |         description: 'The domain to forward to when users access purchased domains',
105 |       },
106 |       domains: {
107 |         type: 'array',
108 |         items: {
109 |           type: 'object',
110 |           properties: {
111 |             domain_name: {
112 |               type: 'string',
113 |               description: 'The domain name you want to purchase',
114 |             },
115 |             mailbox_details: {
116 |               type: 'array',
117 |               items: {
118 |                 type: 'object',
119 |                 properties: {
120 |                   mailbox: {
121 |                     type: 'string',
122 |                     description: 'The complete mailbox address (e.g., [email protected])',
123 |                   },
124 |                   first_name: {
125 |                     type: 'string',
126 |                     description: 'First name for the mailbox owner',
127 |                   },
128 |                   last_name: {
129 |                     type: 'string',
130 |                     description: 'Last name for the mailbox owner',
131 |                   },
132 |                   profile_pic: {
133 |                     type: 'string',
134 |                     description: 'URL or identifier for profile picture (optional)',
135 |                   },
136 |                 },
137 |                 required: ['mailbox', 'first_name', 'last_name'],
138 |               },
139 |               description: 'Details for each mailbox you want to purchase',
140 |             },
141 |           },
142 |           required: ['domain_name', 'mailbox_details'],
143 |         },
144 |         description: 'List of domains and associated mailbox details for purchase',
145 |       },
146 |     },
147 |     required: ['vendor_id', 'forwarding_domain', 'domains'],
148 |   },
149 | };
150 | 
151 | export const GET_DOMAIN_LIST_TOOL: CategoryTool = {
152 |   name: 'smartlead_get_domain_list',
153 |   description: 'Retrieve a list of all domains purchased through SmartSenders.',
154 |   category: ToolCategory.SMART_SENDERS,
155 |   inputSchema: {
156 |     type: 'object',
157 |     properties: {
158 |       // This endpoint doesn't require specific parameters beyond the API key
159 |       // which is handled at the API client level
160 |     },
161 |     required: [],
162 |   },
163 | };
164 | 
165 | // Export all tools as an array for easy registration
166 | export const smartSendersTools = [
167 |   GET_VENDORS_TOOL,
168 |   SEARCH_DOMAIN_TOOL,
169 |   AUTO_GENERATE_MAILBOXES_TOOL,
170 |   PLACE_ORDER_MAILBOXES_TOOL,
171 |   GET_DOMAIN_LIST_TOOL,
172 | ]; 
```

--------------------------------------------------------------------------------
/src/tools/smartDelivery.d.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { z } from 'zod';
  2 | 
  3 | // Tool schemas for Smart Delivery category
  4 | export const regionWiseProviderIdsSchema: {
  5 |   name: string;
  6 |   description: string;
  7 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
  8 | };
  9 | 
 10 | export const createManualPlacementTestSchema: {
 11 |   name: string;
 12 |   description: string;
 13 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 14 | };
 15 | 
 16 | export const createAutomatedPlacementTestSchema: {
 17 |   name: string;
 18 |   description: string;
 19 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 20 | };
 21 | 
 22 | export const getSpamTestDetailsSchema: {
 23 |   name: string;
 24 |   description: string;
 25 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 26 | };
 27 | 
 28 | export const deleteSmartDeliveryTestsInBulkSchema: {
 29 |   name: string;
 30 |   description: string;
 31 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 32 | };
 33 | 
 34 | export const stopAutomatedSmartDeliveryTestSchema: {
 35 |   name: string;
 36 |   description: string;
 37 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 38 | };
 39 | 
 40 | export const listAllTestsSchema: {
 41 |   name: string;
 42 |   description: string;
 43 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 44 | };
 45 | 
 46 | export const providerWiseReportSchema: {
 47 |   name: string;
 48 |   description: string;
 49 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 50 | };
 51 | 
 52 | export const geoWiseReportSchema: {
 53 |   name: string;
 54 |   description: string;
 55 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 56 | };
 57 | 
 58 | export const senderAccountWiseReportSchema: {
 59 |   name: string;
 60 |   description: string;
 61 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 62 | };
 63 | 
 64 | export const spamFilterReportSchema: {
 65 |   name: string;
 66 |   description: string;
 67 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 68 | };
 69 | 
 70 | export const dkimDetailsSchema: {
 71 |   name: string;
 72 |   description: string;
 73 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 74 | };
 75 | 
 76 | export const spfDetailsSchema: {
 77 |   name: string;
 78 |   description: string;
 79 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 80 | };
 81 | 
 82 | export const rdnsReportSchema: {
 83 |   name: string;
 84 |   description: string;
 85 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 86 | };
 87 | 
 88 | export const senderAccountListSchema: {
 89 |   name: string;
 90 |   description: string;
 91 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 92 | };
 93 | 
 94 | export const blacklistsSchema: {
 95 |   name: string;
 96 |   description: string;
 97 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
 98 | };
 99 | 
100 | export const spamTestEmailContentSchema: {
101 |   name: string;
102 |   description: string;
103 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
104 | };
105 | 
106 | export const spamTestIpBlacklistCountSchema: {
107 |   name: string;
108 |   description: string;
109 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
110 | };
111 | 
112 | export const emailReplyHeadersSchema: {
113 |   name: string;
114 |   description: string;
115 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
116 | };
117 | 
118 | export const scheduleHistoryForAutomatedTestsSchema: {
119 |   name: string;
120 |   description: string;
121 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
122 | };
123 | 
124 | export const ipDetailsSchema: {
125 |   name: string;
126 |   description: string;
127 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
128 | };
129 | 
130 | export const mailboxSummarySchema: {
131 |   name: string;
132 |   description: string;
133 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
134 | };
135 | 
136 | export const mailboxCountApiSchema: {
137 |   name: string;
138 |   description: string;
139 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
140 | };
141 | 
142 | export const getAllFoldersSchema: {
143 |   name: string;
144 |   description: string;
145 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
146 | };
147 | 
148 | export const createFoldersSchema: {
149 |   name: string;
150 |   description: string;
151 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
152 | };
153 | 
154 | export const getFolderByIdSchema: {
155 |   name: string;
156 |   description: string;
157 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
158 | };
159 | 
160 | export const deleteFolderSchema: {
161 |   name: string;
162 |   description: string;
163 |   schema: z.ZodOptional<z.ZodObject<{}, "strip", z.ZodTypeAny, {}, {}>>;
164 | };
165 | 
166 | // Type declarations for Smart Delivery tools
167 | declare module './tools/smartDelivery.js' {
168 |   import { CategoryTool } from '../types/common.js';
169 |   
170 |   export const REGION_WISE_PROVIDER_IDS_TOOL: string;
171 |   export const CREATE_MANUAL_PLACEMENT_TEST_TOOL: string;
172 |   export const CREATE_AUTOMATED_PLACEMENT_TEST_TOOL: string;
173 |   export const GET_SPAM_TEST_DETAILS_TOOL: string;
174 |   export const DELETE_SMART_DELIVERY_TESTS_IN_BULK_TOOL: string;
175 |   export const STOP_AUTOMATED_SMART_DELIVERY_TEST_TOOL: string;
176 |   export const LIST_ALL_TESTS_TOOL: string;
177 |   export const PROVIDER_WISE_REPORT_TOOL: string;
178 |   export const GEO_WISE_REPORT_TOOL: string;
179 |   export const SENDER_ACCOUNT_WISE_REPORT_TOOL: string;
180 |   export const SPAM_FILTER_REPORT_TOOL: string;
181 |   export const DKIM_DETAILS_TOOL: string;
182 |   export const SPF_DETAILS_TOOL: string;
183 |   export const RDNS_REPORT_TOOL: string;
184 |   export const SENDER_ACCOUNT_LIST_TOOL: string;
185 |   export const BLACKLISTS_TOOL: string;
186 |   export const SPAM_TEST_EMAIL_CONTENT_TOOL: string;
187 |   export const SPAM_TEST_IP_BLACKLIST_COUNT_TOOL: string;
188 |   export const EMAIL_REPLY_HEADERS_TOOL: string;
189 |   export const SCHEDULE_HISTORY_FOR_AUTOMATED_TESTS_TOOL: string;
190 |   export const IP_DETAILS_TOOL: string;
191 |   export const MAILBOX_SUMMARY_TOOL: string;
192 |   export const MAILBOX_COUNT_API_TOOL: string;
193 |   export const GET_ALL_FOLDERS_TOOL: string;
194 |   export const CREATE_FOLDERS_TOOL: string;
195 |   export const GET_FOLDER_BY_ID_TOOL: string;
196 |   export const DELETE_FOLDER_TOOL: string;
197 |   
198 |   export const smartDeliveryTools: CategoryTool[];
199 | } 
```

--------------------------------------------------------------------------------
/src/tools/lead.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { CategoryTool, ToolCategory } from '../types/common.js';
  2 | 
  3 | // Lead Management Tools
  4 | export const LIST_LEADS_TOOL: CategoryTool = {
  5 |   name: 'smartlead_list_leads',
  6 |   description: 'List leads with optional filtering by campaign or status.',
  7 |   category: ToolCategory.LEAD_MANAGEMENT,
  8 |   inputSchema: {
  9 |     type: 'object',
 10 |     properties: {
 11 |       campaign_id: {
 12 |         type: 'number',
 13 |         description: 'Filter leads by campaign ID',
 14 |       },
 15 |       status: {
 16 |         type: 'string',
 17 |         description: 'Filter leads by status (e.g., "active", "unsubscribed", "bounced")',
 18 |       },
 19 |       limit: {
 20 |         type: 'number',
 21 |         description: 'Maximum number of leads to return',
 22 |       },
 23 |       offset: {
 24 |         type: 'number',
 25 |         description: 'Offset for pagination',
 26 |       },
 27 |       search: {
 28 |         type: 'string',
 29 |         description: 'Search term to filter leads',
 30 |       },
 31 |       start_date: {
 32 |         type: 'string',
 33 |         description: 'Filter leads created after this date (YYYY-MM-DD format)',
 34 |       },
 35 |       end_date: {
 36 |         type: 'string',
 37 |         description: 'Filter leads created before this date (YYYY-MM-DD format)',
 38 |       },
 39 |     },
 40 |   },
 41 | };
 42 | 
 43 | export const GET_LEAD_TOOL: CategoryTool = {
 44 |   name: 'smartlead_get_lead',
 45 |   description: 'Get details of a specific lead by ID.',
 46 |   category: ToolCategory.LEAD_MANAGEMENT,
 47 |   inputSchema: {
 48 |     type: 'object',
 49 |     properties: {
 50 |       lead_id: {
 51 |         type: 'number',
 52 |         description: 'ID of the lead to retrieve',
 53 |       },
 54 |     },
 55 |     required: ['lead_id'],
 56 |   },
 57 | };
 58 | 
 59 | export const ADD_LEAD_TO_CAMPAIGN_TOOL: CategoryTool = {
 60 |   name: 'smartlead_add_lead_to_campaign',
 61 |   description: 'Add a new lead to a campaign.',
 62 |   category: ToolCategory.LEAD_MANAGEMENT,
 63 |   inputSchema: {
 64 |     type: 'object',
 65 |     properties: {
 66 |       campaign_id: {
 67 |         type: 'number',
 68 |         description: 'ID of the campaign to add the lead to',
 69 |       },
 70 |       email: {
 71 |         type: 'string',
 72 |         description: 'Email address of the lead',
 73 |       },
 74 |       first_name: {
 75 |         type: 'string',
 76 |         description: 'First name of the lead',
 77 |       },
 78 |       last_name: {
 79 |         type: 'string',
 80 |         description: 'Last name of the lead',
 81 |       },
 82 |       company: {
 83 |         type: 'string',
 84 |         description: 'Company of the lead',
 85 |       },
 86 |       title: {
 87 |         type: 'string',
 88 |         description: 'Job title of the lead',
 89 |       },
 90 |       phone: {
 91 |         type: 'string',
 92 |         description: 'Phone number of the lead',
 93 |       },
 94 |       custom_fields: {
 95 |         type: 'object',
 96 |         description: 'Custom fields for the lead',
 97 |       },
 98 |     },
 99 |     required: ['campaign_id', 'email'],
100 |   },
101 | };
102 | 
103 | export const UPDATE_LEAD_TOOL: CategoryTool = {
104 |   name: 'smartlead_update_lead',
105 |   description: 'Update an existing lead\'s information.',
106 |   category: ToolCategory.LEAD_MANAGEMENT,
107 |   inputSchema: {
108 |     type: 'object',
109 |     properties: {
110 |       lead_id: {
111 |         type: 'number',
112 |         description: 'ID of the lead to update',
113 |       },
114 |       email: {
115 |         type: 'string',
116 |         description: 'New email address for the lead',
117 |       },
118 |       first_name: {
119 |         type: 'string',
120 |         description: 'New first name for the lead',
121 |       },
122 |       last_name: {
123 |         type: 'string',
124 |         description: 'New last name for the lead',
125 |       },
126 |       company: {
127 |         type: 'string',
128 |         description: 'New company for the lead',
129 |       },
130 |       title: {
131 |         type: 'string',
132 |         description: 'New job title for the lead',
133 |       },
134 |       phone: {
135 |         type: 'string',
136 |         description: 'New phone number for the lead',
137 |       },
138 |       custom_fields: {
139 |         type: 'object',
140 |         description: 'Updated custom fields for the lead',
141 |       },
142 |     },
143 |     required: ['lead_id'],
144 |   },
145 | };
146 | 
147 | export const UPDATE_LEAD_STATUS_TOOL: CategoryTool = {
148 |   name: 'smartlead_update_lead_status',
149 |   description: 'Update a lead\'s status.',
150 |   category: ToolCategory.LEAD_MANAGEMENT,
151 |   inputSchema: {
152 |     type: 'object',
153 |     properties: {
154 |       lead_id: {
155 |         type: 'number',
156 |         description: 'ID of the lead to update',
157 |       },
158 |       status: {
159 |         type: 'string',
160 |         description: 'New status for the lead',
161 |       },
162 |     },
163 |     required: ['lead_id', 'status'],
164 |   },
165 | };
166 | 
167 | export const BULK_IMPORT_LEADS_TOOL: CategoryTool = {
168 |   name: 'smartlead_bulk_import_leads',
169 |   description: 'Import multiple leads into a campaign at once.',
170 |   category: ToolCategory.LEAD_MANAGEMENT,
171 |   inputSchema: {
172 |     type: 'object',
173 |     properties: {
174 |       campaign_id: {
175 |         type: 'number',
176 |         description: 'ID of the campaign to add the leads to',
177 |       },
178 |       leads: {
179 |         type: 'array',
180 |         items: {
181 |           type: 'object',
182 |           properties: {
183 |             email: {
184 |               type: 'string',
185 |               description: 'Email address of the lead',
186 |             },
187 |             first_name: {
188 |               type: 'string',
189 |               description: 'First name of the lead',
190 |             },
191 |             last_name: {
192 |               type: 'string',
193 |               description: 'Last name of the lead',
194 |             },
195 |             company: {
196 |               type: 'string',
197 |               description: 'Company of the lead',
198 |             },
199 |             title: {
200 |               type: 'string',
201 |               description: 'Job title of the lead',
202 |             },
203 |             phone: {
204 |               type: 'string',
205 |               description: 'Phone number of the lead',
206 |             },
207 |             custom_fields: {
208 |               type: 'object',
209 |               description: 'Custom fields for the lead',
210 |             },
211 |           },
212 |           required: ['email'],
213 |         },
214 |         description: 'Array of leads to import',
215 |       },
216 |     },
217 |     required: ['campaign_id', 'leads'],
218 |   },
219 | };
220 | 
221 | export const DELETE_LEAD_TOOL: CategoryTool = {
222 |   name: 'smartlead_delete_lead',
223 |   description: 'Delete a lead permanently.',
224 |   category: ToolCategory.LEAD_MANAGEMENT,
225 |   inputSchema: {
226 |     type: 'object',
227 |     properties: {
228 |       lead_id: {
229 |         type: 'number',
230 |         description: 'ID of the lead to delete',
231 |       },
232 |     },
233 |     required: ['lead_id'],
234 |   },
235 | };
236 | 
237 | // Export an array of all lead management tools for registration
238 | export const leadTools = [
239 |   LIST_LEADS_TOOL,
240 |   GET_LEAD_TOOL,
241 |   ADD_LEAD_TO_CAMPAIGN_TOOL,
242 |   UPDATE_LEAD_TOOL,
243 |   UPDATE_LEAD_STATUS_TOOL,
244 |   BULK_IMPORT_LEADS_TOOL,
245 |   DELETE_LEAD_TOOL,
246 | ]; 
```

--------------------------------------------------------------------------------
/src/handlers/smartSenders.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { AxiosInstance } from 'axios';
  2 | import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
  3 | import {
  4 |   isGetVendorsParams,
  5 |   isSearchDomainParams,
  6 |   isAutoGenerateMailboxesParams,
  7 |   isPlaceOrderParams,
  8 |   isGetDomainListParams
  9 | } from '../types/smartSenders.js';
 10 | 
 11 | // Smart Senders API base URL - different from the main SmartLead API
 12 | const SMART_SENDERS_API_URL = 'https://smart-senders.smartlead.ai/api/v1';
 13 | 
 14 | // Handler for Smart Senders-related tools
 15 | export async function handleSmartSendersTool(
 16 |   toolName: string,
 17 |   args: unknown,
 18 |   apiClient: AxiosInstance,
 19 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
 20 | ) {
 21 |   switch (toolName) {
 22 |     case 'smartlead_get_vendors': {
 23 |       return handleGetVendors(args, apiClient, withRetry);
 24 |     }
 25 |     case 'smartlead_search_domain': {
 26 |       return handleSearchDomain(args, apiClient, withRetry);
 27 |     }
 28 |     case 'smartlead_auto_generate_mailboxes': {
 29 |       return handleAutoGenerateMailboxes(args, apiClient, withRetry);
 30 |     }
 31 |     case 'smartlead_place_order_mailboxes': {
 32 |       return handlePlaceOrderMailboxes(args, apiClient, withRetry);
 33 |     }
 34 |     case 'smartlead_get_domain_list': {
 35 |       return handleGetDomainList(args, apiClient, withRetry);
 36 |     }
 37 |     default:
 38 |       throw new Error(`Unknown Smart Senders tool: ${toolName}`);
 39 |   }
 40 | }
 41 | 
 42 | // Create a modified client for Smart Senders API with the correct base URL
 43 | function createSmartSendersClient(apiClient: AxiosInstance) {
 44 |   return {
 45 |     get: (url: string, config?: any) => 
 46 |       apiClient.get(`${SMART_SENDERS_API_URL}${url}`, config),
 47 |     post: (url: string, data?: any, config?: any) => 
 48 |       apiClient.post(`${SMART_SENDERS_API_URL}${url}`, data, config),
 49 |     put: (url: string, data?: any, config?: any) => 
 50 |       apiClient.put(`${SMART_SENDERS_API_URL}${url}`, data, config),
 51 |     delete: (url: string, config?: any) => 
 52 |       apiClient.delete(`${SMART_SENDERS_API_URL}${url}`, config)
 53 |   };
 54 | }
 55 | 
 56 | // Individual handlers for each tool
 57 | async function handleGetVendors(
 58 |   args: unknown,
 59 |   apiClient: AxiosInstance,
 60 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
 61 | ) {
 62 |   if (!isGetVendorsParams(args)) {
 63 |     throw new McpError(
 64 |       ErrorCode.InvalidParams,
 65 |       'Invalid arguments for smartlead_get_vendors'
 66 |     );
 67 |   }
 68 | 
 69 |   try {
 70 |     const smartSendersClient = createSmartSendersClient(apiClient);
 71 |     
 72 |     const response = await withRetry(
 73 |       async () => smartSendersClient.get('/smart-senders/get-vendors'),
 74 |       'get vendors'
 75 |     );
 76 | 
 77 |     return {
 78 |       content: [
 79 |         {
 80 |           type: 'text',
 81 |           text: JSON.stringify(response.data, null, 2),
 82 |         },
 83 |       ],
 84 |       isError: false,
 85 |     };
 86 |   } catch (error: any) {
 87 |     return {
 88 |       content: [{ 
 89 |         type: 'text', 
 90 |         text: `API Error: ${error.response?.data?.message || error.message}` 
 91 |       }],
 92 |       isError: true,
 93 |     };
 94 |   }
 95 | }
 96 | 
 97 | async function handleSearchDomain(
 98 |   args: unknown,
 99 |   apiClient: AxiosInstance,
100 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
101 | ) {
102 |   if (!isSearchDomainParams(args)) {
103 |     throw new McpError(
104 |       ErrorCode.InvalidParams,
105 |       'Invalid arguments for smartlead_search_domain'
106 |     );
107 |   }
108 | 
109 |   try {
110 |     const smartSendersClient = createSmartSendersClient(apiClient);
111 |     const { domain_name, vendor_id } = args;
112 |     
113 |     const response = await withRetry(
114 |       async () => smartSendersClient.get(`/smart-senders/search-domain?domain_name=${domain_name}&vendor_id=${vendor_id}`),
115 |       'search domain'
116 |     );
117 | 
118 |     return {
119 |       content: [
120 |         {
121 |           type: 'text',
122 |           text: JSON.stringify(response.data, null, 2),
123 |         },
124 |       ],
125 |       isError: false,
126 |     };
127 |   } catch (error: any) {
128 |     return {
129 |       content: [{ 
130 |         type: 'text', 
131 |         text: `API Error: ${error.response?.data?.message || error.message}` 
132 |       }],
133 |       isError: true,
134 |     };
135 |   }
136 | }
137 | 
138 | async function handleAutoGenerateMailboxes(
139 |   args: unknown,
140 |   apiClient: AxiosInstance,
141 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
142 | ) {
143 |   if (!isAutoGenerateMailboxesParams(args)) {
144 |     throw new McpError(
145 |       ErrorCode.InvalidParams,
146 |       'Invalid arguments for smartlead_auto_generate_mailboxes'
147 |     );
148 |   }
149 | 
150 |   try {
151 |     const smartSendersClient = createSmartSendersClient(apiClient);
152 |     
153 |     const response = await withRetry(
154 |       async () => smartSendersClient.post('/smart-senders/auto-generate-mailboxes', args),
155 |       'auto-generate mailboxes'
156 |     );
157 | 
158 |     return {
159 |       content: [
160 |         {
161 |           type: 'text',
162 |           text: JSON.stringify(response.data, null, 2),
163 |         },
164 |       ],
165 |       isError: false,
166 |     };
167 |   } catch (error: any) {
168 |     return {
169 |       content: [{ 
170 |         type: 'text', 
171 |         text: `API Error: ${error.response?.data?.message || error.message}` 
172 |       }],
173 |       isError: true,
174 |     };
175 |   }
176 | }
177 | 
178 | async function handlePlaceOrderMailboxes(
179 |   args: unknown,
180 |   apiClient: AxiosInstance,
181 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
182 | ) {
183 |   if (!isPlaceOrderParams(args)) {
184 |     throw new McpError(
185 |       ErrorCode.InvalidParams,
186 |       'Invalid arguments for smartlead_place_order_mailboxes'
187 |     );
188 |   }
189 | 
190 |   try {
191 |     const smartSendersClient = createSmartSendersClient(apiClient);
192 |     
193 |     const response = await withRetry(
194 |       async () => smartSendersClient.post('/smart-senders/place-order', args),
195 |       'place order for mailboxes'
196 |     );
197 | 
198 |     return {
199 |       content: [
200 |         {
201 |           type: 'text',
202 |           text: JSON.stringify(response.data, null, 2),
203 |         },
204 |       ],
205 |       isError: false,
206 |     };
207 |   } catch (error: any) {
208 |     return {
209 |       content: [{ 
210 |         type: 'text', 
211 |         text: `API Error: ${error.response?.data?.message || error.message}` 
212 |       }],
213 |       isError: true,
214 |     };
215 |   }
216 | }
217 | 
218 | async function handleGetDomainList(
219 |   args: unknown,
220 |   apiClient: AxiosInstance,
221 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
222 | ) {
223 |   if (!isGetDomainListParams(args)) {
224 |     throw new McpError(
225 |       ErrorCode.InvalidParams,
226 |       'Invalid arguments for smartlead_get_domain_list'
227 |     );
228 |   }
229 | 
230 |   try {
231 |     const smartSendersClient = createSmartSendersClient(apiClient);
232 |     
233 |     const response = await withRetry(
234 |       async () => smartSendersClient.get('/smart-senders/get-domain-list'),
235 |       'get domain list'
236 |     );
237 | 
238 |     return {
239 |       content: [
240 |         {
241 |           type: 'text',
242 |           text: JSON.stringify(response.data, null, 2),
243 |         },
244 |       ],
245 |       isError: false,
246 |     };
247 |   } catch (error: any) {
248 |     return {
249 |       content: [{ 
250 |         type: 'text', 
251 |         text: `API Error: ${error.response?.data?.message || error.message}` 
252 |       }],
253 |       isError: true,
254 |     };
255 |   }
256 | } 
```

--------------------------------------------------------------------------------
/src/types/email.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { AxiosError } from 'axios';
  2 | 
  3 | // Type guards for Email Account parameters
  4 | export function isListEmailAccountsParams(args: unknown): args is ListEmailAccountsParams {
  5 |   if (!args || typeof args !== 'object') return false;
  6 |   return true;
  7 | }
  8 | 
  9 | export function isAddEmailToCampaignParams(args: unknown): args is AddEmailToCampaignParams {
 10 |   if (!args || typeof args !== 'object') return false;
 11 |   const { campaign_id, email_account_id } = args as Partial<AddEmailToCampaignParams>;
 12 |   return (
 13 |     typeof campaign_id === 'number' &&
 14 |     typeof email_account_id === 'number'
 15 |   );
 16 | }
 17 | 
 18 | export function isRemoveEmailFromCampaignParams(args: unknown): args is RemoveEmailFromCampaignParams {
 19 |   if (!args || typeof args !== 'object') return false;
 20 |   const { campaign_id, email_account_id } = args as Partial<RemoveEmailFromCampaignParams>;
 21 |   return (
 22 |     typeof campaign_id === 'number' &&
 23 |     typeof email_account_id === 'number'
 24 |   );
 25 | }
 26 | 
 27 | export function isFetchEmailAccountsParams(args: unknown): args is FetchEmailAccountsParams {
 28 |   if (!args || typeof args !== 'object') return false;
 29 |   return true;
 30 | }
 31 | 
 32 | export function isCreateEmailAccountParams(args: unknown): args is CreateEmailAccountParams {
 33 |   if (!args || typeof args !== 'object') return false;
 34 |   const { from_name, from_email, user_name, password, smtp_host, smtp_port, imap_host, imap_port } = args as Partial<CreateEmailAccountParams>;
 35 |   return (
 36 |     typeof from_name === 'string' &&
 37 |     typeof from_email === 'string' &&
 38 |     typeof user_name === 'string' &&
 39 |     typeof password === 'string' &&
 40 |     typeof smtp_host === 'string' &&
 41 |     typeof smtp_port === 'number' &&
 42 |     typeof imap_host === 'string' &&
 43 |     typeof imap_port === 'number'
 44 |   );
 45 | }
 46 | 
 47 | export function isUpdateEmailAccountParams(args: unknown): args is UpdateEmailAccountParams {
 48 |   if (!args || typeof args !== 'object') return false;
 49 |   const { email_account_id } = args as Partial<UpdateEmailAccountParams>;
 50 |   return typeof email_account_id === 'number';
 51 | }
 52 | 
 53 | export function isFetchEmailAccountByIdParams(args: unknown): args is FetchEmailAccountByIdParams {
 54 |   if (!args || typeof args !== 'object') return false;
 55 |   const { email_account_id } = args as Partial<FetchEmailAccountByIdParams>;
 56 |   return typeof email_account_id === 'number';
 57 | }
 58 | 
 59 | export function isUpdateEmailWarmupParams(args: unknown): args is UpdateEmailWarmupParams {
 60 |   if (!args || typeof args !== 'object') return false;
 61 |   const { email_account_id, warmup_enabled } = args as Partial<UpdateEmailWarmupParams>;
 62 |   return (
 63 |     typeof email_account_id === 'number' &&
 64 |     typeof warmup_enabled === 'string'
 65 |   );
 66 | }
 67 | 
 68 | export function isReconnectEmailAccountParams(args: unknown): args is ReconnectEmailAccountParams {
 69 |   if (!args || typeof args !== 'object') return false;
 70 |   const { email_account_id } = args as Partial<ReconnectEmailAccountParams>;
 71 |   return typeof email_account_id === 'number';
 72 | }
 73 | 
 74 | export function isUpdateEmailAccountTagParams(args: unknown): args is UpdateEmailAccountTagParams {
 75 |   if (!args || typeof args !== 'object') return false;
 76 |   const { id, name, color } = args as Partial<UpdateEmailAccountTagParams>;
 77 |   return (
 78 |     typeof id === 'number' &&
 79 |     typeof name === 'string' &&
 80 |     typeof color === 'string'
 81 |   );
 82 | }
 83 | 
 84 | // Interface definitions for Email Account parameters
 85 | export interface ListEmailAccountsParams {
 86 |   campaign_id?: number;
 87 |   status?: string;
 88 |   limit?: number;
 89 |   offset?: number;
 90 | }
 91 | 
 92 | export interface AddEmailToCampaignParams {
 93 |   campaign_id: number;
 94 |   email_account_id: number;
 95 | }
 96 | 
 97 | export interface RemoveEmailFromCampaignParams {
 98 |   campaign_id: number;
 99 |   email_account_id: number;
100 | }
101 | 
102 | export interface FetchEmailAccountsParams {
103 |   status?: string;
104 |   limit?: number;
105 |   offset?: number;
106 |   username?: string;
107 |   client_id?: number; // Required Client ID according to the docs
108 | }
109 | 
110 | export interface CreateEmailAccountParams {
111 |   from_name: string;         // User's name
112 |   from_email: string;        // User email
113 |   user_name: string;         // Username
114 |   password: string;          // User's password
115 |   smtp_host: string;         // Mail SMTP host
116 |   smtp_port: number;         // Mail SMTP port
117 |   imap_host: string;         // Imap host URL
118 |   imap_port: number;         // Imap port
119 |   max_email_per_day?: number; // Max number of emails per day
120 |   custom_tracking_url?: string; // Custom email tracking url
121 |   bcc?: string;              // Email BCC
122 |   signature?: string;        // Email signature
123 |   warmup_enabled?: boolean;  // Set true to enable warmup
124 |   total_warmup_per_day?: number; // Total number of warmups per day
125 |   daily_rampup?: number;     // Daily rampup number
126 |   reply_rate_percentage?: number; // Reply rate in percentage
127 |   client_id?: number;        // Client ID
128 | }
129 | 
130 | export interface UpdateEmailAccountParams {
131 |   email_account_id: number;          // ID of the email to update
132 |   max_email_per_day?: number;        // Max number of emails per day
133 |   custom_tracking_url?: string;      // Custom email tracking URL
134 |   bcc?: string;                      // Email BCC
135 |   signature?: string;                // Email signature
136 |   client_id?: number | null;         // Client ID. Set to null if not needed
137 |   time_to_wait_in_mins?: number;     // Minimum integer time (in minutes) to wait before sending next email
138 | }
139 | 
140 | export interface FetchEmailAccountByIdParams {
141 |   email_account_id: number;
142 | }
143 | 
144 | export interface UpdateEmailWarmupParams {
145 |   email_account_id: number;          // Email account ID
146 |   warmup_enabled: string;            // Set false to disable warmup
147 |   total_warmup_per_day?: number;     // Total number of warmups in a day
148 |   daily_rampup?: number;             // Set this value to increase or decrease daily ramup in warmup emails
149 |   reply_rate_percentage?: string;    // Reply rate in percentage
150 |   warmup_key_id?: string;            // If passed will update the custom warmup-key identifier
151 | }
152 | 
153 | export interface ReconnectEmailAccountParams {
154 |   email_account_id: number;
155 |   connection_details?: {
156 |     smtp_host?: string;
157 |     smtp_port?: number;
158 |     smtp_username?: string;
159 |     smtp_password?: string;
160 |     imap_host?: string;
161 |     imap_port?: number;
162 |     imap_username?: string;
163 |     imap_password?: string;
164 |     oauth_token?: string;
165 |   };
166 | }
167 | 
168 | export interface UpdateEmailAccountTagParams {
169 |   id: number;              // ID of the tag
170 |   name: string;            // Name of the tag
171 |   color: string;           // The color of the tag in HEX format
172 | }
173 | 
174 | // Email Account response interfaces
175 | export interface EmailAccount {
176 |   id: number;
177 |   email: string;
178 |   name?: string;
179 |   provider: string;
180 |   status: string;
181 |   created_at: string;
182 |   updated_at: string;
183 |   last_checked_at?: string;
184 |   warmup_enabled: boolean;
185 |   daily_limit?: number;
186 |   tags?: string[];
187 | }
188 | 
189 | export interface EmailAccountResponse {
190 |   success: boolean;
191 |   data: EmailAccount;
192 |   message?: string;
193 | }
194 | 
195 | export interface EmailAccountListResponse {
196 |   success: boolean;
197 |   data: {
198 |     accounts: EmailAccount[];
199 |     total: number;
200 |   };
201 |   message?: string;
202 | }
203 | 
204 | export interface EmailAccountActionResponse {
205 |   success: boolean;
206 |   message: string;
207 | } 
```

--------------------------------------------------------------------------------
/src/types/statistics.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { CategoryTool, ToolCategory } from './common.js';
  2 | 
  3 | // Interface for fetching campaign statistics
  4 | export interface CampaignStatisticsParams {
  5 |   campaign_id: number;
  6 |   offset?: number;
  7 |   limit?: number;
  8 |   email_sequence_number?: string;
  9 |   email_status?: string;
 10 |   sent_time_start_date?: string;
 11 |   sent_time_end_date?: string;
 12 | }
 13 | 
 14 | // Interface for fetching campaign statistics by date range
 15 | export interface CampaignStatisticsByDateParams {
 16 |   campaign_id: number;
 17 |   start_date: string;
 18 |   end_date: string;
 19 | }
 20 | 
 21 | // Interface for fetching warmup stats by email account
 22 | export interface WarmupStatsByEmailParams {
 23 |   email_account_id: number;
 24 | }
 25 | 
 26 | // Interface for fetching campaign top level analytics
 27 | export interface CampaignTopLevelAnalyticsParams {
 28 |   campaign_id: number;
 29 | }
 30 | 
 31 | // Interface for fetching campaign top level analytics by date range
 32 | export interface CampaignTopLevelAnalyticsByDateParams {
 33 |   campaign_id: number;
 34 |   start_date: string;
 35 |   end_date: string;
 36 | }
 37 | 
 38 | // Interface for fetching campaign lead statistics
 39 | export interface CampaignLeadStatisticsParams {
 40 |   campaign_id: number;
 41 |   limit?: number;
 42 |   created_at_gt?: string;
 43 |   event_time_gt?: string;
 44 |   offset?: number;
 45 | }
 46 | 
 47 | // Interface for fetching campaign mailbox statistics
 48 | export interface CampaignMailboxStatisticsParams {
 49 |   campaign_id: number;
 50 |   client_id?: string;
 51 |   offset?: number;
 52 |   limit?: number;
 53 |   start_date?: string;
 54 |   end_date?: string;
 55 |   timezone?: string;
 56 | }
 57 | 
 58 | // Interface for downloading campaign data
 59 | export interface DownloadCampaignDataParams {
 60 |   campaign_id: number;
 61 |   download_type: string;
 62 |   format: string;
 63 |   user_id?: string;
 64 | }
 65 | 
 66 | // Interface for viewing download statistics
 67 | export interface ViewDownloadStatisticsParams {
 68 |   time_period?: 'all' | 'today' | 'week' | 'month';
 69 |   group_by?: 'type' | 'format' | 'campaign' | 'date';
 70 | }
 71 | 
 72 | // Type guards for params validation
 73 | 
 74 | export function isCampaignStatisticsParams(args: unknown): args is CampaignStatisticsParams {
 75 |   if (typeof args !== 'object' || args === null) {
 76 |     return false;
 77 |   }
 78 | 
 79 |   const params = args as CampaignStatisticsParams;
 80 |   
 81 |   if (typeof params.campaign_id !== 'number') {
 82 |     return false;
 83 |   }
 84 |   
 85 |   // Optional offset must be a number if present
 86 |   if (params.offset !== undefined && typeof params.offset !== 'number') {
 87 |     return false;
 88 |   }
 89 |   
 90 |   // Optional limit must be a number if present
 91 |   if (params.limit !== undefined && typeof params.limit !== 'number') {
 92 |     return false;
 93 |   }
 94 |   
 95 |   // Optional email_sequence_number must be a string if present
 96 |   if (params.email_sequence_number !== undefined && typeof params.email_sequence_number !== 'string') {
 97 |     return false;
 98 |   }
 99 |   
100 |   // Optional email_status must be a string if present
101 |   if (params.email_status !== undefined && typeof params.email_status !== 'string') {
102 |     return false;
103 |   }
104 |   
105 |   // Optional sent_time_start_date must be a string if present
106 |   if (params.sent_time_start_date !== undefined && typeof params.sent_time_start_date !== 'string') {
107 |     return false;
108 |   }
109 |   
110 |   // Optional sent_time_end_date must be a string if present
111 |   if (params.sent_time_end_date !== undefined && typeof params.sent_time_end_date !== 'string') {
112 |     return false;
113 |   }
114 |   
115 |   return true;
116 | }
117 | 
118 | export function isCampaignStatisticsByDateParams(args: unknown): args is CampaignStatisticsByDateParams {
119 |   if (typeof args !== 'object' || args === null) {
120 |     return false;
121 |   }
122 | 
123 |   const params = args as CampaignStatisticsByDateParams;
124 |   
125 |   return (
126 |     typeof params.campaign_id === 'number' &&
127 |     typeof params.start_date === 'string' &&
128 |     typeof params.end_date === 'string'
129 |   );
130 | }
131 | 
132 | export function isWarmupStatsByEmailParams(args: unknown): args is WarmupStatsByEmailParams {
133 |   if (typeof args !== 'object' || args === null) {
134 |     return false;
135 |   }
136 | 
137 |   const params = args as WarmupStatsByEmailParams;
138 |   
139 |   return typeof params.email_account_id === 'number';
140 | }
141 | 
142 | export function isCampaignTopLevelAnalyticsParams(args: unknown): args is CampaignTopLevelAnalyticsParams {
143 |   if (typeof args !== 'object' || args === null) {
144 |     return false;
145 |   }
146 | 
147 |   const params = args as CampaignTopLevelAnalyticsParams;
148 |   
149 |   return typeof params.campaign_id === 'number';
150 | }
151 | 
152 | export function isCampaignTopLevelAnalyticsByDateParams(args: unknown): args is CampaignTopLevelAnalyticsByDateParams {
153 |   if (typeof args !== 'object' || args === null) {
154 |     return false;
155 |   }
156 | 
157 |   const params = args as CampaignTopLevelAnalyticsByDateParams;
158 |   
159 |   return (
160 |     typeof params.campaign_id === 'number' &&
161 |     typeof params.start_date === 'string' &&
162 |     typeof params.end_date === 'string'
163 |   );
164 | }
165 | 
166 | export function isCampaignLeadStatisticsParams(args: unknown): args is CampaignLeadStatisticsParams {
167 |   if (typeof args !== 'object' || args === null) {
168 |     return false;
169 |   }
170 | 
171 |   const params = args as CampaignLeadStatisticsParams;
172 |   
173 |   if (typeof params.campaign_id !== 'number') {
174 |     return false;
175 |   }
176 |   
177 |   // Optional limit must be a string if present (it will be converted to number)
178 |   if (params.limit !== undefined && typeof params.limit !== 'number') {
179 |     return false;
180 |   }
181 |   
182 |   // Optional created_at_gt must be a string if present
183 |   if (params.created_at_gt !== undefined && typeof params.created_at_gt !== 'string') {
184 |     return false;
185 |   }
186 |   
187 |   // Optional event_time_gt must be a string if present
188 |   if (params.event_time_gt !== undefined && typeof params.event_time_gt !== 'string') {
189 |     return false;
190 |   }
191 |   
192 |   // Optional offset must be a string if present (it will be converted to number)
193 |   if (params.offset !== undefined && typeof params.offset !== 'number') {
194 |     return false;
195 |   }
196 |   
197 |   return true;
198 | }
199 | 
200 | export function isCampaignMailboxStatisticsParams(obj: unknown): obj is CampaignMailboxStatisticsParams {
201 |   return (
202 |     !!obj &&
203 |     typeof obj === 'object' &&
204 |     'campaign_id' in obj &&
205 |     typeof (obj as CampaignMailboxStatisticsParams).campaign_id === 'number'
206 |   );
207 | }
208 | 
209 | export function isDownloadCampaignDataParams(obj: unknown): obj is DownloadCampaignDataParams {
210 |   if (!obj || typeof obj !== 'object') return false;
211 |   
212 |   const params = obj as Partial<DownloadCampaignDataParams>;
213 |   
214 |   // Check required fields
215 |   if (typeof params.campaign_id !== 'number') return false;
216 |   
217 |   if (!params.download_type || 
218 |       !['analytics', 'leads', 'sequence', 'full_export'].includes(params.download_type)) {
219 |     return false;
220 |   }
221 |   
222 |   if (!params.format || !['json', 'csv'].includes(params.format)) {
223 |     return false;
224 |   }
225 |   
226 |   // Check optional fields
227 |   if (params.user_id !== undefined && typeof params.user_id !== 'string') {
228 |     return false;
229 |   }
230 |   
231 |   return true;
232 | }
233 | 
234 | export function isViewDownloadStatisticsParams(obj: unknown): obj is ViewDownloadStatisticsParams {
235 |   if (!obj || typeof obj !== 'object') return false;
236 |   
237 |   const params = obj as Partial<ViewDownloadStatisticsParams>;
238 |   
239 |   // Both fields are optional, but need to be validated if present
240 |   if (params.time_period !== undefined && 
241 |       !['all', 'today', 'week', 'month'].includes(params.time_period)) {
242 |     return false;
243 |   }
244 |   
245 |   if (params.group_by !== undefined &&
246 |       !['type', 'format', 'campaign', 'date'].includes(params.group_by)) {
247 |     return false;
248 |   }
249 |   
250 |   return true;
251 | } 
```

--------------------------------------------------------------------------------
/src/types/lead.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { CategoryTool, ToolCategory } from './common.js';
  2 | 
  3 | // Interface for listing leads
  4 | export interface ListLeadsParams {
  5 |   campaign_id?: number;
  6 |   status?: string;
  7 |   limit?: number;
  8 |   offset?: number;
  9 |   search?: string;
 10 |   start_date?: string;
 11 |   end_date?: string;
 12 | }
 13 | 
 14 | // Interface for getting a single lead
 15 | export interface GetLeadParams {
 16 |   lead_id: number;
 17 | }
 18 | 
 19 | // Interface for adding a lead to a campaign
 20 | export interface AddLeadToCampaignParams {
 21 |   campaign_id: number;
 22 |   email: string;
 23 |   first_name?: string;
 24 |   last_name?: string;
 25 |   company?: string;
 26 |   title?: string;
 27 |   phone?: string;
 28 |   custom_fields?: Record<string, string>;
 29 | }
 30 | 
 31 | // Interface for updating a lead
 32 | export interface UpdateLeadParams {
 33 |   lead_id: number;
 34 |   email?: string;
 35 |   first_name?: string;
 36 |   last_name?: string;
 37 |   company?: string;
 38 |   title?: string;
 39 |   phone?: string;
 40 |   custom_fields?: Record<string, string>;
 41 | }
 42 | 
 43 | // Interface for updating lead status
 44 | export interface UpdateLeadStatusParams {
 45 |   lead_id: number;
 46 |   status: string;
 47 | }
 48 | 
 49 | // Interface for bulk importing leads
 50 | export interface BulkImportLeadsParams {
 51 |   campaign_id: number;
 52 |   leads: Array<{
 53 |     email: string;
 54 |     first_name?: string;
 55 |     last_name?: string;
 56 |     company?: string;
 57 |     title?: string;
 58 |     phone?: string;
 59 |     custom_fields?: Record<string, string>;
 60 |   }>;
 61 | }
 62 | 
 63 | // Interface for deleting a lead
 64 | export interface DeleteLeadParams {
 65 |   lead_id: number;
 66 | }
 67 | 
 68 | // Type guards for params validation
 69 | 
 70 | export function isListLeadsParams(args: unknown): args is ListLeadsParams {
 71 |   if (typeof args !== 'object' || args === null) {
 72 |     return false;
 73 |   }
 74 | 
 75 |   const params = args as ListLeadsParams;
 76 |   
 77 |   // Optional campaign_id must be a number if present
 78 |   if (params.campaign_id !== undefined && typeof params.campaign_id !== 'number') {
 79 |     return false;
 80 |   }
 81 |   
 82 |   // Optional status must be a string if present
 83 |   if (params.status !== undefined && typeof params.status !== 'string') {
 84 |     return false;
 85 |   }
 86 |   
 87 |   // Optional limit must be a number if present
 88 |   if (params.limit !== undefined && typeof params.limit !== 'number') {
 89 |     return false;
 90 |   }
 91 |   
 92 |   // Optional offset must be a number if present
 93 |   if (params.offset !== undefined && typeof params.offset !== 'number') {
 94 |     return false;
 95 |   }
 96 |   
 97 |   // Optional search must be a string if present
 98 |   if (params.search !== undefined && typeof params.search !== 'string') {
 99 |     return false;
100 |   }
101 |   
102 |   // Optional start_date must be a string if present
103 |   if (params.start_date !== undefined && typeof params.start_date !== 'string') {
104 |     return false;
105 |   }
106 |   
107 |   // Optional end_date must be a string if present
108 |   if (params.end_date !== undefined && typeof params.end_date !== 'string') {
109 |     return false;
110 |   }
111 |   
112 |   return true;
113 | }
114 | 
115 | export function isGetLeadParams(args: unknown): args is GetLeadParams {
116 |   return (
117 |     typeof args === 'object' &&
118 |     args !== null &&
119 |     'lead_id' in args &&
120 |     typeof (args as { lead_id: unknown }).lead_id === 'number'
121 |   );
122 | }
123 | 
124 | export function isAddLeadToCampaignParams(args: unknown): args is AddLeadToCampaignParams {
125 |   if (
126 |     typeof args !== 'object' ||
127 |     args === null ||
128 |     !('campaign_id' in args) ||
129 |     !('email' in args) ||
130 |     typeof (args as { campaign_id: unknown }).campaign_id !== 'number' ||
131 |     typeof (args as { email: unknown }).email !== 'string'
132 |   ) {
133 |     return false;
134 |   }
135 |   
136 |   const params = args as AddLeadToCampaignParams;
137 |   
138 |   // Optional fields validation
139 |   if (params.first_name !== undefined && typeof params.first_name !== 'string') {
140 |     return false;
141 |   }
142 |   if (params.last_name !== undefined && typeof params.last_name !== 'string') {
143 |     return false;
144 |   }
145 |   if (params.company !== undefined && typeof params.company !== 'string') {
146 |     return false;
147 |   }
148 |   if (params.title !== undefined && typeof params.title !== 'string') {
149 |     return false;
150 |   }
151 |   if (params.phone !== undefined && typeof params.phone !== 'string') {
152 |     return false;
153 |   }
154 |   if (
155 |     params.custom_fields !== undefined && 
156 |     (typeof params.custom_fields !== 'object' || params.custom_fields === null)
157 |   ) {
158 |     return false;
159 |   }
160 |   
161 |   return true;
162 | }
163 | 
164 | export function isUpdateLeadParams(args: unknown): args is UpdateLeadParams {
165 |   if (
166 |     typeof args !== 'object' ||
167 |     args === null ||
168 |     !('lead_id' in args) ||
169 |     typeof (args as { lead_id: unknown }).lead_id !== 'number'
170 |   ) {
171 |     return false;
172 |   }
173 |   
174 |   const params = args as UpdateLeadParams;
175 |   
176 |   // Optional fields validation
177 |   if (params.email !== undefined && typeof params.email !== 'string') {
178 |     return false;
179 |   }
180 |   if (params.first_name !== undefined && typeof params.first_name !== 'string') {
181 |     return false;
182 |   }
183 |   if (params.last_name !== undefined && typeof params.last_name !== 'string') {
184 |     return false;
185 |   }
186 |   if (params.company !== undefined && typeof params.company !== 'string') {
187 |     return false;
188 |   }
189 |   if (params.title !== undefined && typeof params.title !== 'string') {
190 |     return false;
191 |   }
192 |   if (params.phone !== undefined && typeof params.phone !== 'string') {
193 |     return false;
194 |   }
195 |   if (
196 |     params.custom_fields !== undefined && 
197 |     (typeof params.custom_fields !== 'object' || params.custom_fields === null)
198 |   ) {
199 |     return false;
200 |   }
201 |   
202 |   return true;
203 | }
204 | 
205 | export function isUpdateLeadStatusParams(args: unknown): args is UpdateLeadStatusParams {
206 |   return (
207 |     typeof args === 'object' &&
208 |     args !== null &&
209 |     'lead_id' in args &&
210 |     'status' in args &&
211 |     typeof (args as { lead_id: unknown }).lead_id === 'number' &&
212 |     typeof (args as { status: unknown }).status === 'string'
213 |   );
214 | }
215 | 
216 | export function isBulkImportLeadsParams(args: unknown): args is BulkImportLeadsParams {
217 |   if (
218 |     typeof args !== 'object' ||
219 |     args === null ||
220 |     !('campaign_id' in args) ||
221 |     !('leads' in args) ||
222 |     typeof (args as { campaign_id: unknown }).campaign_id !== 'number' ||
223 |     !Array.isArray((args as { leads: unknown }).leads)
224 |   ) {
225 |     return false;
226 |   }
227 |   
228 |   const params = args as BulkImportLeadsParams;
229 |   
230 |   // Validate each lead in the leads array
231 |   for (const lead of params.leads) {
232 |     if (
233 |       typeof lead !== 'object' ||
234 |       lead === null ||
235 |       !('email' in lead) ||
236 |       typeof lead.email !== 'string'
237 |     ) {
238 |       return false;
239 |     }
240 |     
241 |     // Optional fields validation
242 |     if (lead.first_name !== undefined && typeof lead.first_name !== 'string') {
243 |       return false;
244 |     }
245 |     if (lead.last_name !== undefined && typeof lead.last_name !== 'string') {
246 |       return false;
247 |     }
248 |     if (lead.company !== undefined && typeof lead.company !== 'string') {
249 |       return false;
250 |     }
251 |     if (lead.title !== undefined && typeof lead.title !== 'string') {
252 |       return false;
253 |     }
254 |     if (lead.phone !== undefined && typeof lead.phone !== 'string') {
255 |       return false;
256 |     }
257 |     if (
258 |       lead.custom_fields !== undefined && 
259 |       (typeof lead.custom_fields !== 'object' || lead.custom_fields === null)
260 |     ) {
261 |       return false;
262 |     }
263 |   }
264 |   
265 |   return true;
266 | }
267 | 
268 | export function isDeleteLeadParams(args: unknown): args is DeleteLeadParams {
269 |   return (
270 |     typeof args === 'object' &&
271 |     args !== null &&
272 |     'lead_id' in args &&
273 |     typeof (args as { lead_id: unknown }).lead_id === 'number'
274 |   );
275 | } 
```

--------------------------------------------------------------------------------
/src/cli.ts:
--------------------------------------------------------------------------------

```typescript
  1 | #!/usr/bin/env node
  2 | 
  3 | import { program } from 'commander';
  4 | import dotenv from 'dotenv';
  5 | import { spawn } from 'child_process';
  6 | import path from 'path';
  7 | import { fileURLToPath } from 'url';
  8 | import fs from 'fs';
  9 | import readline from 'readline';
 10 | import { createInterface } from 'readline';
 11 | 
 12 | // Load environment variables from .env file
 13 | dotenv.config();
 14 | 
 15 | // Get the directory name of the current module
 16 | const __filename = fileURLToPath(import.meta.url);
 17 | const __dirname = path.dirname(__filename);
 18 | 
 19 | // Get version from package.json
 20 | const version = '1.0.0'; // This should ideally be imported from package.json
 21 | 
 22 | // License server URL
 23 | const LICENSE_SERVER_URL = 'https://sea-turtle-app-64etr.ondigitalocean.app/';
 24 | 
 25 | // Function to prompt for value interactively
 26 | async function promptForValue(question: string, hidden = false): Promise<string> {
 27 |   const rl = createInterface({
 28 |     input: process.stdin,
 29 |     output: process.stdout,
 30 |   });
 31 |   
 32 |   return new Promise((resolve) => {
 33 |     if (hidden) {
 34 |       process.stdout.write(question);
 35 |       process.stdin.setRawMode(true);
 36 |       let password = '';
 37 |       
 38 |       process.stdin.on('data', (chunk) => {
 39 |         const str = chunk.toString();
 40 |         if (str === '\n' || str === '\r' || str === '\u0004') {
 41 |           process.stdin.setRawMode(false);
 42 |           process.stdout.write('\n');
 43 |           rl.close();
 44 |           resolve(password);
 45 |         } else if (str === '\u0003') { // Ctrl+C
 46 |           process.exit(0);
 47 |         } else if (str === '\u007F') { // Backspace
 48 |           if (password.length > 0) {
 49 |             password = password.substring(0, password.length - 1);
 50 |             process.stdout.write('\b \b');
 51 |           }
 52 |         } else {
 53 |           password += str;
 54 |           process.stdout.write('*');
 55 |         }
 56 |       });
 57 |     } else {
 58 |       rl.question(question, (answer) => {
 59 |         rl.close();
 60 |         resolve(answer);
 61 |       });
 62 |     }
 63 |   });
 64 | }
 65 | 
 66 | // Function to ensure required environment variables are set
 67 | async function ensureEnvVars(): Promise<void> {
 68 |   // Check for API key
 69 |   if (!process.env.SMARTLEAD_API_KEY) {
 70 |     console.log('\nSmartlead API Key not found.');
 71 |     const apiKey = await promptForValue('Enter your Smartlead API Key: ', true);
 72 |     if (apiKey) {
 73 |       process.env.SMARTLEAD_API_KEY = apiKey;
 74 |     } else {
 75 |       console.log('Smartlead API Key is required to continue.');
 76 |       process.exit(1);
 77 |     }
 78 |   }
 79 | 
 80 |   // Check for license key
 81 |   if (!process.env.JEAN_LICENSE_KEY) {
 82 |     console.log('\nJean License Key not found. Defaulting to free tier access.');
 83 |     process.env.JEAN_LICENSE_KEY = 'JEANPARTNER';
 84 |   }
 85 | 
 86 |   // Set license server URL if not set
 87 |   if (!process.env.LICENSE_SERVER_URL) {
 88 |     process.env.LICENSE_SERVER_URL = LICENSE_SERVER_URL;
 89 |   }
 90 |   
 91 |   console.log('\nConfiguration complete!\n');
 92 | }
 93 | 
 94 | // Function to save environment variables to .env file
 95 | async function saveEnvToFile(): Promise<void> {
 96 |   if (process.env.SMARTLEAD_API_KEY || process.env.JEAN_LICENSE_KEY) {
 97 |     const saveEnv = await promptForValue('Do you want to save these settings to a .env file for future use? (y/n): ');
 98 |     if (saveEnv.toLowerCase() === 'y') {
 99 |       try {
100 |         let envContent = '';
101 |         if (process.env.SMARTLEAD_API_KEY) {
102 |           envContent += `SMARTLEAD_API_KEY=${process.env.SMARTLEAD_API_KEY}\n`;
103 |         }
104 |         if (process.env.JEAN_LICENSE_KEY) {
105 |           envContent += `JEAN_LICENSE_KEY=${process.env.JEAN_LICENSE_KEY}\n`;
106 |         }
107 |         if (process.env.LICENSE_SERVER_URL) {
108 |           envContent += `LICENSE_SERVER_URL=${process.env.LICENSE_SERVER_URL}\n`;
109 |         }
110 |         
111 |         fs.writeFileSync('.env', envContent);
112 |         console.log('Settings saved to .env file in the current directory.');
113 |       } catch (error) {
114 |         console.error('Error saving .env file:', error);
115 |       }
116 |     }
117 |   }
118 | }
119 | 
120 | program
121 |   .version(version)
122 |   .description('Smartlead MCP Server CLI');
123 | 
124 | program
125 |   .command('start')
126 |   .description('Start the MCP server in standard STDIO mode')
127 |   .option('--api-key <key>', 'Your Smartlead API Key')
128 |   .option('--license-key <key>', 'Your Jean License Key')
129 |   .action(async (options: { apiKey?: string; licenseKey?: string }) => {
130 |     // Set env vars from command line options if provided
131 |     if (options.apiKey) process.env.SMARTLEAD_API_KEY = options.apiKey;
132 |     if (options.licenseKey) process.env.JEAN_LICENSE_KEY = options.licenseKey;
133 |     
134 |     // Ensure required env vars are set (will prompt if missing)
135 |     await ensureEnvVars();
136 |     await saveEnvToFile();
137 |     
138 |     console.log('Starting Smartlead MCP Server in STDIO mode...');
139 |     // Run as a separate process instead of trying to import
140 |     const indexPath = path.join(__dirname, 'index.js');
141 |     const child = spawn('node', [indexPath], {
142 |       stdio: 'inherit',
143 |       env: process.env
144 |     });
145 |     
146 |     process.on('SIGINT', () => {
147 |       child.kill();
148 |       process.exit();
149 |     });
150 |   });
151 | 
152 | program
153 |   .command('sse')
154 |   .description('Start the MCP server in SSE mode for n8n integration')
155 |   .option('-p, --port <port>', 'Port to run the server on', '3000')
156 |   .option('--api-key <key>', 'Your Smartlead API Key')
157 |   .option('--license-key <key>', 'Your Jean License Key')
158 |   .action(async (options: { port: string; apiKey?: string; licenseKey?: string }) => {
159 |     // Set env vars from command line options if provided
160 |     if (options.apiKey) process.env.SMARTLEAD_API_KEY = options.apiKey;
161 |     if (options.licenseKey) process.env.JEAN_LICENSE_KEY = options.licenseKey;
162 |     
163 |     // Ensure required env vars are set (will prompt if missing)
164 |     await ensureEnvVars();
165 |     await saveEnvToFile();
166 |     
167 |     console.log(`Starting Smartlead MCP Server in SSE mode on port ${options.port}...`);
168 |     console.log(`Connect from n8n to http://localhost:${options.port}/sse`);
169 |     
170 |     // Use supergateway to run in SSE mode
171 |     const indexPath = path.join(__dirname, 'index.js');
172 |     const supergateway = spawn('npx', [
173 |       '-y', 
174 |       'supergateway', 
175 |       '--stdio', 
176 |       `node ${indexPath}`, 
177 |       '--port', 
178 |       options.port
179 |     ], { 
180 |       shell: true,
181 |       stdio: 'inherit',
182 |       env: process.env
183 |     });
184 |     
185 |     process.on('SIGINT', () => {
186 |       supergateway.kill();
187 |       process.exit();
188 |     });
189 |   });
190 | 
191 | program
192 |   .command('config')
193 |   .description('Show current configuration and set up environment variables')
194 |   .option('--api-key <key>', 'Set your Smartlead API Key')
195 |   .option('--license-key <key>', 'Set your Jean License Key')
196 |   .action(async (options: { apiKey?: string; licenseKey?: string }) => {
197 |     if (options.apiKey) process.env.SMARTLEAD_API_KEY = options.apiKey;
198 |     if (options.licenseKey) process.env.JEAN_LICENSE_KEY = options.licenseKey;
199 |     
200 |     await ensureEnvVars();
201 |     await saveEnvToFile();
202 |     
203 |     console.log('\nSmartlead MCP Server Configuration:');
204 |     console.log(`API URL: ${process.env.SMARTLEAD_API_URL || 'https://server.smartlead.ai/api/v1'}`);
205 |     console.log(`License Server: ${process.env.LICENSE_SERVER_URL || LICENSE_SERVER_URL}`);
206 |     console.log(`License Status: ${process.env.JEAN_LICENSE_KEY ? 'Configured' : 'Not Configured'}`);
207 |     console.log('\nConfiguration saved and ready to use.');
208 |   });
209 | 
210 | program.parse(process.argv);
211 | 
212 | // Default to help if no command is provided
213 | if (!process.argv.slice(2).length) {
214 |   program.outputHelp();
215 | } 
```

--------------------------------------------------------------------------------
/src/handlers/webhooks.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { AxiosInstance } from 'axios';
  2 | import { McpError, ErrorCode } from '@modelcontextprotocol/sdk/types.js';
  3 | import {
  4 |   isFetchWebhooksByCampaignParams,
  5 |   isUpsertCampaignWebhookParams,
  6 |   isDeleteCampaignWebhookParams,
  7 |   isGetWebhooksPublishSummaryParams,
  8 |   isRetriggerFailedEventsParams
  9 | } from '../types/webhooks.js';
 10 | 
 11 | // SmartLead API base URL
 12 | const SMARTLEAD_API_URL = 'https://server.smartlead.ai/api/v1';
 13 | 
 14 | // Handler for Webhook-related tools
 15 | export async function handleWebhookTool(
 16 |   toolName: string,
 17 |   args: unknown,
 18 |   apiClient: AxiosInstance,
 19 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
 20 | ) {
 21 |   switch (toolName) {
 22 |     case 'smartlead_fetch_webhooks_by_campaign': {
 23 |       return handleFetchWebhooksByCampaign(args, apiClient, withRetry);
 24 |     }
 25 |     case 'smartlead_upsert_campaign_webhook': {
 26 |       return handleUpsertCampaignWebhook(args, apiClient, withRetry);
 27 |     }
 28 |     case 'smartlead_delete_campaign_webhook': {
 29 |       return handleDeleteCampaignWebhook(args, apiClient, withRetry);
 30 |     }
 31 |     case 'smartlead_get_webhooks_publish_summary': {
 32 |       return handleGetWebhooksPublishSummary(args, apiClient, withRetry);
 33 |     }
 34 |     case 'smartlead_retrigger_failed_events': {
 35 |       return handleRetriggerFailedEvents(args, apiClient, withRetry);
 36 |     }
 37 |     default:
 38 |       throw new Error(`Unknown Webhook tool: ${toolName}`);
 39 |   }
 40 | }
 41 | 
 42 | // Create a modified client for SmartLead API with the correct base URL
 43 | function createSmartLeadClient(apiClient: AxiosInstance) {
 44 |   return {
 45 |     get: (url: string, config?: any) => 
 46 |       apiClient.get(`${SMARTLEAD_API_URL}${url}`, config),
 47 |     post: (url: string, data?: any, config?: any) => 
 48 |       apiClient.post(`${SMARTLEAD_API_URL}${url}`, data, config),
 49 |     put: (url: string, data?: any, config?: any) => 
 50 |       apiClient.put(`${SMARTLEAD_API_URL}${url}`, data, config),
 51 |     delete: (url: string, config?: any) => 
 52 |       apiClient.delete(`${SMARTLEAD_API_URL}${url}`, config)
 53 |   };
 54 | }
 55 | 
 56 | // Individual handlers for each tool
 57 | async function handleFetchWebhooksByCampaign(
 58 |   args: unknown,
 59 |   apiClient: AxiosInstance,
 60 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
 61 | ) {
 62 |   if (!isFetchWebhooksByCampaignParams(args)) {
 63 |     throw new McpError(
 64 |       ErrorCode.InvalidParams,
 65 |       'Invalid arguments for smartlead_fetch_webhooks_by_campaign'
 66 |     );
 67 |   }
 68 | 
 69 |   try {
 70 |     const smartLeadClient = createSmartLeadClient(apiClient);
 71 |     const { campaign_id } = args;
 72 |     
 73 |     const response = await withRetry(
 74 |       async () => smartLeadClient.get(`/campaigns/${campaign_id}/webhooks`),
 75 |       'fetch webhooks by campaign'
 76 |     );
 77 | 
 78 |     return {
 79 |       content: [
 80 |         {
 81 |           type: 'text',
 82 |           text: JSON.stringify(response.data, null, 2),
 83 |         },
 84 |       ],
 85 |       isError: false,
 86 |     };
 87 |   } catch (error: any) {
 88 |     return {
 89 |       content: [{ 
 90 |         type: 'text', 
 91 |         text: `API Error: ${error.response?.data?.message || error.message}` 
 92 |       }],
 93 |       isError: true,
 94 |     };
 95 |   }
 96 | }
 97 | 
 98 | async function handleUpsertCampaignWebhook(
 99 |   args: unknown,
100 |   apiClient: AxiosInstance,
101 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
102 | ) {
103 |   if (!isUpsertCampaignWebhookParams(args)) {
104 |     throw new McpError(
105 |       ErrorCode.InvalidParams,
106 |       'Invalid arguments for smartlead_upsert_campaign_webhook'
107 |     );
108 |   }
109 | 
110 |   try {
111 |     const smartLeadClient = createSmartLeadClient(apiClient);
112 |     const { campaign_id, ...webhookData } = args;
113 |     
114 |     const response = await withRetry(
115 |       async () => smartLeadClient.post(`/campaigns/${campaign_id}/webhooks`, webhookData),
116 |       'upsert campaign webhook'
117 |     );
118 | 
119 |     return {
120 |       content: [
121 |         {
122 |           type: 'text',
123 |           text: JSON.stringify(response.data, null, 2),
124 |         },
125 |       ],
126 |       isError: false,
127 |     };
128 |   } catch (error: any) {
129 |     return {
130 |       content: [{ 
131 |         type: 'text', 
132 |         text: `API Error: ${error.response?.data?.message || error.message}` 
133 |       }],
134 |       isError: true,
135 |     };
136 |   }
137 | }
138 | 
139 | async function handleDeleteCampaignWebhook(
140 |   args: unknown,
141 |   apiClient: AxiosInstance,
142 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
143 | ) {
144 |   if (!isDeleteCampaignWebhookParams(args)) {
145 |     throw new McpError(
146 |       ErrorCode.InvalidParams,
147 |       'Invalid arguments for smartlead_delete_campaign_webhook'
148 |     );
149 |   }
150 | 
151 |   try {
152 |     const smartLeadClient = createSmartLeadClient(apiClient);
153 |     const { campaign_id, id } = args;
154 |     
155 |     // The API documentation suggests a DELETE with a body payload
156 |     // Different from typical REST practices but following the API spec
157 |     const response = await withRetry(
158 |       async () => smartLeadClient.delete(`/campaigns/${campaign_id}/webhooks`, { 
159 |         data: { id }
160 |       }),
161 |       'delete campaign webhook'
162 |     );
163 | 
164 |     return {
165 |       content: [
166 |         {
167 |           type: 'text',
168 |           text: JSON.stringify(response.data, null, 2),
169 |         },
170 |       ],
171 |       isError: false,
172 |     };
173 |   } catch (error: any) {
174 |     return {
175 |       content: [{ 
176 |         type: 'text', 
177 |         text: `API Error: ${error.response?.data?.message || error.message}` 
178 |       }],
179 |       isError: true,
180 |     };
181 |   }
182 | }
183 | 
184 | async function handleGetWebhooksPublishSummary(
185 |   args: unknown,
186 |   apiClient: AxiosInstance,
187 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
188 | ) {
189 |   if (!isGetWebhooksPublishSummaryParams(args)) {
190 |     throw new McpError(
191 |       ErrorCode.InvalidParams,
192 |       'Invalid arguments for smartlead_get_webhooks_publish_summary'
193 |     );
194 |   }
195 | 
196 |   try {
197 |     const smartLeadClient = createSmartLeadClient(apiClient);
198 |     const { campaign_id, fromTime, toTime } = args;
199 |     
200 |     let url = `/campaigns/${campaign_id}/webhooks/summary`;
201 |     const queryParams = new URLSearchParams();
202 |     
203 |     if (fromTime) {
204 |       queryParams.append('fromTime', fromTime);
205 |     }
206 |     
207 |     if (toTime) {
208 |       queryParams.append('toTime', toTime);
209 |     }
210 |     
211 |     if (queryParams.toString()) {
212 |       url += `?${queryParams.toString()}`;
213 |     }
214 |     
215 |     const response = await withRetry(
216 |       async () => smartLeadClient.get(url),
217 |       'get webhooks publish summary'
218 |     );
219 | 
220 |     return {
221 |       content: [
222 |         {
223 |           type: 'text',
224 |           text: JSON.stringify(response.data, null, 2),
225 |         },
226 |       ],
227 |       isError: false,
228 |     };
229 |   } catch (error: any) {
230 |     return {
231 |       content: [{ 
232 |         type: 'text', 
233 |         text: `API Error: ${error.response?.data?.message || error.message}` 
234 |       }],
235 |       isError: true,
236 |     };
237 |   }
238 | }
239 | 
240 | async function handleRetriggerFailedEvents(
241 |   args: unknown,
242 |   apiClient: AxiosInstance,
243 |   withRetry: <T>(operation: () => Promise<T>, context: string) => Promise<T>
244 | ) {
245 |   if (!isRetriggerFailedEventsParams(args)) {
246 |     throw new McpError(
247 |       ErrorCode.InvalidParams,
248 |       'Invalid arguments for smartlead_retrigger_failed_events'
249 |     );
250 |   }
251 | 
252 |   try {
253 |     const smartLeadClient = createSmartLeadClient(apiClient);
254 |     const { campaign_id, fromTime, toTime } = args;
255 |     
256 |     const response = await withRetry(
257 |       async () => smartLeadClient.post(`/campaigns/${campaign_id}/webhooks/retrigger-failed-events`, {
258 |         fromTime,
259 |         toTime
260 |       }),
261 |       'retrigger failed events'
262 |     );
263 | 
264 |     return {
265 |       content: [
266 |         {
267 |           type: 'text',
268 |           text: JSON.stringify(response.data, null, 2),
269 |         },
270 |       ],
271 |       isError: false,
272 |     };
273 |   } catch (error: any) {
274 |     return {
275 |       content: [{ 
276 |         type: 'text', 
277 |         text: `API Error: ${error.response?.data?.message || error.message}` 
278 |       }],
279 |       isError: true,
280 |     };
281 |   }
282 | } 
```

--------------------------------------------------------------------------------
/src/types/campaign.ts:
--------------------------------------------------------------------------------

```typescript
  1 | // Type definitions for campaign management
  2 | 
  3 | export interface CreateCampaignParams {
  4 |   name: string;
  5 |   client_id?: number;
  6 | }
  7 | 
  8 | export interface UpdateCampaignScheduleParams {
  9 |   campaign_id: number;
 10 |   timezone?: string;
 11 |   days_of_the_week?: number[];
 12 |   start_hour?: string;
 13 |   end_hour?: string;
 14 |   min_time_btw_emails?: number;
 15 |   max_new_leads_per_day?: number;
 16 |   schedule_start_time?: string;
 17 | }
 18 | 
 19 | export interface UpdateCampaignSettingsParams {
 20 |   campaign_id: number;
 21 |   name?: string;
 22 |   status?: 'active' | 'paused' | 'completed';
 23 |   settings?: Record<string, any>;
 24 | }
 25 | 
 26 | export interface UpdateCampaignStatusParams {
 27 |   campaign_id: number;
 28 |   status: 'PAUSED' | 'STOPPED' | 'START';
 29 | }
 30 | 
 31 | export interface GetCampaignParams {
 32 |   campaign_id: number;
 33 | }
 34 | 
 35 | export interface GetCampaignSequenceParams {
 36 |   campaign_id: number;
 37 | }
 38 | 
 39 | export interface ListCampaignsParams {
 40 |   status?: 'active' | 'paused' | 'completed';
 41 |   limit?: number;
 42 |   offset?: number;
 43 | }
 44 | 
 45 | export interface SaveCampaignSequenceParams {
 46 |   campaign_id: number;
 47 |   sequence: Array<{
 48 |     seq_number: number;
 49 |     seq_delay_details: {
 50 |       delay_in_days: number;
 51 |     };
 52 |     variant_distribution_type: 'MANUAL_EQUAL' | 'MANUAL_PERCENTAGE' | 'AI_EQUAL';
 53 |     lead_distribution_percentage?: number;
 54 |     winning_metric_property?: 'OPEN_RATE' | 'CLICK_RATE' | 'REPLY_RATE' | 'POSITIVE_REPLY_RATE';
 55 |     seq_variants: Array<{
 56 |       subject: string;
 57 |       email_body: string;
 58 |       variant_label: string;
 59 |       id?: number;
 60 |       variant_distribution_percentage?: number;
 61 |     }>;
 62 |   }>;
 63 | }
 64 | 
 65 | // New interface definitions for remaining campaign management endpoints
 66 | export interface GetCampaignsByLeadParams {
 67 |   lead_id: number;
 68 | }
 69 | 
 70 | export interface ExportCampaignLeadsParams {
 71 |   campaign_id: number;
 72 | }
 73 | 
 74 | export interface DeleteCampaignParams {
 75 |   campaign_id: number;
 76 | }
 77 | 
 78 | export interface GetCampaignAnalyticsByDateParams {
 79 |   campaign_id: number;
 80 |   start_date: string;
 81 |   end_date: string;
 82 | }
 83 | 
 84 | export interface GetCampaignSequenceAnalyticsParams {
 85 |   campaign_id: number;
 86 |   start_date: string;
 87 |   end_date: string;
 88 |   time_zone?: string;
 89 | }
 90 | 
 91 | // Type guards
 92 | export function isCreateCampaignParams(args: unknown): args is CreateCampaignParams {
 93 |   return (
 94 |     typeof args === 'object' &&
 95 |     args !== null &&
 96 |     'name' in args &&
 97 |     typeof (args as { name: unknown }).name === 'string'
 98 |   );
 99 | }
100 | 
101 | export function isUpdateCampaignScheduleParams(args: unknown): args is UpdateCampaignScheduleParams {
102 |   return (
103 |     typeof args === 'object' &&
104 |     args !== null &&
105 |     'campaign_id' in args &&
106 |     typeof (args as { campaign_id: unknown }).campaign_id === 'number'
107 |   );
108 | }
109 | 
110 | export function isUpdateCampaignSettingsParams(args: unknown): args is UpdateCampaignSettingsParams {
111 |   return (
112 |     typeof args === 'object' &&
113 |     args !== null &&
114 |     'campaign_id' in args &&
115 |     typeof (args as { campaign_id: unknown }).campaign_id === 'number'
116 |   );
117 | }
118 | 
119 | export function isUpdateCampaignStatusParams(args: unknown): args is UpdateCampaignStatusParams {
120 |   return (
121 |     typeof args === 'object' &&
122 |     args !== null &&
123 |     'campaign_id' in args &&
124 |     typeof (args as { campaign_id: unknown }).campaign_id === 'number' &&
125 |     'status' in args &&
126 |     typeof (args as { status: unknown }).status === 'string' &&
127 |     ['PAUSED', 'STOPPED', 'START'].includes((args as { status: string }).status)
128 |   );
129 | }
130 | 
131 | export function isGetCampaignParams(args: unknown): args is GetCampaignParams {
132 |   return (
133 |     typeof args === 'object' &&
134 |     args !== null &&
135 |     'campaign_id' in args &&
136 |     typeof (args as { campaign_id: unknown }).campaign_id === 'number'
137 |   );
138 | }
139 | 
140 | export function isGetCampaignSequenceParams(args: unknown): args is GetCampaignSequenceParams {
141 |   return (
142 |     typeof args === 'object' &&
143 |     args !== null &&
144 |     'campaign_id' in args &&
145 |     typeof (args as { campaign_id: unknown }).campaign_id === 'number'
146 |   );
147 | }
148 | 
149 | export function isListCampaignsParams(args: unknown): args is ListCampaignsParams {
150 |   return typeof args === 'object' && args !== null;
151 | }
152 | 
153 | export function isSaveCampaignSequenceParams(args: unknown): args is SaveCampaignSequenceParams {
154 |   if (
155 |     typeof args !== 'object' ||
156 |     args === null ||
157 |     !('campaign_id' in args) ||
158 |     typeof (args as { campaign_id: unknown }).campaign_id !== 'number' ||
159 |     !('sequence' in args) ||
160 |     !Array.isArray((args as { sequence: unknown }).sequence)
161 |   ) {
162 |     return false;
163 |   }
164 | 
165 |   const sequence = (args as { sequence: unknown[] }).sequence;
166 |   return sequence.every(isValidSequenceItem);
167 | }
168 | 
169 | // New type guards for the remaining campaign management endpoints
170 | export function isGetCampaignsByLeadParams(args: unknown): args is GetCampaignsByLeadParams {
171 |   return (
172 |     typeof args === 'object' &&
173 |     args !== null &&
174 |     'lead_id' in args &&
175 |     typeof (args as { lead_id: unknown }).lead_id === 'number'
176 |   );
177 | }
178 | 
179 | export function isExportCampaignLeadsParams(args: unknown): args is ExportCampaignLeadsParams {
180 |   return (
181 |     typeof args === 'object' &&
182 |     args !== null &&
183 |     'campaign_id' in args &&
184 |     typeof (args as { campaign_id: unknown }).campaign_id === 'number'
185 |   );
186 | }
187 | 
188 | export function isDeleteCampaignParams(args: unknown): args is DeleteCampaignParams {
189 |   return (
190 |     typeof args === 'object' &&
191 |     args !== null &&
192 |     'campaign_id' in args &&
193 |     typeof (args as { campaign_id: unknown }).campaign_id === 'number'
194 |   );
195 | }
196 | 
197 | export function isGetCampaignAnalyticsByDateParams(args: unknown): args is GetCampaignAnalyticsByDateParams {
198 |   return (
199 |     typeof args === 'object' &&
200 |     args !== null &&
201 |     'campaign_id' in args &&
202 |     typeof (args as { campaign_id: unknown }).campaign_id === 'number' &&
203 |     'start_date' in args &&
204 |     typeof (args as { start_date: unknown }).start_date === 'string' &&
205 |     'end_date' in args &&
206 |     typeof (args as { end_date: unknown }).end_date === 'string'
207 |   );
208 | }
209 | 
210 | export function isGetCampaignSequenceAnalyticsParams(args: unknown): args is GetCampaignSequenceAnalyticsParams {
211 |   return (
212 |     typeof args === 'object' &&
213 |     args !== null &&
214 |     'campaign_id' in args &&
215 |     typeof (args as { campaign_id: unknown }).campaign_id === 'number' &&
216 |     'start_date' in args &&
217 |     typeof (args as { start_date: unknown }).start_date === 'string' &&
218 |     'end_date' in args &&
219 |     typeof (args as { end_date: unknown }).end_date === 'string'
220 |   );
221 | }
222 | 
223 | function isValidSequenceItem(item: unknown): boolean {
224 |   return (
225 |     typeof item === 'object' &&
226 |     item !== null &&
227 |     'seq_number' in item &&
228 |     typeof (item as { seq_number: unknown }).seq_number === 'number' &&
229 |     'seq_delay_details' in item &&
230 |     typeof (item as { seq_delay_details: unknown }).seq_delay_details === 'object' &&
231 |     (item as { seq_delay_details: unknown }).seq_delay_details !== null &&
232 |     'delay_in_days' in (item as { seq_delay_details: { delay_in_days: unknown } }).seq_delay_details &&
233 |     typeof (item as { seq_delay_details: { delay_in_days: unknown } }).seq_delay_details.delay_in_days === 'number' &&
234 |     'variant_distribution_type' in item &&
235 |     typeof (item as { variant_distribution_type: unknown }).variant_distribution_type === 'string' &&
236 |     'seq_variants' in item &&
237 |     Array.isArray((item as { seq_variants: unknown[] }).seq_variants) &&
238 |     (item as { seq_variants: unknown[] }).seq_variants.every(
239 |       (variant) =>
240 |         typeof variant === 'object' &&
241 |         variant !== null &&
242 |         'subject' in variant &&
243 |         typeof (variant as { subject: unknown }).subject === 'string' &&
244 |         'email_body' in variant &&
245 |         typeof (variant as { email_body: unknown }).email_body === 'string' &&
246 |         'variant_label' in variant &&
247 |         typeof (variant as { variant_label: unknown }).variant_label === 'string'
248 |     )
249 |   );
250 | } 
```

--------------------------------------------------------------------------------
/src/tools/statistics.ts:
--------------------------------------------------------------------------------

```typescript
  1 | import { CategoryTool, ToolCategory } from '../types/common.js';
  2 | 
  3 | // Campaign Statistics Tools
  4 | export const CAMPAIGN_STATISTICS_TOOL: CategoryTool = {
  5 |   name: 'smartlead_get_campaign_statistics',
  6 |   description: 'Fetch campaign statistics using the campaign\'s ID.',
  7 |   category: ToolCategory.CAMPAIGN_STATISTICS,
  8 |   inputSchema: {
  9 |     type: 'object',
 10 |     properties: {
 11 |       campaign_id: {
 12 |         type: 'number',
 13 |         description: 'ID of the campaign to fetch statistics for',
 14 |       },
 15 |       offset: {
 16 |         type: 'number',
 17 |         description: 'Offset for pagination',
 18 |       },
 19 |       limit: {
 20 |         type: 'number',
 21 |         description: 'Maximum number of statistics to return',
 22 |       },
 23 |       email_sequence_number: {
 24 |         type: 'string',
 25 |         description: 'Email sequence number to filter by (e.g., "1,2,3,4")',
 26 |       },
 27 |       email_status: {
 28 |         type: 'string',
 29 |         description: 'Email status to filter by (e.g., "opened", "clicked", "replied", "unsubscribed", "bounced")',
 30 |       },
 31 |       sent_time_start_date: {
 32 |         type: 'string',
 33 |         description: 'Filter by sent time greater than this date (e.g., "2023-10-16 10:33:02.000Z")',
 34 |       },
 35 |       sent_time_end_date: {
 36 |         type: 'string',
 37 |         description: 'Filter by sent time less than this date (e.g., "2023-10-16 10:33:02.000Z")',
 38 |       },
 39 |     },
 40 |     required: ['campaign_id'],
 41 |   },
 42 | };
 43 | 
 44 | export const CAMPAIGN_STATISTICS_BY_DATE_TOOL: CategoryTool = {
 45 |   name: 'smartlead_get_campaign_statistics_by_date',
 46 |   description: 'Fetch campaign statistics for a specific date range.',
 47 |   category: ToolCategory.CAMPAIGN_STATISTICS,
 48 |   inputSchema: {
 49 |     type: 'object',
 50 |     properties: {
 51 |       campaign_id: {
 52 |         type: 'number',
 53 |         description: 'ID of the campaign to fetch statistics for',
 54 |       },
 55 |       start_date: {
 56 |         type: 'string',
 57 |         description: 'Start date in YYYY-MM-DD format',
 58 |       },
 59 |       end_date: {
 60 |         type: 'string',
 61 |         description: 'End date in YYYY-MM-DD format',
 62 |       },
 63 |     },
 64 |     required: ['campaign_id', 'start_date', 'end_date'],
 65 |   },
 66 | };
 67 | 
 68 | export const WARMUP_STATS_BY_EMAIL_TOOL: CategoryTool = {
 69 |   name: 'smartlead_get_warmup_stats_by_email',
 70 |   description: 'Fetch warmup stats for the last 7 days for a specific email account.',
 71 |   category: ToolCategory.CAMPAIGN_STATISTICS,
 72 |   inputSchema: {
 73 |     type: 'object',
 74 |     properties: {
 75 |       email_account_id: {
 76 |         type: 'number',
 77 |         description: 'ID of the email account to fetch warmup stats for',
 78 |       },
 79 |     },
 80 |     required: ['email_account_id'],
 81 |   },
 82 | };
 83 | 
 84 | export const CAMPAIGN_TOP_LEVEL_ANALYTICS_TOOL: CategoryTool = {
 85 |   name: 'smartlead_get_campaign_top_level_analytics',
 86 |   description: 'Fetch top level analytics for a campaign.',
 87 |   category: ToolCategory.CAMPAIGN_STATISTICS,
 88 |   inputSchema: {
 89 |     type: 'object',
 90 |     properties: {
 91 |       campaign_id: {
 92 |         type: 'number',
 93 |         description: 'ID of the campaign to fetch analytics for',
 94 |       },
 95 |     },
 96 |     required: ['campaign_id'],
 97 |   },
 98 | };
 99 | 
100 | export const CAMPAIGN_TOP_LEVEL_ANALYTICS_BY_DATE_TOOL: CategoryTool = {
101 |   name: 'smartlead_get_campaign_top_level_analytics_by_date',
102 |   description: 'Fetch campaign top level analytics for a specific date range.',
103 |   category: ToolCategory.CAMPAIGN_STATISTICS,
104 |   inputSchema: {
105 |     type: 'object',
106 |     properties: {
107 |       campaign_id: {
108 |         type: 'number',
109 |         description: 'ID of the campaign to fetch analytics for',
110 |       },
111 |       start_date: {
112 |         type: 'string',
113 |         description: 'Start date in YYYY-MM-DD format',
114 |       },
115 |       end_date: {
116 |         type: 'string',
117 |         description: 'End date in YYYY-MM-DD format',
118 |       },
119 |     },
120 |     required: ['campaign_id', 'start_date', 'end_date'],
121 |   },
122 | };
123 | 
124 | export const CAMPAIGN_LEAD_STATISTICS_TOOL: CategoryTool = {
125 |   name: 'smartlead_get_campaign_lead_statistics',
126 |   description: 'Fetch lead statistics for a campaign.',
127 |   category: ToolCategory.CAMPAIGN_STATISTICS,
128 |   inputSchema: {
129 |     type: 'object',
130 |     properties: {
131 |       campaign_id: {
132 |         type: 'number',
133 |         description: 'ID of the campaign to fetch lead statistics for',
134 |       },
135 |       limit: {
136 |         type: 'number',
137 |         description: 'Maximum number of leads to return (max 100)',
138 |       },
139 |       created_at_gt: {
140 |         type: 'string',
141 |         description: 'Filter by leads created after this date (YYYY-MM-DD format)',
142 |       },
143 |       event_time_gt: {
144 |         type: 'string',
145 |         description: 'Filter by events after this date (YYYY-MM-DD format)',
146 |       },
147 |       offset: {
148 |         type: 'number',
149 |         description: 'Offset for pagination',
150 |       },
151 |     },
152 |     required: ['campaign_id'],
153 |   },
154 | };
155 | 
156 | export const CAMPAIGN_MAILBOX_STATISTICS_TOOL: CategoryTool = {
157 |   name: 'smartlead_get_campaign_mailbox_statistics',
158 |   description: 'Fetch mailbox statistics for a campaign.',
159 |   category: ToolCategory.CAMPAIGN_STATISTICS,
160 |   inputSchema: {
161 |     type: 'object',
162 |     properties: {
163 |       campaign_id: {
164 |         type: 'number',
165 |         description: 'ID of the campaign to fetch mailbox statistics for',
166 |       },
167 |       client_id: {
168 |         type: 'string',
169 |         description: 'Client ID if the campaign is client-specific',
170 |       },
171 |       offset: {
172 |         type: 'number',
173 |         description: 'Offset for pagination',
174 |       },
175 |       limit: {
176 |         type: 'number',
177 |         description: 'Maximum number of results to return (min 1, max 20)',
178 |       },
179 |       start_date: {
180 |         type: 'string',
181 |         description: 'Start date (must be used with end_date)',
182 |       },
183 |       end_date: {
184 |         type: 'string',
185 |         description: 'End date (must be used with start_date)',
186 |       },
187 |       timezone: {
188 |         type: 'string',
189 |         description: 'Timezone for the data (e.g., "America/Los_Angeles")',
190 |       },
191 |     },
192 |     required: ['campaign_id'],
193 |   },
194 | };
195 | 
196 | // Add this new tool for downloading campaign data with tracking
197 | export const DOWNLOAD_CAMPAIGN_DATA_TOOL: CategoryTool = {
198 |   name: 'smartlead_download_campaign_data',
199 |   description: 'Download campaign data and track the download for analytics.',
200 |   category: ToolCategory.CAMPAIGN_STATISTICS,
201 |   inputSchema: {
202 |     type: 'object',
203 |     properties: {
204 |       campaign_id: {
205 |         type: 'number',
206 |         description: 'ID of the campaign to download data for',
207 |       },
208 |       download_type: {
209 |         type: 'string',
210 |         enum: ['analytics', 'leads', 'sequence', 'full_export'],
211 |         description: 'Type of data to download',
212 |       },
213 |       format: {
214 |         type: 'string',
215 |         enum: ['json', 'csv'],
216 |         description: 'Format of the downloaded data',
217 |       },
218 |       user_id: {
219 |         type: 'string',
220 |         description: 'Optional user identifier for tracking downloads',
221 |       },
222 |     },
223 |     required: ['campaign_id', 'download_type', 'format'],
224 |   },
225 | };
226 | 
227 | // Add this new tool for viewing download statistics
228 | export const VIEW_DOWNLOAD_STATISTICS_TOOL: CategoryTool = {
229 |   name: 'smartlead_view_download_statistics',
230 |   description: 'View statistics about downloaded campaign data.',
231 |   category: ToolCategory.CAMPAIGN_STATISTICS,
232 |   inputSchema: {
233 |     type: 'object',
234 |     properties: {
235 |       time_period: {
236 |         type: 'string',
237 |         enum: ['all', 'today', 'week', 'month'],
238 |         description: 'Time period to filter statistics by',
239 |       },
240 |       group_by: {
241 |         type: 'string',
242 |         enum: ['type', 'format', 'campaign', 'date'],
243 |         description: 'How to group the statistics',
244 |       },
245 |     },
246 |   },
247 | };
248 | 
249 | // Export an array of all campaign statistics tools for registration
250 | export const statisticsTools: CategoryTool[] = [
251 |   CAMPAIGN_STATISTICS_TOOL,
252 |   CAMPAIGN_STATISTICS_BY_DATE_TOOL,
253 |   WARMUP_STATS_BY_EMAIL_TOOL,
254 |   CAMPAIGN_TOP_LEVEL_ANALYTICS_TOOL,
255 |   CAMPAIGN_TOP_LEVEL_ANALYTICS_BY_DATE_TOOL,
256 |   CAMPAIGN_LEAD_STATISTICS_TOOL,
257 |   CAMPAIGN_MAILBOX_STATISTICS_TOOL,
258 |   DOWNLOAD_CAMPAIGN_DATA_TOOL,
259 |   VIEW_DOWNLOAD_STATISTICS_TOOL,
260 | ]; 
```
Page 1/3FirstPrevNextLast