mcpengine/servers/wrike/src/tools/timelogs-tools.ts
Jake Shore 5833a090c0 wrike: Complete MCP server with 88 tools and 22 React apps
- 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
2026-02-12 17:28:25 -05:00

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),
},
],
};
},
},
};
}