search_contacts
Find contacts in Autotask by name or email, with options to filter by company, active status, and result count for efficient contact management.
Instructions
Search for contacts in Autotask with optional filters
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| companyID | No | Filter by company ID | |
| isActive | No | Filter by active status (1=active, 0=inactive) | |
| pageSize | No | Number of results to return (default: 50, max: 200) | |
| searchTerm | No | Search term for contact name or email |
Implementation Reference
- src/services/autotask.service.ts:232-301 (handler)Core implementation of searchContacts method in AutotaskService, handling API calls to Autotask with smart pagination (returns all results by default unless pageSize specified)async searchContacts(options: AutotaskQueryOptions = {}): Promise<AutotaskContact[]> { const client = await this.ensureClient(); try { this.logger.debug('Searching contacts with options:', options); // PAGINATION BY DEFAULT for data accuracy // Only limit results when user explicitly provides pageSize if (options.pageSize !== undefined && options.pageSize > 0) { // User wants limited results const queryOptions = { ...options, pageSize: Math.min(options.pageSize, 500) // Respect user limit, max 500 per request }; this.logger.debug('Single page request with user-specified limit:', queryOptions); const result = await client.contacts.list(queryOptions as any); const contacts = (result.data as AutotaskContact[]) || []; this.logger.info(`Retrieved ${contacts.length} contacts (limited by user to ${options.pageSize})`); return contacts; } else { // DEFAULT: Get ALL matching contacts via pagination for complete accuracy const allContacts: AutotaskContact[] = []; const pageSize = 500; // Use max safe page size for efficiency let currentPage = 1; let hasMorePages = true; while (hasMorePages) { const queryOptions = { ...options, pageSize: pageSize, page: currentPage }; this.logger.debug(`Fetching contacts page ${currentPage}...`); const result = await client.contacts.list(queryOptions as any); const contacts = (result.data as AutotaskContact[]) || []; if (contacts.length === 0) { hasMorePages = false; } else { allContacts.push(...contacts); // Check if we got a full page - if not, we're done if (contacts.length < pageSize) { hasMorePages = false; } else { currentPage++; } } // Safety check to prevent infinite loops if (currentPage > 30) { this.logger.warn('Contact pagination safety limit reached at 30 pages (15,000 contacts)'); hasMorePages = false; } } this.logger.info(`Retrieved ${allContacts.length} contacts across ${currentPage} pages (COMPLETE dataset for accuracy)`); return allContacts; } } catch (error) { this.logger.error('Failed to search contacts:', error); throw error; } }
- src/handlers/tool.handler.ts:168-194 (registration)Registers the MCP tool 'search_contacts' in listTools() method, including name, description, and input schemaname: 'search_contacts', description: 'Search for contacts in Autotask with optional filters', inputSchema: { type: 'object', properties: { searchTerm: { type: 'string', description: 'Search term for contact name or email' }, companyID: { type: 'number', description: 'Filter by company ID' }, isActive: { type: 'number', description: 'Filter by active status (1=active, 0=inactive)' }, pageSize: { type: 'number', description: 'Number of results to return (default: 50, max: 200)', minimum: 1, maximum: 200 } }, required: [] } },
- src/handlers/tool.handler.ts:1091-1094 (handler)Dispatches execution of 'search_contacts' tool in callTool() switch statement by calling AutotaskService.searchContactscase 'search_contacts': result = await this.autotaskService.searchContacts(args); message = `Found ${result.length} contacts`; break;
- src/handlers/tool.handler.ts:170-193 (schema)JSON schema definition for input parameters of 'search_contacts' toolinputSchema: { type: 'object', properties: { searchTerm: { type: 'string', description: 'Search term for contact name or email' }, companyID: { type: 'number', description: 'Filter by company ID' }, isActive: { type: 'number', description: 'Filter by active status (1=active, 0=inactive)' }, pageSize: { type: 'number', description: 'Number of results to return (default: 50, max: 200)', minimum: 1, maximum: 200 } }, required: [] }