Skip to main content
Glama
relationship-search.ts5.13 kB
/** * Relationship search tool configuration */ import { UniversalToolConfig, RelationshipSearchParams, RelationshipType, } from '../types.js'; import { AttioRecord } from '@shared-types/attio.js'; // Specific interfaces for better type safety interface RecordValues { name?: Array<{ value?: string; full_name?: string }>; full_name?: Array<{ value?: string }>; title?: Array<{ value?: string }>; email?: Array<{ value?: string }>; role?: Array<{ value?: string }>; position?: Array<{ value?: string }>; } interface RecordId { record_id?: string; } import { validateUniversalToolParams } from '../schemas.js'; import { ValidationService } from '@services/ValidationService.js'; import { isValidUUID } from '@utils/validation/uuid-validation.js'; import { ErrorService } from '@services/ErrorService.js'; import { searchCompaniesByPeople } from '@src/objects/companies/index.js'; import { searchPeopleByCompany } from '@src/objects/people/index.js'; import { searchDealsByCompany, searchDealsByPerson, } from '@src/objects/deals/index.js'; export const searchByRelationshipConfig: UniversalToolConfig< RelationshipSearchParams, AttioRecord[] > = { name: 'records_search_by_relationship', handler: async (params: RelationshipSearchParams): Promise<AttioRecord[]> => { try { const sanitizedParams = validateUniversalToolParams( 'records_search_by_relationship', params ); // Check for listId parameter first - if present and invalid, return error immediately if (params.listId && !isValidUUID(params.listId)) { throw new Error( `Invalid list_id: must be a UUID. Got: ${params.listId}` ); } const { relationship_type, source_id } = sanitizedParams; switch (relationship_type) { case RelationshipType.COMPANY_TO_PEOPLE: return await searchPeopleByCompany(source_id); case RelationshipType.PEOPLE_TO_COMPANY: return await searchCompaniesByPeople(source_id); case RelationshipType.COMPANY_TO_DEALS: return await searchDealsByCompany(source_id); case RelationshipType.PERSON_TO_DEALS: return await searchDealsByPerson(source_id); case RelationshipType.PERSON_TO_TASKS: case RelationshipType.COMPANY_TO_TASKS: // Task relationship search requires filtering tasks by linked records // This functionality depends on the Attio API's task filtering capabilities throw new Error( `Task relationship search (${relationship_type}) is not currently available. ` + `This feature requires enhanced API filtering capabilities. ` + `As a workaround, you can use the 'records_search' tool with resource_type='tasks' to find all tasks, ` + `then filter the results programmatically.` ); case 'list_entries': { // Special handling for list_entries relationship type const list_id = params.source_id; if ( !list_id || !ValidationService.validateUUIDForSearch(String(list_id)) ) { // Invalid listId should return error, not empty array throw new Error(`Invalid list_id: must be a UUID. Got: ${list_id}`); } // list_entries is not implemented as a relationship search - this should use list tools instead throw new Error( `List entries search is not supported via relationship search. ` + `Use 'get-list-details' or list-specific tools to retrieve list entries.` ); } default: throw new Error( `Invalid relationship type: ${relationship_type} not found` ); } } catch (error: unknown) { throw ErrorService.createUniversalError( 'records_search_by_relationship', params.relationship_type, error ); } }, formatResult: (results: AttioRecord[], ...args: unknown[]) => { const relationshipType = args[0] as RelationshipType | undefined; if (!Array.isArray(results)) { return 'No related records found'; } const relationshipName = relationshipType ? relationshipType.replace(/_/g, ' ') : 'relationship'; return `Found ${results.length} records for ${relationshipName}:\n${results .map((record: AttioRecord, index: number) => { const values = record.values as RecordValues; const recordId = record.id as RecordId; const name = values?.name?.[0]?.value || values?.name?.[0]?.full_name || values?.full_name?.[0]?.value || values?.title?.[0]?.value || 'Unnamed'; const id = recordId?.record_id || 'unknown'; const email = values?.email?.[0]?.value; const role = values?.role?.[0]?.value || values?.position?.[0]?.value; let details = ''; if (role) details += ` (${role})`; if (email) details += ` - ${email}`; return `${index + 1}. ${name}${details} (ID: ${id})`; }) .join('\n')}`; }, };

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/kesslerio/attio-mcp-server'

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