- Full Wrike API v4 client with auth, rate limiting, pagination - 88 MCP tools across 13 categories (tasks, projects, folders, spaces, comments, attachments, timelogs, contacts, groups, workflows, custom fields, approvals, webhooks, and more) - 22 interactive React apps (task board, Gantt view, project dashboard, space overview, team workload, time tracker, approval manager, custom fields manager, workflow editor, and more) - Complete TypeScript types for all Wrike entities - Comprehensive README with usage examples - Both stdio and HTTP server modes - Successfully compiles with TypeScript
229 lines
8.1 KiB
TypeScript
229 lines
8.1 KiB
TypeScript
import type { WrikeClient } from '../clients/wrike.js';
|
|
import type { WrikeTimelog, CreateTimelogRequest } from '../types/index.js';
|
|
|
|
export function createTimelogTools(client: WrikeClient) {
|
|
return {
|
|
// List timelogs
|
|
wrike_list_timelogs: {
|
|
name: 'wrike_list_timelogs',
|
|
description: 'List time logs with optional filters',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
taskId: { type: 'string', description: 'Filter by task ID' },
|
|
folderId: { type: 'string', description: 'Filter by folder ID' },
|
|
contactId: { type: 'string', description: 'Filter by contact ID' },
|
|
categoryId: { type: 'string', description: 'Filter by category ID' },
|
|
descendants: { type: 'boolean', description: 'Include timelogs from subfolders' },
|
|
trackedDateStart: { type: 'string', description: 'Tracked date range begin (YYYY-MM-DD)' },
|
|
trackedDateEnd: { type: 'string', description: 'Tracked date range end (YYYY-MM-DD)' },
|
|
createdDateStart: { type: 'string', description: 'Created date range begin' },
|
|
createdDateEnd: { type: 'string', description: 'Created date range end' },
|
|
updatedDateStart: { type: 'string', description: 'Updated date range begin' },
|
|
updatedDateEnd: { type: 'string', description: 'Updated date range end' },
|
|
me: { type: 'boolean', description: 'Only my timelogs' },
|
|
billable: { type: 'boolean', description: 'Filter by billable status' },
|
|
},
|
|
},
|
|
handler: async (params: Record<string, unknown>) => {
|
|
let endpoint = '/timelogs';
|
|
|
|
if (params.taskId) {
|
|
endpoint = `/tasks/${params.taskId}/timelogs`;
|
|
} else if (params.folderId) {
|
|
endpoint = `/folders/${params.folderId}/timelogs`;
|
|
} else if (params.contactId) {
|
|
endpoint = `/contacts/${params.contactId}/timelogs`;
|
|
}
|
|
|
|
const queryParams: Record<string, unknown> = {};
|
|
if (params.descendants !== undefined) queryParams.descendants = params.descendants;
|
|
if (params.categoryId) queryParams.categoryId = params.categoryId;
|
|
if (params.me !== undefined) queryParams.me = params.me;
|
|
if (params.billable !== undefined) queryParams.billable = params.billable;
|
|
|
|
if (params.trackedDateStart || params.trackedDateEnd) {
|
|
queryParams.trackedDate = {
|
|
start: params.trackedDateStart,
|
|
end: params.trackedDateEnd,
|
|
};
|
|
}
|
|
|
|
if (params.createdDateStart || params.createdDateEnd) {
|
|
queryParams.createdDate = {
|
|
start: params.createdDateStart,
|
|
end: params.createdDateEnd,
|
|
};
|
|
}
|
|
|
|
if (params.updatedDateStart || params.updatedDateEnd) {
|
|
queryParams.updatedDate = {
|
|
start: params.updatedDateStart,
|
|
end: params.updatedDateEnd,
|
|
};
|
|
}
|
|
|
|
const response = await client.get<WrikeTimelog>(endpoint, queryParams);
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(response.data, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
|
|
// Get timelog by ID
|
|
wrike_get_timelog: {
|
|
name: 'wrike_get_timelog',
|
|
description: 'Get a specific timelog by ID',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
timelogId: { type: 'string', description: 'Timelog ID (required)' },
|
|
},
|
|
required: ['timelogId'],
|
|
},
|
|
handler: async (params: { timelogId: string }) => {
|
|
const response = await client.get<WrikeTimelog>(`/timelogs/${params.timelogId}`);
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(response.data[0], null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
|
|
// Create timelog
|
|
wrike_create_timelog: {
|
|
name: 'wrike_create_timelog',
|
|
description: 'Create a new time log entry',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
taskId: { type: 'string', description: 'Task ID (required)' },
|
|
hours: { type: 'number', description: 'Hours logged (required)' },
|
|
trackedDate: { type: 'string', description: 'Date tracked (YYYY-MM-DD, required)' },
|
|
comment: { type: 'string', description: 'Comment/description' },
|
|
categoryId: { type: 'string', description: 'Time category ID' },
|
|
billable: { type: 'boolean', description: 'Is billable' },
|
|
},
|
|
required: ['taskId', 'hours', 'trackedDate'],
|
|
},
|
|
handler: async (params: { taskId: string; hours: number; trackedDate: string; [key: string]: unknown }) => {
|
|
const body: CreateTimelogRequest = {
|
|
hours: params.hours,
|
|
trackedDate: params.trackedDate,
|
|
};
|
|
|
|
if (params.comment) body.comment = params.comment as string;
|
|
if (params.categoryId) body.categoryId = params.categoryId as string;
|
|
if (params.billable !== undefined) body.billable = params.billable as boolean;
|
|
|
|
const response = await client.post<WrikeTimelog>(`/tasks/${params.taskId}/timelogs`, body);
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(response.data[0], null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
|
|
// Update timelog
|
|
wrike_update_timelog: {
|
|
name: 'wrike_update_timelog',
|
|
description: 'Update an existing time log entry',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
timelogId: { type: 'string', description: 'Timelog ID (required)' },
|
|
hours: { type: 'number', description: 'New hours logged' },
|
|
trackedDate: { type: 'string', description: 'New tracked date (YYYY-MM-DD)' },
|
|
comment: { type: 'string', description: 'New comment' },
|
|
categoryId: { type: 'string', description: 'New time category ID' },
|
|
billable: { type: 'boolean', description: 'New billable status' },
|
|
},
|
|
required: ['timelogId'],
|
|
},
|
|
handler: async (params: { timelogId: string; [key: string]: unknown }) => {
|
|
const body: Partial<CreateTimelogRequest> = {};
|
|
|
|
if (params.hours !== undefined) body.hours = params.hours as number;
|
|
if (params.trackedDate) body.trackedDate = params.trackedDate as string;
|
|
if (params.comment !== undefined) body.comment = params.comment as string;
|
|
if (params.categoryId) body.categoryId = params.categoryId as string;
|
|
if (params.billable !== undefined) body.billable = params.billable as boolean;
|
|
|
|
const response = await client.put<WrikeTimelog>(`/timelogs/${params.timelogId}`, body);
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(response.data[0], null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
|
|
// Delete timelog
|
|
wrike_delete_timelog: {
|
|
name: 'wrike_delete_timelog',
|
|
description: 'Delete a time log entry',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {
|
|
timelogId: { type: 'string', description: 'Timelog ID (required)' },
|
|
},
|
|
required: ['timelogId'],
|
|
},
|
|
handler: async (params: { timelogId: string }) => {
|
|
const response = await client.delete<WrikeTimelog>(`/timelogs/${params.timelogId}`);
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(response.data[0], null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
|
|
// Get timelog categories
|
|
wrike_list_timelog_categories: {
|
|
name: 'wrike_list_timelog_categories',
|
|
description: 'List all time log categories',
|
|
inputSchema: {
|
|
type: 'object',
|
|
properties: {},
|
|
},
|
|
handler: async () => {
|
|
const response = await client.get('/timelog_categories');
|
|
|
|
return {
|
|
content: [
|
|
{
|
|
type: 'text',
|
|
text: JSON.stringify(response.data, null, 2),
|
|
},
|
|
],
|
|
};
|
|
},
|
|
},
|
|
};
|
|
}
|