- API Client: Full Wrike API v4 with OAuth2/token auth, pagination, error handling - 60+ Tools across 14 categories: tasks, folders, projects, spaces, contacts, comments, timelogs, attachments, workflows, custom-fields, approvals, groups, invitations, webhooks - 22 React Apps: task-dashboard, task-detail, task-grid, task-board, project-dashboard, project-detail, project-grid, folder-tree, space-overview, gantt-view, time-dashboard, time-entries, member-workload, comment-thread, approval-manager, workflow-editor, custom-fields-manager, attachment-gallery, search-results, activity-feed, sprint-board, reports-dashboard - All apps: dark theme, client-side state, standalone directories - Full TypeScript types for all Wrike API entities - Comprehensive README with setup instructions Replaces single-file stub with production-ready MCP server
183 lines
5.8 KiB
TypeScript
183 lines
5.8 KiB
TypeScript
import type { WrikeClient } from '../clients/wrike.js';
|
|
import type { WrikeComment } from '../types/index.js';
|
|
|
|
export function createCommentTools(client: WrikeClient) {
|
|
return {
|
|
// List comments
|
|
wrike_list_comments: {
|
|
name: 'wrike_list_comments',
|
|
description: 'List comments on a task or folder',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
taskId: { type: 'string', description: 'Task ID to get comments from' },
|
|
folderId: { type: 'string', description: 'Folder ID to get comments from' },
|
|
updatedDateStart: { type: 'string', description: 'Updated date range begin' },
|
|
updatedDateEnd: { type: 'string', description: 'Updated date range end' },
|
|
plainText: { type: 'boolean', description: 'Return plain text instead of HTML' },
|
|
limit: { type: 'number', description: 'Maximum comments to return' },
|
|
},
|
|
},
|
|
handler: async (params: Record<string, unknown>) => {
|
|
let endpoint = '/comments';
|
|
|
|
if (params.taskId) {
|
|
endpoint = `/tasks/${params.taskId}/comments`;
|
|
} else if (params.folderId) {
|
|
endpoint = `/folders/${params.folderId}/comments`;
|
|
}
|
|
|
|
const queryParams: Record<string, unknown> = {};
|
|
if (params.plainText !== undefined) queryParams.plainText = params.plainText;
|
|
if (params.limit) queryParams.limit = params.limit;
|
|
|
|
if (params.updatedDateStart || params.updatedDateEnd) {
|
|
queryParams.updatedDate = {
|
|
start: params.updatedDateStart,
|
|
end: params.updatedDateEnd,
|
|
};
|
|
}
|
|
|
|
const response = await client.get<WrikeComment>(endpoint, queryParams);
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(response.data, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
|
|
// Get comment by ID
|
|
wrike_get_comment: {
|
|
name: 'wrike_get_comment',
|
|
description: 'Get a specific comment by ID',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
commentId: { type: 'string', description: 'Comment ID (required)' },
|
|
plainText: { type: 'boolean', description: 'Return plain text instead of HTML' },
|
|
},
|
|
required: ['commentId'],
|
|
},
|
|
handler: async (params: { commentId: string; plainText?: boolean }) => {
|
|
const response = await client.get<WrikeComment>(`/comments/${params.commentId}`, {
|
|
plainText: params.plainText,
|
|
});
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(response.data[0], null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
|
|
// Create comment
|
|
wrike_create_comment: {
|
|
name: 'wrike_create_comment',
|
|
description: 'Create a new comment on a task or folder',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
taskId: { type: 'string', description: 'Task ID to comment on' },
|
|
folderId: { type: 'string', description: 'Folder ID to comment on' },
|
|
text: { type: 'string', description: 'Comment text (HTML supported, required)' },
|
|
plainText: { type: 'boolean', description: 'Text is plain text, not HTML' },
|
|
},
|
|
required: ['text'],
|
|
},
|
|
handler: async (params: { taskId?: string; folderId?: string; text: string; plainText?: boolean }) => {
|
|
let endpoint = '/comments';
|
|
|
|
if (params.taskId) {
|
|
endpoint = `/tasks/${params.taskId}/comments`;
|
|
} else if (params.folderId) {
|
|
endpoint = `/folders/${params.folderId}/comments`;
|
|
} else {
|
|
throw new Error('Either taskId or folderId is required');
|
|
}
|
|
|
|
const body = {
|
|
text: params.text,
|
|
plainText: params.plainText,
|
|
};
|
|
|
|
const response = await client.post<WrikeComment>(endpoint, body);
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(response.data[0], null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
|
|
// Update comment
|
|
wrike_update_comment: {
|
|
name: 'wrike_update_comment',
|
|
description: 'Update an existing comment',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
commentId: { type: 'string', description: 'Comment ID (required)' },
|
|
text: { type: 'string', description: 'New comment text (required)' },
|
|
plainText: { type: 'boolean', description: 'Text is plain text, not HTML' },
|
|
},
|
|
required: ['commentId', 'text'],
|
|
},
|
|
handler: async (params: { commentId: string; text: string; plainText?: boolean }) => {
|
|
const body = {
|
|
text: params.text,
|
|
plainText: params.plainText,
|
|
};
|
|
|
|
const response = await client.put<WrikeComment>(`/comments/${params.commentId}`, body);
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(response.data[0], null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
|
|
// Delete comment
|
|
wrike_delete_comment: {
|
|
name: 'wrike_delete_comment',
|
|
description: 'Delete a comment',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
commentId: { type: 'string', description: 'Comment ID (required)' },
|
|
},
|
|
required: ['commentId'],
|
|
},
|
|
handler: async (params: { commentId: string }) => {
|
|
const response = await client.delete<WrikeComment>(`/comments/${params.commentId}`);
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(response.data[0], null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
};
|
|
}
|