icypeas_find_work_email
Retrieve professional email addresses by entering a person's first name, last name, and company or domain information. Simplify contact discovery with precision.
Instructions
Find a work email using name and company information.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| domainOrCompany | Yes | The domain or company name | |
| firstname | Yes | The first name of the person | |
| lastname | Yes | The last name of the person |
Implementation Reference
- src/index.ts:281-386 (handler)Main execution logic for the 'icypeas_find_work_email' tool. Validates input using isFindWorkEmailParams, initiates API search via '/email-search', polls results using pollForEmailSearchResults, formats response with emails and person details.case 'icypeas_find_work_email': { if (!isFindWorkEmailParams(args)) { throw new McpError( ErrorCode.InvalidParams, 'Invalid arguments for icypeas_find_work_email' ); } try { const payload = { firstname: args.firstname, lastname: args.lastname, domainOrCompany: args.domainOrCompany }; // Step 1: Initiate the email search safeLog('info', 'Initiating email search with payload: ' + JSON.stringify(payload)); const searchResponse = await withRetry<{data: EmailSearchResponse}>( async () => apiClient.post('/email-search', payload), 'initiate email search' ); if (!searchResponse.data.success || !searchResponse.data.item._id) { throw new Error('Failed to initiate email search: ' + JSON.stringify(searchResponse.data)); } const searchId = searchResponse.data.item._id; safeLog('info', `Email search initiated with ID: ${searchId}`); // Step 2: Poll for results safeLog('info', `Initiating polling for results with search ID: ${searchId}`); const searchResult = await pollForEmailSearchResults( searchId, 10, // Max 10 attempts 3000, // 3 seconds between polls 5000 // 5 seconds initial delay ); // Format the response let formattedResponse; if ( searchResult.success && searchResult.items.length > 0 && searchResult.items[0].results && searchResult.items[0].results.emails && searchResult.items[0].results.emails.length > 0 ) { // Success case with emails found formattedResponse = { success: true, person: { firstname: searchResult.items[0].results.firstname, lastname: searchResult.items[0].results.lastname, fullname: searchResult.items[0].results.fullname, gender: searchResult.items[0].results.gender }, emails: searchResult.items[0].results.emails.map(email => ({ email: email.email, certainty: email.certainty, provider: email.mxProvider })), status: searchResult.items[0].status }; } else if (searchResult.items.length > 0) { // Search completed but no emails found formattedResponse = { success: true, person: { firstname: args.firstname, lastname: args.lastname, fullname: `${args.firstname} ${args.lastname}` }, emails: [], status: searchResult.items[0].status, message: "No emails found or search still in progress" }; } else { // Something went wrong formattedResponse = { success: false, message: "Failed to retrieve email search results", rawResponse: searchResult }; } return { content: [ { type: 'text', text: JSON.stringify(formattedResponse, null, 2), }, ], isError: false, }; } catch (error) { const errorMessage = axios.isAxiosError(error) ? `API Error: ${error.response?.data?.message || error.message}` : `Error: ${error instanceof Error ? error.message : String(error)}`; return { content: [{ type: 'text', text: errorMessage }], isError: true, }; } }
- src/index.ts:18-39 (schema)Tool schema definition including name, description, and inputSchema with required properties: firstname, lastname, domainOrCompany.const FIND_WORK_EMAIL_TOOL: Tool = { name: 'icypeas_find_work_email', description: 'Find a work email using name and company information.', inputSchema: { type: 'object', properties: { firstname: { type: 'string', description: 'The first name of the person', }, lastname: { type: 'string', description: 'The last name of the person', }, domainOrCompany: { type: 'string', description: 'The domain or company name', } }, required: ['firstname', 'lastname', 'domainOrCompany'], }, };
- src/index.ts:259-263 (registration)Registration of the tool in the MCP server's listTools handler.server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: [ FIND_WORK_EMAIL_TOOL, ], }));
- src/index.ts:92-107 (helper)Type guard function to validate input parameters for the tool handler.function isFindWorkEmailParams(args: unknown): args is FindWorkEmailParams { if ( typeof args !== 'object' || args === null || !('firstname' in args) || typeof (args as { firstname: unknown }).firstname !== 'string' || !('lastname' in args) || typeof (args as { lastname: unknown }).lastname !== 'string' || !('domainOrCompany' in args) || typeof (args as { domainOrCompany: unknown }).domainOrCompany !== 'string' ) { return false; } return true; }
- src/index.ts:183-223 (helper)Polling helper function to wait for email search results from the API.async function pollForEmailSearchResults( searchId: string, maxAttempts = 10, intervalMs = 3000, initialDelayMs = 5000 ): Promise<EmailSearchResult> { // Initial delay before first poll safeLog('info', `Waiting initial delay of ${initialDelayMs}ms before polling`); await delay(initialDelayMs); let attempts = 0; while (attempts < maxAttempts) { attempts++; safeLog('info', `Polling attempt ${attempts}/${maxAttempts}`); const response = await apiClient.post<EmailSearchResult>( '/bulk-single-searchs/read', { id: searchId } ); // Check if search is complete if ( response.data.success && response.data.items.length > 0 && !['NONE', 'SCHEDULED', 'IN_PROGRESS'].includes(response.data.items[0].status) ) { return response.data; } // If we've reached max attempts, return the current result if (attempts >= maxAttempts) { return response.data; } // Wait before trying again await delay(intervalMs); } throw new Error('Max polling attempts reached'); }