Skip to main content
Glama
mcp-handlers.tsβ€’7.98 kB
/** * Instantly MCP Server - MCP Protocol Handlers * * This module contains the MCP protocol request handlers that were previously * in the main index.ts file. These handlers implement the MCP protocol for: * - Initialize: Server initialization and capability negotiation * - ListTools: Returns available tools to MCP clients * - CallTool: Routes tool calls to the tool executor * * All handlers are extracted exactly as-is from the original implementation * to maintain 100% backward compatibility. */ import { Server } from '@modelcontextprotocol/sdk/server/index.js'; import { InitializeRequestSchema, ListToolsRequestSchema, CallToolRequestSchema, ErrorCode, McpError, } from '@modelcontextprotocol/sdk/types.js'; import { TOOLS_DEFINITION } from '../tools/index.js'; import { executeToolDirectly } from './tool-executor.js'; import { handleInstantlyError } from '../error-handler.js'; import { paginateTools, getPaginationInfo, getToolPaginationConfig } from '../config/tool-pagination.js'; /** * Load Instantly.ai icons for MCP protocol * * Icons are displayed in MCP clients like Claude Desktop and Claude.ai * to provide visual branding for the server. */ function loadInstantlyIcons(): Array<{src: string, mimeType: string, sizes: string[]}> { const INSTANTLY_ICONS = [ { src: 'https://cdn.prod.website-files.com/63860c8c65e7bef4a1eeebeb/63f62e4f7dc7e3426e9b7874_cleaned_rounded_favicon.png', mimeType: 'image/png', sizes: ['any'] } ]; return INSTANTLY_ICONS; } /** * Register all MCP protocol handlers on the server * * This function is called from the main index.ts to set up the MCP protocol * handlers. It registers three core handlers: * 1. Initialize - Server initialization and capability negotiation * 2. ListTools - Returns available tools to MCP clients * 3. CallTool - Routes tool calls to the tool executor * * @param server - The MCP server instance * @param apiKey - Optional API key for stdio mode (from environment variable) */ export function registerMcpHandlers(server: Server, apiKey?: string): void { // Initialize handler - provides server info with icon for remote MCP connectors server.setRequestHandler(InitializeRequestSchema, async (request) => { const clientName = request.params?.clientInfo?.name || 'unknown'; console.error('[Instantly MCP] πŸ”§ Initialize request received from:', clientName); // Update client detection manager with client info try { const { globalClientManager } = await import('../client-detection.js'); globalClientManager.updateClientInfo( request.params?.clientInfo, undefined // User agent not available in stdio mode ); console.error('[Instantly MCP] πŸ“Š Client detection updated'); } catch (error) { console.error('[Instantly MCP] ⚠️ Client detection unavailable:', error); } // Ensure icons are loaded synchronously for Claude Desktop compatibility const icons = loadInstantlyIcons(); console.error('[Instantly MCP] 🎨 Icons loaded:', icons.length > 0 ? `βœ… ${icons.length} icon(s)` : '❌ Missing'); // Enhanced initialization response matching HTTP transport // Updated to 2025-06-18 for latest MCP protocol features const initResponse = { protocolVersion: '2025-06-18', capabilities: { tools: { listChanged: true, }, resources: { subscribe: false, listChanged: false, }, prompts: { listChanged: false, }, }, serverInfo: { name: 'instantly-mcp', version: '1.2.0', icons: icons, description: 'Instantly.ai email automation and campaign management tools', }, instructions: 'Use these tools to manage Instantly.ai email campaigns, accounts, and automation workflows.', }; console.error('[Instantly MCP] βœ… Initialize response prepared'); return initResponse; }); // List tools handler with pagination support (MCP 2025-06-18) server.setRequestHandler(ListToolsRequestSchema, async (request) => { const cursor = request.params?.cursor; const config = getToolPaginationConfig(); // Get pagination info for logging const paginationInfo = getPaginationInfo(TOOLS_DEFINITION.length, cursor, config); console.error(`[Instantly MCP] πŸ“‹ Listing tools (page ${paginationInfo.currentPage}/${paginationInfo.totalPages}, ` + `showing ${paginationInfo.startIndex + 1}-${paginationInfo.endIndex} of ${paginationInfo.totalTools})...`); // Paginate tools for context window efficiency const { tools, nextCursor } = paginateTools(TOOLS_DEFINITION, cursor, config); if (nextCursor) { console.error(`[Instantly MCP] πŸ“„ More tools available - nextCursor provided for lazy loading`); } else { console.error(`[Instantly MCP] βœ… All tools returned (pagination ${config.enabled ? 'enabled' : 'disabled'})`); } return { tools, ...(nextCursor && { nextCursor }) }; }); // Call tool handler - now supports per-request API keys server.setRequestHandler(CallToolRequestSchema, async (request, extra) => { const { name, arguments: args } = request.params; console.error(`[Instantly MCP] πŸ”§ Tool called via MCP: ${name}`); console.error(`[Instantly MCP] πŸ” Debug - Main handler params:`, JSON.stringify(request.params, null, 2)); console.error(`[Instantly MCP] πŸ” Debug - Extra parameter:`, JSON.stringify(extra, null, 2)); // Extract API key from multiple sources let extractedApiKey: string | undefined; // Method 1: Check if API key is provided in args (from HTTP transport) if (args && typeof args === 'object' && 'apiKey' in args) { extractedApiKey = (args as any).apiKey; // Remove apiKey from args to avoid passing it to tool functions delete (args as any).apiKey; console.error(`[Instantly MCP] πŸ”‘ API key extracted from args`); } // Method 2: Check if API key is in extra context (from HTTP transport headers) if (!extractedApiKey && extra && typeof extra === 'object') { const extraObj = extra as any; console.error(`[Instantly MCP] πŸ” Debug - extraObj structure:`, Object.keys(extraObj)); // Try requestInfo.headers first (SDK standard) if (extraObj.requestInfo && extraObj.requestInfo.headers) { console.error(`[Instantly MCP] πŸ” Debug - requestInfo.headers keys:`, Object.keys(extraObj.requestInfo.headers)); if (extraObj.requestInfo.headers['x-instantly-api-key']) { extractedApiKey = extraObj.requestInfo.headers['x-instantly-api-key']; console.error(`[Instantly MCP] πŸ”‘ API key extracted from requestInfo.headers`); } } // Fallback to direct headers property if (!extractedApiKey && extraObj.headers && extraObj.headers['x-instantly-api-key']) { extractedApiKey = extraObj.headers['x-instantly-api-key']; console.error(`[Instantly MCP] πŸ”‘ API key extracted from direct headers`); } } // Method 3: Fall back to environment variable for stdio transport if (!extractedApiKey) { extractedApiKey = apiKey; console.error(`[Instantly MCP] πŸ”‘ API key from environment variable`); } try { // Use the shared tool execution function return await executeToolDirectly(name, args, extractedApiKey); } catch (error) { console.error(`[Instantly MCP] ❌ Tool execution error:`, error); if (error instanceof McpError) { throw error; } // Handle the error and re-throw as McpError try { handleInstantlyError(error, name); } catch (handledError: any) { throw new McpError(ErrorCode.InternalError, handledError.message || String(error)); } } }); console.error('[Instantly MCP] βœ… MCP protocol handlers registered successfully'); }

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/bcharleson/Instantly-MCP'

If you have feedback or need assistance with the MCP directory API, please join our Discord server