Skip to main content
Glama
kesslerio

Attio MCP Server

by kesslerio

create-note

Create and attach notes to records in Attio CRM for companies, people, deals, tasks, and other resource types to document important information and updates.

Instructions

Create a note for any record type (companies, people, deals)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
contentYesContent of the note
record_idYesID of the record to attach the note to
resource_typeYesTarget resource type
titleYesTitle of the note

Implementation Reference

  • The core handler function that executes the create-note tool by posting to Attio's /v2/notes API endpoint.
    export async function handleCreateNote(
      client: HttpClient,
      params: {
        resource_type: 'companies' | 'people' | 'deals';
        record_id: string;
        title: string;
        content: string;
        format?: 'plaintext' | 'markdown';
      }
    ): Promise<ToolResult> {
      try {
        const {
          resource_type,
          record_id,
          title,
          content,
          format = 'plaintext',
        } = params;
    
        const response = await client.post<AttioApiResponse<AttioNote>>(
          '/v2/notes',
          {
            data: {
              parent_object: resource_type,
              parent_record_id: record_id,
              title,
              format,
              content, // API expects 'content', not 'content_plaintext'
            },
          }
        );
    
        const note = response.data.data;
        const noteId = note.id?.note_id || 'unknown';
    
        return structuredResult(
          note,
          `Created note "${title}" (ID: ${noteId}) on ${resource_type} ${record_id}`
        );
      } catch (error) {
        const { message, details } = extractErrorInfo(error);
        return errorResult(message || 'Failed to create note', details);
      }
    }
  • The tool definition object containing the name, description, input schema, and annotations for create-note.
    export const createNoteDefinition: ToolDefinition = {
      name: 'create-note',
      description: formatDescription({
        capability:
          'Create note for companies, people, or deals with optional markdown formatting',
        boundaries: 'update or delete notes; creates only',
        constraints:
          'Requires resource_type, record_id, title, content. Optional format (plaintext or markdown)',
        recoveryHint: 'If record not found, use records_search first',
      }),
      inputSchema: {
        type: 'object',
        properties: {
          resource_type: {
            type: 'string',
            enum: ['companies', 'people', 'deals'],
            description: 'Target resource type for the note',
          },
          record_id: {
            type: 'string',
            description: 'ID of the record to attach the note to',
          },
          title: {
            type: 'string',
            description: 'Title of the note',
          },
          content: {
            type: 'string',
            description: 'Content of the note',
          },
          format: {
            type: 'string',
            enum: ['plaintext', 'markdown'],
            description: 'Content format (default: plaintext)',
            default: 'plaintext',
          },
        },
        required: ['resource_type', 'record_id', 'title', 'content'],
      },
    };
  • Registration of the create-note handler in the tool dispatch map within getToolHandler function.
    'create-note': async (client, params) =>
      handleCreateNote(
        client,
        params as Parameters<typeof handleCreateNote>[1]
      ),
  • MCP server registration of the create-note tool config in the core operations tool configs export.
    'create-note': createNoteConfig,
  • MCP-specific wrapper handler config for create-note, including validation, error handling, and result formatting.
    export const createNoteConfig: UniversalToolConfig<
      Record<string, unknown>,
      Record<string, unknown>
    > = {
      name: 'create-note',
      handler: async (
        params: Record<string, unknown>
      ): Promise<Record<string, unknown>> => {
        try {
          const sanitizedParams = validateUniversalToolParams(
            'create-note',
            params
          ) as UniversalCreateNoteParams;
    
          if (!isValidUUID(sanitizedParams.record_id)) {
            throw new Error(
              `Invalid record_id: must be a UUID. Got: ${sanitizedParams.record_id}`
            );
          }
    
          const result = await handleUniversalCreateNote(sanitizedParams);
          const { success, error } = result as Record<string, unknown> & {
            success?: boolean;
            error?: unknown;
          };
    
          if (success === false) {
            throw new Error(
              typeof error === 'string' && error.length
                ? error
                : 'Universal note creation failed'
            );
          }
    
          return result;
        } catch (err: unknown) {
          throw ErrorService.createUniversalError('create-note', 'notes', err);
        }
      },
      formatResult: (note: Record<string, unknown>): string => {
        try {
          if (!note) {
            return 'No note created';
          }
    
          const { title, content, id } = extractNoteFields(note);
    
          return `✅ Note created successfully: ${title} (ID: ${id})${
            content ? `\n${content}` : ''
          }`;
        } catch (error) {
          const err = error instanceof Error ? error : new Error(String(error));
          const fallback = createErrorResult(
            err,
            'create-note#format',
            'FORMAT'
          ) as McpErrorPayload;
          const message = fallback.content?.[0]?.text;
          return typeof message === 'string'
            ? message
            : 'Error formatting note result';
        }
      },
      structuredOutput: (
        note: Record<string, unknown>
      ): Record<string, unknown> => {
        if (!note) return {};
    
        // Normalize content fields to top-level, but preserve original id object
        const { title, content } = extractNoteFields(note);
        return {
          ...note,
          // Keep original id (object) - don't replace with extracted string
          title: title || note.title,
          content:
            content ||
            note.content ||
            note.content_markdown ||
            note.content_plaintext,
        };
      },
    };

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