identify_leads
Analyze Instagram accounts or posts to find potential leads by filtering users based on engagement metrics, follower counts, and keyword matches in comments or bios.
Instructions
Identify potential leads based on engagement patterns
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| accountOrPostUrl | Yes | Instagram account handle or post URL to analyze | |
| criteria | No | Criteria for identifying leads |
Implementation Reference
- src/index.ts:530-671 (handler)The main handler function that implements the identify_leads tool logic. It processes either a post URL or account username, fetches relevant users (commenters or followers), applies the specified criteria (min comments, min followers, keywords), and returns potential leads.private async handleIdentifyLeads(args: IdentifyLeadsArgs) { console.error('[Tool] handleIdentifyLeads called with args:', args); const { accountOrPostUrl, criteria = {} } = args; const { minComments, minFollowers, keywords } = criteria; let targetId: string; let targetType: 'account' | 'post'; let sourceDescription: string; if (isValidPostUrl(accountOrPostUrl)) { targetType = 'post'; const mediaId = await this.getMediaIdFromUrl(accountOrPostUrl); if (!mediaId) { throw new McpError(ErrorCode.InvalidParams, 'Could not extract media ID from post URL.'); } targetId = mediaId; sourceDescription = `comments on post ${targetId}`; console.error(`[Tool] Identifying leads from post: ${targetId}`); } else if (isValidUsername(accountOrPostUrl)) { targetType = 'account'; try { const userId = await this.ig.user.getIdByUsername(accountOrPostUrl); targetId = String(userId); // Convert number userId to string for targetId sourceDescription = `followers of account ${accountOrPostUrl}`; console.error(`[Tool] Identifying leads from account followers: ${accountOrPostUrl} (ID: ${targetId})`); } catch(e: any) { if (e.name === 'IgNotFoundError') { throw new McpError(ErrorCode.InvalidParams, `Account ${accountOrPostUrl} not found.`); } throw new McpError(ErrorCode.InternalError, `Failed to get user ID for ${accountOrPostUrl}: ${e.message}`); } } else { throw new McpError(ErrorCode.InvalidParams, 'Invalid input. Provide a valid Instagram username or post URL.'); } try { let potentialLeads: any[] = []; // Use Map with string key (user PK converted to string) let usersToAnalyze: Map<string, any> = new Map(); if (targetType === 'post') { const commentsFeed = this.ig.feed.mediaComments(targetId); const comments = await commentsFeed.items(); console.error(`[Tool] Fetched ${comments.length} comments for lead analysis.`); comments.forEach(comment => { const userPkStr = String(comment.user.pk); if (!usersToAnalyze.has(userPkStr)) { usersToAnalyze.set(userPkStr, { ...comment.user, comments: [comment.text] }); } else { usersToAnalyze.get(userPkStr).comments.push(comment.text); } }); } else { // targetType === 'account' const userIdNum = parseInt(targetId, 10); const followersFeed = this.ig.feed.accountFollowers(userIdNum); const followers = await followersFeed.items(); console.error(`[Tool] Fetched ${followers.length} followers for lead analysis.`); followers.forEach(follower => { const followerPkStr = String(follower.pk); if (!usersToAnalyze.has(followerPkStr)) { usersToAnalyze.set(followerPkStr, { ...follower, comments: [] }); } }); } console.error(`[Tool] Analyzing ${usersToAnalyze.size} unique users from ${sourceDescription}.`); for (const user of usersToAnalyze.values()) { let meetsCriteria = true; let reasons: string[] = []; let userInfo = user; if ( (minFollowers && !userInfo.follower_count) || (keywords && !userInfo.biography)) { try { if (user.pk) { userInfo = await this.ig.user.info(user.pk); await new Promise(resolve => setTimeout(resolve, 100 + Math.random() * 200)); } else { console.warn(`[Tool] Skipping detailed check for user without pk: ${user.username || 'Unknown'}`); continue; } } catch (infoError: any) { console.warn(`[Tool] Could not fetch full info for user ${user.username || user.pk}: ${infoError.message}`); if (minFollowers && !userInfo.follower_count) { continue; } } } if (minFollowers && (userInfo.follower_count === undefined || userInfo.follower_count < minFollowers)) { meetsCriteria = false; } else if (minFollowers) { reasons.push(`Followers: ${userInfo.follower_count} (>=${minFollowers})`); } const userCommentCount = user.comments?.length || 0; if (minComments && userCommentCount < minComments) { meetsCriteria = false; } else if (minComments) { reasons.push(`Comments: ${userCommentCount} (>=${minComments})`); } if (keywords && keywords.length > 0) { const bio = userInfo.biography || ''; const commentsText = (user.comments || []).join(' ').toLowerCase(); const bioLower = bio.toLowerCase(); const foundKeywords = keywords.filter(kw => bioLower.includes(kw.toLowerCase()) || commentsText.includes(kw.toLowerCase())); if (foundKeywords.length === 0) { meetsCriteria = false; } else { reasons.push(`Keywords found: [${foundKeywords.join(', ')}]`); } } if (meetsCriteria) { potentialLeads.push({ username: userInfo.username, userId: userInfo.pk, fullName: userInfo.full_name, followerCount: userInfo.follower_count, isPrivate: userInfo.is_private, reasons: reasons, sampleComment: user.comments?.[0]?.substring(0, 100) }); } } console.error(`[Tool] Identified ${potentialLeads.length} potential leads.`); return { results: { leads: potentialLeads.slice(0, 50) } }; } catch (error: any) { console.error(`[API Error] Failed to identify leads for ${accountOrPostUrl}:`, error.message || error); if (error.name === 'IgNotFoundError') { throw new McpError(ErrorCode.InvalidParams, `${targetType === 'post' ? 'Post' : 'Account'} not found or access denied.`); } throw new McpError(ErrorCode.InternalError, `Failed to process lead identification: ${error.message}`); } }
- src/index.ts:43-50 (schema)TypeScript interface defining the input arguments for the identify_leads tool handler.interface IdentifyLeadsArgs { accountOrPostUrl: string; criteria?: { minComments?: number; minFollowers?: number; keywords?: string[]; }; }
- src/index.ts:190-223 (registration)Tool registration in the ListToolsRequestSchema handler, defining the name, description, and detailed inputSchema for identify_leads.{ name: 'identify_leads', description: 'Identify potential leads based on engagement patterns', inputSchema: { type: 'object', properties: { accountOrPostUrl: { type: 'string', description: 'Instagram account handle or post URL to analyze', }, criteria: { type: 'object', properties: { minComments: { type: 'number', description: 'Minimum number of comments from a user', }, minFollowers: { type: 'number', description: 'Minimum number of followers a user should have', }, keywords: { type: 'array', items: { type: 'string', }, description: 'Keywords to look for in user comments or bio', }, }, description: 'Criteria for identifying leads', }, }, required: ['accountOrPostUrl'], },
- src/index.ts:272-273 (registration)Dispatch case in the CallToolRequestSchema handler that routes calls to the identify_leads handler function.case 'identify_leads': return await this.handleIdentifyLeads(args as unknown as IdentifyLeadsArgs);