hubspot-create-engagement
Create HubSpot notes or tasks to track interactions outside the CRM, associating them with contacts, companies, deals, or tickets for updated activity reporting.
Instructions
π‘οΈ Guardrails:
1. Data Modification Warning: This tool modifies HubSpot data. Only use when the user has explicitly requested to update their CRM.
π― Purpose:
1. Creates a HubSpot engagement (Note or Task) associated with contacts, companies, deals, or tickets.
2. This endpoint is useful for keeping your CRM records up-to-date on any interactions that take place outside of HubSpot.
3. Activity reporting in the CRM also feeds off of this data.
π Prerequisites:
1. Use the hubspot-get-user-details tool to get the OwnerId and UserId.
π§ Usage Guidance:
1. Use NOTE type for adding notes to records
2. Use TASK type for creating tasks with subject, status, and assignment
3. Both require relevant associations to connect them to CRM records
4. Other types of engagements (EMAIL, CALL, MEETING) are NOT supported yet.
5. HubSpot notes and task descriptions support HTML formatting. However headings (<h1>, <h2>, etc.) look ugly in the CRM. So use them sparingly.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| type | Yes | The type of engagement to create (NOTE or TASK) | |
| ownerId | Yes | The ID of the owner of this engagement | |
| timestamp | No | Timestamp for the engagement (milliseconds since epoch). Defaults to current time if not provided. | |
| associations | Yes | Associated records for this engagement | |
| metadata | Yes | Metadata specific to the engagement type |
Implementation Reference
- The 'process' method in CreateEngagementTool class that handles the core logic: destructures input args, builds the engagement request body, calls the HubSpot API endpoint '/engagements/v1/engagements', and formats success/error responses.async process(args) { try { const { type, ownerId, timestamp, associations, metadata } = args; const engagementTimestamp = timestamp || Date.now(); const requestBody = { engagement: { active: true, ownerId, type, timestamp: engagementTimestamp, }, associations, metadata, }; const response = await this.client.post('/engagements/v1/engagements', { body: requestBody, }); return { content: [ { type: 'text', text: JSON.stringify({ status: 'success', engagement: response, message: `Successfully created ${type.toLowerCase()} engagement`, }, null, 2), }, ], }; } catch (error) { return { content: [ { type: 'text', text: `Error creating HubSpot engagement: ${error instanceof Error ? error.message : String(error)}`, }, ], isError: true, }; } }
- Zod schemas defining the input structure: ENGAGEMENT_TYPES, NoteMetadataSchema, TaskMetadataSchema, AssociationsSchema, metadataSchemas map, and the main CreateEngagementSchema with superRefine for type-specific metadata validation.const NoteMetadataSchema = z.object({ body: z.string().describe('The content of the note'), }); const TaskMetadataSchema = z.object({ body: z.string().describe('The body/description of the task'), subject: z.string().describe('The title/subject of the task'), status: z.enum(['NOT_STARTED', 'IN_PROGRESS', 'COMPLETED', 'WAITING']).default('NOT_STARTED'), forObjectType: z.enum(['CONTACT', 'COMPANY', 'DEAL', 'TICKET']).default('CONTACT'), }); export const AssociationsSchema = z.object({ contactIds: z.array(z.number().int()).optional().default([]), companyIds: z.array(z.number().int()).optional().default([]), dealIds: z.array(z.number().int()).optional().default([]), ownerIds: z.array(z.number().int()).optional().default([]), ticketIds: z.array(z.number().int()).optional().default([]), }); // Map engagement types to their metadata schemas const metadataSchemas = { NOTE: NoteMetadataSchema, TASK: TaskMetadataSchema, }; const CreateEngagementSchema = z .object({ type: z.enum(ENGAGEMENT_TYPES).describe('The type of engagement to create (NOTE or TASK)'), ownerId: z.number().int().positive().describe('The ID of the owner of this engagement'), timestamp: z .number() .int() .optional() .describe('Timestamp for the engagement (milliseconds since epoch). Defaults to current time if not provided.'), associations: AssociationsSchema.describe('Associated records for this engagement'), metadata: z.object({}).passthrough().describe('Metadata specific to the engagement type'), }) .superRefine((data, ctx) => { const schema = metadataSchemas[data.type]; if (!schema) { ctx.addIssue({ code: z.ZodIssueCode.custom, message: `Unsupported engagement type: ${data.type}`, path: ['type'], }); return; } const result = schema.safeParse(data.metadata); if (!result.success) { result.error.issues.forEach(issue => { ctx.addIssue({ ...issue, path: ['metadata', ...(issue.path || [])], }); }); } });
- dist/tools/toolsRegistry.js:40-40 (registration)Registers the CreateEngagementTool instance in the tools registry using the registerTool function.registerTool(new CreateEngagementTool());
- dist/tools/engagements/createEngagementTool.js:60-89 (registration)ToolDefinition object containing the tool name 'hubspot-create-engagement', description, inputSchema, and annotations, passed to BaseTool constructor.const ToolDefinition = { name: 'hubspot-create-engagement', description: ` π‘οΈ Guardrails: 1. Data Modification Warning: This tool modifies HubSpot data. Only use when the user has explicitly requested to update their CRM. π― Purpose: 1. Creates a HubSpot engagement (Note or Task) associated with contacts, companies, deals, or tickets. 2. This endpoint is useful for keeping your CRM records up-to-date on any interactions that take place outside of HubSpot. 3. Activity reporting in the CRM also feeds off of this data. π Prerequisites: 1. Use the hubspot-get-user-details tool to get the OwnerId and UserId. π§ Usage Guidance: 1. Use NOTE type for adding notes to records 2. Use TASK type for creating tasks with subject, status, and assignment 3. Both require relevant associations to connect them to CRM records 4. Other types of engagements (EMAIL, CALL, MEETING) are NOT supported yet. 5. HubSpot notes and task descriptions support HTML formatting. However headings (<h1>, <h2>, etc.) look ugly in the CRM. So use them sparingly. `, inputSchema: zodToJsonSchema(CreateEngagementSchema), annotations: { title: 'Create Engagement', readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: true, }, };