Skip to main content
Glama
universal.constants.tsβ€’12.9 kB
/** * Universal Constants for Attio MCP Server * * Centralized location for all magic numbers, field mappings, and configuration * constants used throughout the universal handlers and services. * * Addresses PR feedback: Extract constants to improve maintainability and * reduce magic numbers scattered throughout the codebase. */ import { UniversalResourceType } from '../handlers/tool-configs/universal/types.js'; // ======================================== // Cache Configuration // ======================================== /** Default TTL for tasks cache in milliseconds (30 seconds) */ export const DEFAULT_TASKS_CACHE_TTL = 30000; /** Default TTL for 404 response cache in milliseconds (60 seconds) */ export const DEFAULT_404_CACHE_TTL = 60000; /** Default TTL for attribute discovery cache in milliseconds (5 minutes) */ export const DEFAULT_ATTRIBUTES_CACHE_TTL = 300000; /** Maximum number of cache entries before cleanup */ export const MAX_CACHE_ENTRIES = 1000; // ======================================== // Performance & Limits // ======================================== /** Maximum number of suggestions to show in validation errors */ export const MAX_VALIDATION_SUGGESTIONS = 5; /** Maximum length for truncated suggestion text */ export const MAX_SUGGESTION_TEXT_LENGTH = 100; /** Default request timeout in milliseconds */ export const DEFAULT_REQUEST_TIMEOUT = 30000; /** Maximum number of retry attempts for API calls */ export const MAX_RETRY_ATTEMPTS = 3; /** Base delay between retries in milliseconds */ export const RETRY_BASE_DELAY = 1000; // ======================================== // Resource Type Mappings // ======================================== /** * Maps various resource type strings to canonical UniversalResourceType values * Handles common typos and plural/singular variations */ export const RESOURCE_TYPE_MAPPINGS: Record<string, UniversalResourceType> = { // Canonical forms record: UniversalResourceType.RECORDS, records: UniversalResourceType.RECORDS, company: UniversalResourceType.COMPANIES, companies: UniversalResourceType.COMPANIES, person: UniversalResourceType.PEOPLE, people: UniversalResourceType.PEOPLE, deal: UniversalResourceType.DEALS, deals: UniversalResourceType.DEALS, task: UniversalResourceType.TASKS, tasks: UniversalResourceType.TASKS, note: UniversalResourceType.NOTES, notes: UniversalResourceType.NOTES, list: UniversalResourceType.LISTS, lists: UniversalResourceType.LISTS, // Common typos and variations comapny: UniversalResourceType.COMPANIES, compnay: UniversalResourceType.COMPANIES, poeple: UniversalResourceType.PEOPLE, peolpe: UniversalResourceType.PEOPLE, dela: UniversalResourceType.DEALS, dael: UniversalResourceType.DEALS, taks: UniversalResourceType.TASKS, tsak: UniversalResourceType.TASKS, not: UniversalResourceType.NOTES, liste: UniversalResourceType.LISTS, }; /** * Maps resource types to their Attio API object slugs * Used for schema discovery and API routing */ export const OBJECT_SLUG_MAP: Record<string, string> = { companies: 'companies', people: 'people', deals: 'deals', tasks: 'tasks', records: 'records', lists: 'lists', notes: 'notes', }; // ======================================== // Field Mappings - Companies // ======================================== export const COMPANY_FIELD_MAPPINGS = { // Common incorrect field names -> correct ones website: 'domains', url: 'domains', company_name: 'name', company_domain: 'domains', domain: 'domains', website_url: 'domains', company_url: 'domains', site: 'domains', homepage: 'domains', web: 'domains', // Industry and description industry_type: 'industry', business_type: 'industry', sector: 'industry', category: 'industry', about: 'description', summary: 'description', overview: 'description', info: 'description', details: 'description', // Size and employee count size: 'team_size', employees: 'team_size', employee_count: 'team_size', headcount: 'team_size', staff_count: 'team_size', }; export const COMPANY_VALID_FIELDS = [ 'name', 'domains', 'description', 'industry', 'team_size', 'founded_at', 'headquarters', 'linkedin_url', 'twitter_handle', 'facebook_url', 'crunchbase_url', 'annual_revenue', 'categories', 'locations', ]; export const COMPANY_COMMON_MISTAKES = { website: 'Use "domains" for company websites (as an array of strings)', url: 'Use "domains" for company websites (as an array of strings)', company_name: 'Use "name" for the company name', about: 'Use "description" for company descriptions', size: 'Use "team_size" for employee count (as a number)', }; // ======================================== // Field Mappings - People // ======================================== export const PEOPLE_FIELD_MAPPINGS = { // Name variations full_name: 'name', fullname: 'name', person_name: 'name', contact_name: 'name', individual_name: 'name', // Email variations email: 'email_addresses', emails: 'email_addresses', email_address: 'email_addresses', contact_email: 'email_addresses', work_email: 'email_addresses', business_email: 'email_addresses', // Phone variations phone: 'phone_numbers', phones: 'phone_numbers', phone_number: 'phone_numbers', contact_phone: 'phone_numbers', mobile: 'phone_numbers', cell: 'phone_numbers', telephone: 'phone_numbers', // Job title variations job_title: 'title', position: 'title', role: 'title', job_position: 'title', job_role: 'title', occupation: 'title', designation: 'title', }; export const PEOPLE_VALID_FIELDS = [ 'name', 'email_addresses', 'phone_numbers', 'title', 'linkedin_url', 'twitter_handle', 'location', 'avatar_url', 'timezone', 'primary_email_address', 'primary_phone_number', ]; export const PEOPLE_COMMON_MISTAKES = { email: 'Use "email_addresses" as an array of email strings', phone: 'Use "phone_numbers" as an array of phone strings', job_title: 'Use "title" for job titles', full_name: 'Use "name" for person names (can be string or name object)', }; // ======================================== // Field Mappings - Tasks // ======================================== export const TASK_FIELD_MAPPINGS = { // Content variations task: 'content', description: 'content', title: 'content', name: 'content', task_name: 'content', task_title: 'content', task_description: 'content', todo: 'content', item: 'content', // Status variations status: 'is_completed', completed: 'is_completed', done: 'is_completed', finished: 'is_completed', complete: 'is_completed', is_done: 'is_completed', is_finished: 'is_completed', // Deadline variations deadline: 'deadline_at', due_date: 'deadline_at', due: 'deadline_at', expires_at: 'deadline_at', completion_date: 'deadline_at', target_date: 'deadline_at', // Assignment variations assignee: 'assignees', assigned_to: 'assignees', owner: 'assignees', responsible: 'assignees', assigned_user: 'assignees', task_owner: 'assignees', // Linked records variations linked_record: 'linked_records', related_records: 'linked_records', connected_records: 'linked_records', associated_records: 'linked_records', }; export const TASK_VALID_FIELDS = [ 'content', 'is_completed', 'deadline_at', 'assignees', 'linked_records', 'created_at', 'updated_at', 'completed_at', ]; export const TASK_COMMON_MISTAKES = { task: 'Use "content" for task descriptions', title: 'Use "content" for task descriptions', status: 'Use "is_completed" (boolean) for completion status', deadline: 'Use "deadline_at" for due dates (ISO 8601 string)', assignee: 'Use "assignees" as an array of user IDs', }; // ======================================== // Field Mappings - Deals // ======================================== export const DEAL_FIELD_MAPPINGS = { // Name variations deal_name: 'name', opportunity_name: 'name', title: 'name', deal_title: 'name', // Value variations amount: 'value', deal_value: 'value', opportunity_value: 'value', deal_amount: 'value', revenue: 'value', // Stage variations deal_stage: 'stage', opportunity_stage: 'stage', sales_stage: 'stage', pipeline_stage: 'stage', // Close date variations close_date: 'close_date', expected_close: 'close_date', target_close: 'close_date', projected_close: 'close_date', }; export const DEAL_VALID_FIELDS = [ 'name', 'value', 'stage', 'close_date', 'currency', 'probability', 'owner', 'source', 'type', 'priority', ]; export const DEAL_COMMON_MISTAKES = { amount: 'Use "value" for deal amounts', deal_name: 'Use "name" for deal names', deal_stage: 'Use "stage" for deal stages', close_date: 'Use "close_date" for expected close dates', }; // ======================================== // Field Mappings - Records // ======================================== export const RECORD_FIELD_MAPPINGS = { // Generic record mappings title: 'name', record_name: 'name', }; export const RECORD_VALID_FIELDS = [ 'object', 'object_api_slug', 'object_slug', 'values', 'name', 'notes', 'created_at', 'updated_at', ]; export const RECORD_COMMON_MISTAKES = { title: 'Use "name" for record titles', }; // ======================================== // Field Mappings - Notes // ======================================== export const NOTE_FIELD_MAPPINGS = { // Content variations note: 'content', text: 'content', body: 'content', message: 'content', description: 'content', comment: 'content', // Title variations note_title: 'title', subject: 'title', heading: 'title', // Parent record variations parent: 'parent_record_id', record_id: 'parent_record_id', attached_to: 'parent_record_id', linked_to: 'parent_record_id', // Parent object variations object_type: 'parent_object', parent_type: 'parent_object', attached_to_type: 'parent_object', }; export const NOTE_VALID_FIELDS = [ 'content', 'title', 'parent_object', 'parent_record_id', 'format', 'created_at', 'updated_at', ]; export const NOTE_COMMON_MISTAKES = { note: 'Use "content" for note text', text: 'Use "content" for note text', parent: 'Use "parent_record_id" for the record the note is attached to', object_type: 'Use "parent_object" for the type of record the note is attached to', }; // ======================================== // Error Messages // ======================================== export const ERROR_MESSAGES = { INVALID_RESOURCE_TYPE: (type: string) => `Invalid resource type: ${type}`, MISSING_REQUIRED_FIELD: (field: string) => `Missing required field: ${field}`, INVALID_FIELD_TYPE: (field: string, expected: string, received: string) => `Invalid type for field "${field}": expected ${expected}, received ${received}`, FIELD_COLLISION: (fields: string[], target: string) => `Multiple fields map to "${target}": ${fields.join(', ')}`, ATTRIBUTE_DISCOVERY_FAILED: (resourceType: string) => `Failed to discover attributes for ${resourceType}`, CACHE_CLEANUP_FAILED: 'Failed to cleanup expired cache entries', VALIDATION_FAILED: (resourceType: string) => `Validation failed for ${resourceType}`, }; // ======================================== // Validation Patterns // ======================================== /** Regex pattern for valid email addresses (basic validation) */ export const EMAIL_PATTERN = /^[^\s@]+@[^\s@]+\.[^\s@]+$/; /** Regex pattern for valid phone numbers (international format) */ export const PHONE_PATTERN = /^\+[\d\s\-().]+$/; /** Regex pattern for valid URLs */ export const URL_PATTERN = /^https?:\/\/.+$/; /** Regex pattern for valid UUID format */ export const UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[1-5][0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/i; // ======================================== // Boolean Conversion Values // ======================================== /** Values that should be converted to true */ export const TRUTHY_VALUES = [ 'done', 'complete', 'completed', 'true', 'yes', 'y', '1', 'closed', 'finished', 'resolved', ]; /** Values that should be converted to false */ export const FALSY_VALUES = [ 'open', 'pending', 'in progress', 'false', 'no', 'n', '0', 'todo', 'incomplete', 'unresolved', ]; // ======================================== // API Configuration // ======================================== /** Default page size for paginated requests */ export const DEFAULT_PAGE_SIZE = 25; /** Maximum page size allowed */ export const MAX_PAGE_SIZE = 100; /** Default limit for search results */ export const DEFAULT_SEARCH_LIMIT = 10; /** Maximum search results limit */ export const MAX_SEARCH_LIMIT = 500;

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