twenty-mcp-server
Version:
Easy-to-install Model Context Protocol server for Twenty CRM. Try instantly with 'npx twenty-mcp-server setup' or install globally for permanent use.
196 lines (190 loc) • 9.02 kB
JavaScript
import { z } from 'zod';
export function registerActivityTools(server, client) {
server.tool('get_activities', 'Get unified activities timeline from Twenty CRM (tasks, notes, etc.)', {
type: z.array(z.enum(['task', 'note'])).optional().describe('Filter by activity types'),
dateFrom: z.string().optional().describe('Start date filter (ISO 8601 format)'),
dateTo: z.string().optional().describe('End date filter (ISO 8601 format)'),
authorId: z.string().optional().describe('Filter by author/assignee ID'),
limit: z.number().optional().default(20).describe('Maximum number of activities to return'),
offset: z.number().optional().default(0).describe('Number of activities to skip'),
}, async (args) => {
try {
const timeline = await client.getActivities({
type: args.type,
dateFrom: args.dateFrom,
dateTo: args.dateTo,
authorId: args.authorId,
limit: args.limit,
offset: args.offset,
});
const activitiesText = timeline.activities.map(activity => {
const authorName = activity.author
? `${activity.author.name.firstName} ${activity.author.name.lastName}`
: 'Unknown';
const createdDate = new Date(activity.createdAt).toLocaleDateString();
return `[${activity.type.toUpperCase()}] ${activity.title || 'Untitled'} (${createdDate})
Author: ${authorName}
${activity.body ? `Content: ${activity.body.substring(0, 200)}${activity.body.length > 200 ? '...' : ''}` : ''}
ID: ${activity.id}
---`;
}).join('\n\n');
return {
content: [{
type: 'text',
text: `Activities Timeline (${timeline.totalCount} total, showing ${timeline.activities.length}):
${activitiesText}
${timeline.hasMore ? 'Use offset parameter to load more activities.' : 'No more activities to load.'}`
}]
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `Error retrieving activities: ${error instanceof Error ? error.message : 'Unknown error'}`
}]
};
}
});
server.tool('filter_activities', 'Filter activities by specific criteria', {
type: z.array(z.enum(['task', 'note'])).optional().describe('Activity types to include'),
dateFrom: z.string().optional().describe('Start date (ISO 8601 format)'),
dateTo: z.string().optional().describe('End date (ISO 8601 format)'),
authorId: z.string().optional().describe('Filter by author/assignee ID'),
status: z.array(z.string()).optional().describe('Task status filter (for tasks only)'),
limit: z.number().optional().default(20).describe('Maximum number of results'),
offset: z.number().optional().default(0).describe('Number of results to skip'),
}, async (args) => {
try {
const activities = await client.filterActivities({
type: args.type,
dateFrom: args.dateFrom,
dateTo: args.dateTo,
authorId: args.authorId,
status: args.status,
limit: args.limit,
offset: args.offset,
});
if (activities.length === 0) {
return {
content: [{
type: 'text',
text: 'No activities found matching the specified criteria.'
}]
};
}
const resultsText = activities.map((activity, index) => {
const authorName = activity.author
? `${activity.author.name.firstName} ${activity.author.name.lastName}`
: 'Unknown';
return `${index + 1}. [${activity.type.toUpperCase()}] ${activity.title || 'Untitled'}
Created: ${new Date(activity.createdAt).toLocaleString()}
Author: ${authorName}
ID: ${activity.id}`;
}).join('\n\n');
return {
content: [{
type: 'text',
text: `Found ${activities.length} activities matching criteria:
${resultsText}`
}]
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `Error filtering activities: ${error instanceof Error ? error.message : 'Unknown error'}`
}]
};
}
});
server.tool('create_comment', 'Create a comment on any CRM record', {
body: z.string().describe('Comment content'),
authorId: z.string().optional().describe('ID of the comment author'),
activityTargetId: z.string().optional().describe('ID of the activity target (if linking to specific record)'),
targetObjectId: z.string().optional().describe('ID of the target object (person, company, opportunity)'),
targetObjectType: z.enum(['person', 'company', 'opportunity']).optional().describe('Type of target object'),
}, async (args) => {
try {
const comment = await client.createComment({
body: args.body,
authorId: args.authorId,
activityTargetId: args.activityTargetId,
targetObjectId: args.targetObjectId,
targetObjectNameSingular: args.targetObjectType,
});
const authorName = comment.author
? `${comment.author.name.firstName} ${comment.author.name.lastName}`
: 'Unknown';
return {
content: [{
type: 'text',
text: `Comment created successfully by ${authorName} (ID: ${comment.id})
Content: ${comment.body}
Created: ${new Date(comment.createdAt).toLocaleString()}`
}]
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `Error creating comment: ${error instanceof Error ? error.message : 'Unknown error'}`
}]
};
}
});
server.tool('get_entity_activities', 'Get all activities related to a specific entity (person, company, or opportunity)', {
entityId: z.string().describe('ID of the entity'),
entityType: z.enum(['person', 'company', 'opportunity']).describe('Type of entity'),
includeComments: z.boolean().optional().default(true).describe('Include comments in results'),
limit: z.number().optional().default(20).describe('Maximum number of activities'),
offset: z.number().optional().default(0).describe('Number of activities to skip'),
}, async (args) => {
try {
const timeline = await client.getEntityActivities({
entityId: args.entityId,
entityType: args.entityType,
includeComments: args.includeComments,
limit: args.limit,
offset: args.offset,
});
if (timeline.activities.length === 0) {
return {
content: [{
type: 'text',
text: `No activities found for ${args.entityType} ${args.entityId}.`
}]
};
}
const activitiesText = timeline.activities.map((activity, index) => {
const authorName = activity.author
? `${activity.author.name.firstName} ${activity.author.name.lastName}`
: 'Unknown';
const date = new Date(activity.createdAt);
return `${index + 1}. [${activity.type.toUpperCase()}] ${activity.title || 'Untitled'}
Created: ${date.toLocaleDateString()} at ${date.toLocaleTimeString()}
Author: ${authorName}
${activity.body ? `Preview: ${activity.body.substring(0, 150)}${activity.body.length > 150 ? '...' : ''}` : ''}`;
}).join('\n\n');
return {
content: [{
type: 'text',
text: `Activities for ${args.entityType} ${args.entityId} (${timeline.totalCount} total):
${activitiesText}
${timeline.hasMore ? `Use offset=${args.offset + args.limit} to load more activities.` : 'No more activities available.'}`
}]
};
}
catch (error) {
return {
content: [{
type: 'text',
text: `Error retrieving entity activities: ${error instanceof Error ? error.message : 'Unknown error'}`
}]
};
}
});
}
//# sourceMappingURL=activities.js.map