smartlead-mcp-by-leadmagic
Version:
π The Premier Model Context Protocol Server for SmartLead's Cold Email Automation Platform - Complete API coverage with 116+ tools for campaign management, lead tracking, smart delivery, and analytics. Beautiful purple-gradient installer, zero-config set
378 lines β’ 23.3 kB
JavaScript
#!/usr/bin/env node
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
/**
* π SmartLead MCP Server - Beautiful Interactive Installer
*
* The most beautiful, user-friendly MCP installer ever created!
* Features stunning purple gradients, smooth animations, and zero-config setup.
*
* @author LeadMagic Team
* @version 1.6.1
*/
import fs from 'fs';
import { Box, Text, useApp, useInput } from 'ink';
import BigText from 'ink-big-text';
import Gradient from 'ink-gradient';
import Link from 'ink-link';
import SelectInput from 'ink-select-input';
import Spinner from 'ink-spinner';
import TextInput from 'ink-text-input';
import os from 'os';
import path from 'path';
import { useEffect, useState } from 'react';
import { SmartLeadClient, SmartLeadError } from './client/index.js';
// ===== UTILITIES =====
const getConfigPaths = () => {
const platform = process.platform;
const home = os.homedir();
const paths = {
darwin: {
claude: path.join(home, 'Library/Application Support/Claude/claude_desktop_config.json'),
cursor: path.join(home, 'Library/Application Support/Cursor/User/settings.json'),
windsurf: path.join(home, 'Library/Application Support/Windsurf/User/settings.json'),
continue: path.join(home, '.continue/config.json'),
vscode: path.join(home, 'Library/Application Support/Code/User/settings.json'),
zed: path.join(home, '.config/zed/settings.json'),
},
linux: {
claude: path.join(home, '.config/claude/claude_desktop_config.json'),
cursor: path.join(home, '.config/Cursor/User/settings.json'),
windsurf: path.join(home, '.config/Windsurf/User/settings.json'),
continue: path.join(home, '.continue/config.json'),
vscode: path.join(home, '.config/Code/User/settings.json'),
zed: path.join(home, '.config/zed/settings.json'),
},
win32: {
claude: path.join(home, 'AppData/Roaming/Claude/claude_desktop_config.json'),
cursor: path.join(home, 'AppData/Roaming/Cursor/User/settings.json'),
windsurf: path.join(home, 'AppData/Roaming/Windsurf/User/settings.json'),
continue: path.join(home, '.continue/config.json'),
vscode: path.join(home, 'AppData/Roaming/Code/User/settings.json'),
zed: path.join(home, 'AppData/Roaming/Zed/settings.json'),
},
};
return paths[platform] || paths.linux;
};
const detectClients = () => {
const configPaths = getConfigPaths();
return [
{
id: 'claude',
name: 'Claude Desktop',
emoji: 'π€',
description: 'Anthropic Claude Desktop',
configPath: configPaths.claude,
detected: fs.existsSync(configPaths.claude),
},
{
id: 'cursor',
name: 'Cursor',
emoji: 'π―',
description: 'AI-powered code editor',
configPath: configPaths.cursor,
detected: fs.existsSync(configPaths.cursor),
},
{
id: 'windsurf',
name: 'Windsurf',
emoji: 'π',
description: 'Codeium AI IDE',
configPath: configPaths.windsurf,
detected: fs.existsSync(configPaths.windsurf),
},
{
id: 'continue',
name: 'Continue.dev',
emoji: 'π',
description: 'Open source coding assistant',
configPath: configPaths.continue,
detected: fs.existsSync(configPaths.continue),
},
{
id: 'vscode',
name: 'VS Code',
emoji: 'π»',
description: 'Visual Studio Code',
configPath: configPaths.vscode,
detected: fs.existsSync(configPaths.vscode),
},
{
id: 'zed',
name: 'Zed',
emoji: 'β‘',
description: 'High-performance editor',
configPath: configPaths.zed,
detected: fs.existsSync(configPaths.zed),
},
];
};
const ensureConfigDir = (configPath) => {
const configDir = path.dirname(configPath);
if (!fs.existsSync(configDir)) {
fs.mkdirSync(configDir, { recursive: true });
}
};
const readConfigSafely = (configPath) => {
try {
if (fs.existsSync(configPath)) {
const content = fs.readFileSync(configPath, 'utf8');
return JSON.parse(content);
}
}
catch (error) {
console.warn(`Warning: Could not read config from ${configPath}`);
}
return {};
};
const smartleadConfig = (apiKey) => ({
command: 'npx',
args: ['smartlead-mcp-by-leadmagic'],
env: {
SMARTLEAD_API_KEY: apiKey,
SMARTLEAD_ADVANCED_TOOLS: 'true',
SMARTLEAD_ADMIN_TOOLS: 'true',
},
});
const installForClient = (client, apiKey) => {
try {
ensureConfigDir(client.configPath);
const config = readConfigSafely(client.configPath);
const serverConfig = smartleadConfig(apiKey);
switch (client.id) {
case 'claude':
case 'windsurf':
case 'zed':
config.mcpServers = { ...config.mcpServers, smartlead: serverConfig };
break;
case 'cursor':
case 'vscode':
config['cline.mcpServers'] = { ...config['cline.mcpServers'], smartlead: serverConfig };
break;
case 'continue': {
if (!config.mcpServers)
config.mcpServers = [];
const existingIndex = config.mcpServers.findIndex((s) => s.name === 'smartlead');
const serverWithName = { name: 'smartlead', ...serverConfig };
if (existingIndex >= 0) {
config.mcpServers[existingIndex] = serverWithName;
}
else {
config.mcpServers.push(serverWithName);
}
break;
}
}
fs.writeFileSync(client.configPath, JSON.stringify(config, null, 2));
return {
client: client.name,
success: true,
message: 'Successfully configured',
configPath: client.configPath,
};
}
catch (error) {
return {
client: client.name,
success: false,
message: error instanceof Error ? error.message : 'Configuration failed',
};
}
};
// ===== COMPONENTS =====
const Logo = () => (_jsxs(Box, { flexDirection: "column", alignItems: "center", marginBottom: 2, children: [_jsx(Gradient, { name: "mind", children: _jsx(BigText, { text: "SmartLead", font: "block" }) }), _jsx(Box, { marginTop: -1, children: _jsx(Gradient, { name: "teen", children: _jsx(Text, { bold: true, children: "\uD83D\uDC9C MCP SERVER INSTALLER \uD83D\uDC9C" }) }) }), _jsx(Text, { color: "magenta", dimColor: true, children: "\u2728 by LeadMagic \u2022 Official SmartLead Partner \u2728" })] }));
const WelcomeScreen = ({ onNext }) => {
const [dots, setDots] = useState('');
useEffect(() => {
const interval = setInterval(() => {
setDots((prev) => (prev.length >= 3 ? '' : prev + '.'));
}, 500);
return () => clearInterval(interval);
}, []);
useInput((input, key) => {
if (key.return || input === ' ') {
onNext();
}
});
return (_jsxs(Box, { flexDirection: "column", padding: 2, borderStyle: "round", borderColor: "magenta", children: [_jsx(Logo, {}), _jsxs(Box, { flexDirection: "column", alignItems: "center", marginBottom: 2, children: [_jsx(Gradient, { name: "passion", children: _jsx(Text, { bold: true, children: "\uD83D\uDE80 The Complete Cold Email Automation Suite \uD83D\uDE80" }) }), _jsxs(Text, { color: "white", children: ["\uD83C\uDFAF", ' ', _jsx(Text, { color: "cyan", bold: true, children: "116+ API Tools" }), ' ', "\u2022 \uD83D\uDEE1\uFE0F", ' ', _jsx(Text, { color: "green", bold: true, children: "Production Ready" }), ' ', "\u2022 \uD83C\uDFA8", ' ', _jsx(Text, { color: "yellow", bold: true, children: "Zero Config" })] }), _jsxs(Text, { color: "white", children: ["\uD83D\uDD27", ' ', _jsx(Text, { color: "magenta", bold: true, children: "TypeScript Native" }), ' ', "\u2022 \uD83C\uDF0D", ' ', _jsx(Text, { color: "cyan", bold: true, children: "Cross Platform" }), ' ', "\u2022 \u26A1", ' ', _jsx(Text, { color: "blue", bold: true, children: "Instant Setup" })] })] }), _jsxs(Box, { flexDirection: "column", alignItems: "center", marginBottom: 2, children: [_jsx(Text, { color: "gray", dimColor: true, children: "\uD83D\uDD17 Compatible with:" }), _jsxs(Text, { color: "white", children: [_jsx(Text, { color: "cyan", children: "Claude" }), " \u2022 ", _jsx(Text, { color: "green", children: "Cursor" }), " \u2022", _jsx(Text, { color: "yellow", children: "Windsurf" }), " \u2022 ", _jsx(Text, { color: "magenta", children: "Continue" }), " \u2022", _jsx(Text, { color: "blue", children: "VS Code" }), " \u2022 ", _jsx(Text, { color: "red", children: "Zed" })] })] }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "blue", children: [_jsx(Spinner, { type: "dots" }), " Ready to revolutionize your cold email game", dots] }) }), _jsx(Box, { borderStyle: "double", borderColor: "green", padding: 1, children: _jsx(Gradient, { name: "fruit", children: _jsx(Text, { bold: true, children: "\u25B6\uFE0F Press ENTER or SPACE to begin the magic!" }) }) })] }));
};
const ApiKeyScreen = ({ onNext, onBack }) => {
const [input, setInput] = useState('');
const [error, setError] = useState('');
const [isValidating, setIsValidating] = useState(false);
const validateApiKey = async (key) => {
setIsValidating(true);
setError('');
try {
const client = new SmartLeadClient({ apiKey: key });
await client.testConnection();
onNext(key);
}
catch (err) {
if (err instanceof SmartLeadError) {
setError(`SmartLead API Error: ${err.message}`);
}
else {
setError('Invalid API key or connection failed');
}
}
finally {
setIsValidating(false);
}
};
const handleSubmit = () => {
if (!input || input.length < 10) {
setError('Please enter a valid SmartLead API key (minimum 10 characters)');
}
else {
validateApiKey(input.trim());
}
};
useInput((inputChar, key) => {
if (key.escape) {
onBack();
}
else if (key.return && !isValidating) {
handleSubmit();
}
});
return (_jsxs(Box, { flexDirection: "column", padding: 2, borderStyle: "round", borderColor: "cyan", children: [_jsx(Logo, {}), _jsx(Box, { borderStyle: "single", borderColor: "red", padding: 1, marginBottom: 1, children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Gradient, { name: "morning", children: _jsx(Text, { bold: true, children: "\uD83D\uDD11 Step 1: Enter Your SmartLead API Key (REQUIRED)" }) }), _jsx(Text, { color: "red", children: "\u26A0\uFE0F API key validation is MANDATORY for security!" })] }) }), _jsx(Box, { borderStyle: "single", borderColor: "cyan", padding: 1, marginBottom: 1, children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Gradient, { name: "atlas", children: _jsx(Text, { bold: true, children: "\uD83D\uDCCB How to get your API key:" }) }), _jsxs(Text, { children: ["1. Visit: ", _jsx(Link, { url: "https://app.smartlead.ai", children: "https://app.smartlead.ai" })] }), _jsx(Text, { children: "2. Go to Settings \u2192 API Keys" }), _jsx(Text, { children: "3. Generate a new API key" }), _jsx(Text, { children: "4. Copy and paste it below" })] }) }), _jsx(Box, { borderStyle: "single", borderColor: "green", padding: 1, marginBottom: 1, children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Gradient, { name: "teen", children: _jsx(Text, { bold: true, children: "Enter your API key:" }) }), _jsx(TextInput, { value: input, onChange: (value) => {
setInput(value);
if (error)
setError('');
}, onSubmit: handleSubmit, placeholder: "Paste your SmartLead API key here...", mask: "\u2022" }), input.length > 0 && input.length < 10 && (_jsx(Text, { color: "yellow", dimColor: true, children: "Need at least 10 characters..." })), input.length >= 10 && _jsx(Text, { color: "green", children: "\u2705 Key format looks good!" })] }) }), error && (_jsx(Box, { borderStyle: "single", borderColor: "red", padding: 1, marginBottom: 1, children: _jsxs(Text, { color: "red", children: ["\u274C ", error] }) })), isValidating && (_jsx(Box, { borderStyle: "single", borderColor: "blue", padding: 1, marginBottom: 1, children: _jsxs(Text, { color: "blue", children: [_jsx(Spinner, { type: "dots" }), " Validating with SmartLead API..."] }) })), _jsx(Box, { borderStyle: "single", borderColor: "gray", padding: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "Press ENTER to validate \u2022 ESC to go back" }) })] }));
};
const ClientSelectionScreen = ({ onNext, onBack }) => {
const [clients] = useState(detectClients());
const [selectedClients, setSelectedClients] = useState([]);
const items = [
{ label: 'π All Detected Clients (Recommended)', value: 'all' },
...clients.map((client) => ({
label: `${client.emoji} ${client.name} ${client.detected ? 'β
(detected)' : 'π± (not found)'}`,
value: client.id,
})),
{ label: 'β
Continue with selected clients', value: 'continue' },
];
const handleSelect = (item) => {
if (item.value === 'all') {
const detectedClients = clients.filter((c) => c.detected);
setSelectedClients(detectedClients);
}
else if (item.value === 'continue') {
if (selectedClients.length === 0) {
const detectedClients = clients.filter((c) => c.detected);
if (detectedClients.length > 0) {
onNext(detectedClients);
}
}
else {
onNext(selectedClients);
}
}
else {
const client = clients.find((c) => c.id === item.value);
if (client) {
setSelectedClients((prev) => prev.includes(client) ? prev.filter((c) => c.id !== client.id) : [...prev, client]);
}
}
};
useInput((input, key) => {
if (key.escape) {
onBack();
}
});
return (_jsxs(Box, { flexDirection: "column", padding: 2, borderStyle: "round", borderColor: "yellow", children: [_jsx(Logo, {}), _jsx(Box, { borderStyle: "single", borderColor: "yellow", padding: 1, marginBottom: 1, children: _jsx(Gradient, { name: "passion", children: _jsx(Text, { bold: true, children: "\uD83C\uDFAF Step 2: Select Your AI Coding Tools" }) }) }), _jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: "cyan", children: ["Selected: ", selectedClients.map((c) => c.name).join(', ') || 'None (will auto-detect)'] }) }), _jsx(SelectInput, { items: items, onSelect: handleSelect }), _jsx(Box, { borderStyle: "single", borderColor: "gray", padding: 1, marginTop: 1, children: _jsx(Text, { color: "gray", dimColor: true, children: "Use \u2191\u2193 to navigate \u2022 ENTER to select \u2022 ESC to go back" }) })] }));
};
const InstallationScreen = ({ apiKey, clients, onComplete, onError }) => {
const [currentClient, setCurrentClient] = useState(0);
const [results, setResults] = useState([]);
useEffect(() => {
const install = async () => {
const installResults = [];
for (let i = 0; i < clients.length; i++) {
setCurrentClient(i);
const client = clients[i];
try {
// Add realistic delay for better UX
await new Promise((resolve) => setTimeout(resolve, 1500));
const result = installForClient(client, apiKey);
installResults.push(result);
setResults([...installResults]);
}
catch (error) {
const errorResult = {
client: client.name,
success: false,
message: error instanceof Error ? error.message : 'Unknown error',
};
installResults.push(errorResult);
setResults([...installResults]);
}
}
onComplete(installResults);
};
install();
}, [apiKey, clients, onComplete]);
const progress = Math.round(((currentClient + 1) / clients.length) * 100);
return (_jsxs(Box, { flexDirection: "column", padding: 2, borderStyle: "round", borderColor: "green", children: [_jsx(Logo, {}), _jsx(Box, { borderStyle: "single", borderColor: "green", padding: 1, marginBottom: 1, children: _jsx(Gradient, { name: "cristal", children: _jsx(Text, { bold: true, children: "\uD83D\uDD27 Installing SmartLead MCP Server Magic..." }) }) }), _jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: "cyan", children: ["Progress: ", progress, "% complete (", currentClient + 1, "/", clients.length, " clients)"] }), _jsx(Text, { color: "green", children: 'β'.repeat(Math.floor(progress / 5)) })] }), clients.map((client, index) => (_jsxs(Box, { marginBottom: 1, children: [_jsxs(Text, { color: index < currentClient ? 'green' : index === currentClient ? 'yellow' : 'gray', children: [index < currentClient ? 'β
' : index === currentClient ? 'β³' : 'βΈοΈ', " ", client.emoji, ' ', client.name] }), index < results.length && (_jsxs(Text, { color: results[index]?.success ? 'green' : 'red', dimColor: true, children: [' ', "- ", results[index]?.message] }))] }, client.id))), currentClient < clients.length && (_jsx(Box, { marginTop: 1, children: _jsxs(Text, { color: "blue", children: [_jsx(Spinner, { type: "dots" }), " Configuring ", clients[currentClient]?.name, "..."] }) }))] }));
};
const CompletionScreen = ({ results, onExit }) => {
const successCount = results.filter((r) => r.success).length;
const totalCount = results.length;
const [celebration, setCelebration] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setCelebration((prev) => (prev + 1) % 4);
}, 800);
return () => clearInterval(interval);
}, []);
const celebrationEmojis = ['π', 'π', 'β¨', 'π'];
useInput((input, key) => {
if (key.return || input === ' ' || key.escape) {
onExit();
}
});
return (_jsxs(Box, { flexDirection: "column", padding: 2, borderStyle: "round", borderColor: "green", children: [_jsx(Logo, {}), _jsx(Box, { borderStyle: "double", borderColor: "green", padding: 1, marginBottom: 2, children: _jsx(Gradient, { name: "cristal", children: _jsxs(Text, { bold: true, children: [celebrationEmojis[celebration], " Installation Complete! ", celebrationEmojis[celebration]] }) }) }), _jsx(Box, { marginBottom: 2, children: _jsxs(Text, { color: "green", children: ["\u2705 Successfully configured ", successCount, "/", totalCount, " clients"] }) }), results.map((result) => (_jsx(Box, { marginBottom: 1, children: _jsxs(Text, { color: result.success ? 'green' : 'red', children: [result.success ? 'β
' : 'β', " ", result.client, ": ", result.message] }) }, result.client))), _jsx(Box, { borderStyle: "single", borderColor: "cyan", padding: 1, marginTop: 2, children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Gradient, { name: "teen", children: _jsx(Text, { bold: true, children: "\uD83D\uDE80 Next Steps:" }) }), _jsx(Text, { children: "1. Restart your AI coding tool(s)" }), _jsx(Text, { children: "2. Look for \"smartlead\" in the available tools" }), _jsx(Text, { children: "3. Start automating your cold email campaigns!" }), _jsx(Text, { children: "4. Enjoy 116+ powerful SmartLead tools!" })] }) }), _jsx(Box, { borderStyle: "single", borderColor: "magenta", padding: 1, marginTop: 1, children: _jsxs(Box, { flexDirection: "column", children: [_jsx(Gradient, { name: "passion", children: _jsx(Text, { bold: true, children: "\uD83D\uDCDA Resources:" }) }), _jsxs(Text, { children: ["\u2022 GitHub:", ' ', _jsx(Link, { url: "https://github.com/LeadMagic/smartlead-mcp-server", children: "LeadMagic/smartlead-mcp-server" })] }), _jsxs(Text, { children: ["\u2022 SmartLead: ", _jsx(Link, { url: "https://smartlead.ai", children: "smartlead.ai" })] }), _jsxs(Text, { children: ["\u2022 Support: ", _jsx(Link, { url: "mailto:jesse@leadmagic.io", children: "jesse@leadmagic.io" })] })] }) }), _jsx(Box, { borderStyle: "double", borderColor: "magenta", padding: 1, marginTop: 1, children: _jsx(Gradient, { name: "fruit", children: _jsx(Text, { bold: true, children: "Press ENTER, SPACE, or ESC to finish! Thank you! \uD83D\uDC9C" }) }) })] }));
};
// ===== MAIN APP =====
const SmartLeadInstaller = () => {
const { exit } = useApp();
const [step, setStep] = useState('welcome');
const [apiKey, setApiKey] = useState('');
const [selectedClients, setSelectedClients] = useState([]);
const [results, setResults] = useState([]);
const [error, setError] = useState('');
const renderStep = () => {
switch (step) {
case 'welcome':
return _jsx(WelcomeScreen, { onNext: () => setStep('apiKey') });
case 'apiKey':
return (_jsx(ApiKeyScreen, { onNext: (key) => {
setApiKey(key);
setStep('clientSelection');
}, onBack: () => setStep('welcome') }));
case 'clientSelection':
return (_jsx(ClientSelectionScreen, { onNext: (clients) => {
setSelectedClients(clients);
setStep('installing');
}, onBack: () => setStep('apiKey') }));
case 'installing':
return (_jsx(InstallationScreen, { apiKey: apiKey, clients: selectedClients, onComplete: (results) => {
setResults(results);
setStep('complete');
}, onError: (error) => {
setError(error);
setStep('error');
} }));
case 'complete':
return _jsx(CompletionScreen, { results: results, onExit: () => exit() });
case 'error':
return (_jsxs(Box, { flexDirection: "column", padding: 2, borderStyle: "round", borderColor: "red", children: [_jsxs(Text, { color: "red", children: ["\u274C Installation Error: ", error] }), _jsx(Text, { color: "gray", children: "Press any key to exit..." })] }));
default:
return _jsx(Text, { children: "Unknown step" });
}
};
return renderStep();
};
// ===== ENTRY POINT =====
export { SmartLeadInstaller };
//# sourceMappingURL=installer.js.map