Skip to main content
Glama

search_tickets

Search and filter Autotask tickets by company, status, assigned resources, or keywords to retrieve comprehensive data for reporting and analytics.

Instructions

Search for tickets in Autotask with optional filters. BY DEFAULT retrieves ALL matching tickets via pagination for complete accuracy. Only specify pageSize to limit results. Perfect for reports and analytics.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
assignedResourceIDNoFilter by assigned resource ID. Use null (or omit) to search for unassigned tickets.
companyIDNoFilter by company ID
pageSizeNoOPTIONAL: Limit number of results. If omitted, retrieves ALL matching tickets for complete accuracy.
searchTermNoSearch term for ticket title or description
statusNoFilter by ticket status ID (omit for all open tickets: status < 5)
unassignedNoSet to true to find tickets that are not assigned to any resource (where assignedResourceID is null)

Implementation Reference

  • Tool registration including name, description, and input schema definition in the listTools() method.
    { name: 'search_tickets', description: 'Search for tickets in Autotask with optional filters. BY DEFAULT retrieves ALL matching tickets via pagination for complete accuracy. Only specify pageSize to limit results. Perfect for reports and analytics.', inputSchema: { type: 'object', properties: { searchTerm: { type: 'string', description: 'Search term for ticket title or description' }, companyID: { type: 'number', description: 'Filter by company ID' }, status: { type: 'number', description: 'Filter by ticket status ID (omit for all open tickets: status < 5)' }, assignedResourceID: { type: 'number', description: 'Filter by assigned resource ID. Use null (or omit) to search for unassigned tickets.' }, unassigned: { type: 'boolean', description: 'Set to true to find tickets that are not assigned to any resource (where assignedResourceID is null)' }, pageSize: { type: 'number', description: 'OPTIONAL: Limit number of results. If omitted, retrieves ALL matching tickets for complete accuracy.', minimum: 1, maximum: 500 } }, required: [] } },
  • Dispatch handler in callTool() method that maps tool arguments and delegates to AutotaskService.searchTickets()
    case 'search_tickets': // Map parameter names from tool schema to service expectations const { companyID, ...otherArgs } = args; const ticketSearchOptions = { ...otherArgs, ...(companyID !== undefined && { companyId: companyID }), }; result = await this.autotaskService.searchTickets(ticketSearchOptions); message = `Found ${result.length} tickets`; break;
  • Core searchTickets implementation: builds Autotask API filters, handles pagination (all results by default), calls API, optimizes ticket data.
    async searchTickets(options: AutotaskQueryOptionsExtended = {}): Promise<AutotaskTicket[]> { const client = await this.ensureClient(); try { this.logger.debug('Searching tickets with options:', options); // Build proper filter array for Autotask API const filters: any[] = []; // Handle searchTerm - search in ticket number and title if (options.searchTerm) { filters.push( { op: 'beginsWith', field: 'ticketNumber', value: options.searchTerm } ); } // Handle status filter with more accurate open ticket definition if (options.status !== undefined) { filters.push({ op: 'eq', field: 'status', value: options.status }); } else { // For "open" tickets, we need to be more specific about Autotask status values // Based on Autotask documentation, typical open statuses are: // 1 = New, 2 = In Progress, 8 = Waiting Customer, 9 = Waiting Vendor, etc. // Status 5 = Complete/Closed, so anything NOT complete should be considered open filters.push({ op: 'ne', field: 'status', value: 5 // 5 = Complete in Autotask }); } // Handle assignedResourceID filter or unassigned filter if (options.unassigned === true) { // Search for tickets with no assigned resource (null assignedResourceID) filters.push({ op: 'eq', field: 'assignedResourceID', value: null }); } else if (options.assignedResourceID !== undefined) { filters.push({ op: 'eq', field: 'assignedResourceID', value: options.assignedResourceID }); } // Only add company filter if explicitly provided if (options.companyId !== undefined) { filters.push({ op: 'eq', field: 'companyID', value: options.companyId }); } // 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 = { filter: filters, 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.tickets.list(queryOptions); const tickets = (result.data as AutotaskTicket[]) || []; const optimizedTickets = tickets.map(ticket => this.optimizeTicketDataAggressive(ticket)); this.logger.info(`Retrieved ${optimizedTickets.length} tickets (limited by user to ${options.pageSize})`); return optimizedTickets; } else { // DEFAULT: Get ALL matching tickets via pagination for complete accuracy const allTickets: AutotaskTicket[] = []; const pageSize = 500; // Use max safe page size for efficiency let currentPage = 1; let hasMorePages = true; while (hasMorePages) { const queryOptions = { filter: filters, pageSize: pageSize, page: currentPage }; this.logger.debug(`Fetching page ${currentPage} with filter:`, filters); const result = await client.tickets.list(queryOptions); const tickets = (result.data as AutotaskTicket[]) || []; if (tickets.length === 0) { hasMorePages = false; } else { // Transform tickets to optimize data size const optimizedTickets = tickets.map(ticket => this.optimizeTicketDataAggressive(ticket)); allTickets.push(...optimizedTickets); // Check if we got a full page - if not, we're done if (tickets.length < pageSize) { hasMorePages = false; } else { currentPage++; } } // Safety check to prevent infinite loops if (currentPage > 100) { this.logger.warn('Pagination safety limit reached at 100 pages (50,000 tickets)'); hasMorePages = false; } } this.logger.info(`Retrieved ${allTickets.length} tickets across ${currentPage} pages (COMPLETE dataset for accuracy)`); return allTickets; } } catch (error) { this.logger.error('Failed to search tickets:', error); throw error; }
  • Helper function to aggressively optimize ticket data by selecting essential fields and truncating text to reduce response size.
    private optimizeTicketDataAggressive(ticket: AutotaskTicket): AutotaskTicket { // Keep only the most essential fields to minimize response size const optimized: AutotaskTicket = {}; if (ticket.id !== undefined) optimized.id = ticket.id; if (ticket.ticketNumber !== undefined) optimized.ticketNumber = ticket.ticketNumber; if (ticket.title !== undefined) optimized.title = ticket.title; // Handle description with truncation if (ticket.description !== undefined && ticket.description !== null) { optimized.description = ticket.description.length > 200 ? ticket.description.substring(0, 200) + '... [truncated - use get_ticket_details for full text]' : ticket.description; } if (ticket.status !== undefined) optimized.status = ticket.status; if (ticket.priority !== undefined) optimized.priority = ticket.priority; if (ticket.companyID !== undefined) optimized.companyID = ticket.companyID; if (ticket.contactID !== undefined) optimized.contactID = ticket.contactID; if (ticket.assignedResourceID !== undefined) optimized.assignedResourceID = ticket.assignedResourceID; if (ticket.createDate !== undefined) optimized.createDate = ticket.createDate; if (ticket.lastActivityDate !== undefined) optimized.lastActivityDate = ticket.lastActivityDate; if (ticket.dueDateTime !== undefined) optimized.dueDateTime = ticket.dueDateTime; if (ticket.completedDate !== undefined) optimized.completedDate = ticket.completedDate; if (ticket.estimatedHours !== undefined) optimized.estimatedHours = ticket.estimatedHours; if (ticket.ticketType !== undefined) optimized.ticketType = ticket.ticketType; if (ticket.source !== undefined) optimized.source = ticket.source; if (ticket.issueType !== undefined) optimized.issueType = ticket.issueType; if (ticket.subIssueType !== undefined) optimized.subIssueType = ticket.subIssueType; // Handle resolution with truncation if (ticket.resolution !== undefined && ticket.resolution !== null) { optimized.resolution = ticket.resolution.length > 100 ? ticket.resolution.substring(0, 100) + '... [truncated - use get_ticket_details for full text]' : ticket.resolution; } return optimized; }

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/asachs01/autotask-mcp'

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