Skip to main content
Glama
notes.ts4.46 kB
/** * Note operations for people */ import { getPersonNotes, createPersonNote, } from '../../../objects/people/index.js'; import { NotesToolConfig, CreateNoteToolConfig } from '../../tool-types.js'; import { NoteDisplay } from '../../../types/tool-types.js'; import { createScopedLogger } from '../../../utils/logger.js'; import { safeExtractNoteTitle, safeExtractNoteContent, safeExtractNoteTimestamp, } from '../shared/type-utils.js'; export const notesToolConfigs = { notes: { name: 'get-person-notes', handler: getPersonNotes, formatResult: (notes: NoteDisplay[]) => { if (!notes || notes.length === 0) { return 'No notes found for this person.'; } // Debug logging in development to help identify API response structure (Issue #365) if (process.env.NODE_ENV === 'development' || process.env.DEBUG) { const log = createScopedLogger('people.notes', 'get-person-notes'); log.debug('Raw notes response (first item)', { first: notes.slice(0, 1), }); } return `Found ${notes.length} notes:\n${notes .map( (note: { title?: string; content?: string; created_at?: string; [key: string]: unknown; }) => { // Check multiple possible field structures from the API (Issue #365) // Field Priority Order (why this specific order was chosen): // 1. note.title/content - Standard API response fields (most common) // 2. note.timestamp - Person-specific timestamp field (checked first for person notes) // 3. note.created_at - Standard creation timestamp (fallback) // 4. note.data?.* - Nested data structure (seen in some API versions) // 5. note.values?.* - Attio-style custom field responses // 6. note.text/body - Alternative content field names (legacy/third-party support) // Note: Person notes include note.timestamp check that company notes don't have // This is intentional as person notes may use different timestamp field naming const title = safeExtractNoteTitle(note, 'Untitled'); const content = safeExtractNoteContent(note, ''); const timestamp = safeExtractNoteTimestamp(note, 'unknown'); // Additional debug logging for each note if (process.env.NODE_ENV === 'development' || process.env.DEBUG) { const log = createScopedLogger( 'people.notes', 'get-person-notes' ); log.debug('Note fields available', { keys: Object.keys(note) }); log.debug('Content presence', { hasContent: !!content, length: content ? content.length : 0, }); } // Truncate at 100 chars for person notes (shorter for readability in lists) // This is intentionally shorter than company notes (200 chars) as person notes // are often briefer and displayed in longer lists where conciseness is valued return `- ${title} (Created: ${timestamp})\n ${ content ? content.length > 100 ? content.substring(0, 100) + '...' : content : 'No content' }`; } ) .join('\n\n')}`; }, } as NotesToolConfig, createNote: { name: 'create-person-note', handler: createPersonNote, idParam: 'personId', } as CreateNoteToolConfig, }; export const notesToolDefinitions = [ { name: 'get-person-notes', description: 'Get notes for a person', inputSchema: { type: 'object', properties: { personId: { type: 'string', description: 'ID of the person to get notes for', }, }, required: ['personId'], }, }, { name: 'create-person-note', description: 'Create a note for a specific person', inputSchema: { type: 'object', properties: { personId: { type: 'string', description: 'ID of the person to create a note for', }, title: { type: 'string', description: 'Title of the note (required)', }, content: { type: 'string', description: 'Content of the note' }, }, required: ['personId', 'title', 'content'], }, }, ];

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