get_worklogs
Retrieve your worklogs from JIRA Tempo for specific dates or issues to track time entries and review logged hours.
Instructions
Retrieve worklogs for authenticated user and date range
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| startDate | Yes | Start date in YYYY-MM-DD format | |
| endDate | No | End date in YYYY-MM-DD format (optional, defaults to startDate) | |
| issueKey | No | Optional filter by specific issue key (e.g., PROJ-1234) |
Implementation Reference
- src/tools/get-worklogs.ts:15-149 (handler)The primary handler function for the 'get_worklogs' tool. Fetches worklogs from Tempo API via TempoClient, processes responses, calculates totals, groups by issue, and returns a formatted markdown display with summaries and recent entries.export async function getWorklogs( tempoClient: TempoClient, input: GetWorklogsInput ): Promise<CallToolResult> { try { const { startDate, endDate, issueKey } = input; // Use endDate or default to startDate const actualEndDate = endDate || startDate; // Fetch worklogs from Tempo API (automatically filters by authenticated user) const worklogResponses = await tempoClient.getWorklogs({ from: startDate, to: actualEndDate, issueKey: issueKey }); // Process and format the worklogs const worklogs: TempoWorklog[] = worklogResponses.map((response: TempoWorklogResponse) => ({ id: response.tempoWorklogId?.toString() || response.id || 'unknown', issueKey: response.issue.key, issueSummary: response.issue.summary, timeSpentSeconds: response.timeSpentSeconds, billableSeconds: response.billableSeconds, started: response.started, worker: response.worker, attributes: response.attributes || {}, timeSpent: response.timeSpent, comment: response.comment || '' })); // Calculate total hours const totalSeconds = worklogs.reduce((sum, worklog) => sum + worklog.timeSpentSeconds, 0); const totalHours = Math.round((totalSeconds / 3600) * 100) / 100; // Round to 2 decimal places const result: GetWorklogsResponse = { worklogs, totalHours }; // Format response for display - CONCISE VERSION let displayText = `## Your Worklogs (${startDate}`; if (endDate && endDate !== startDate) { displayText += ` to ${endDate}`; } displayText += `)\n\n`; if (issueKey) { displayText += `**Issue:** ${issueKey}\n\n`; } if (worklogs.length === 0) { displayText += "No worklogs found.\n"; } else { displayText += `**Total:** ${totalHours}h (${worklogs.length} entries)\n\n`; // Group by issue for summary (more concise) const issueGroups = worklogs.reduce((acc, worklog) => { if (!acc[worklog.issueKey]) { acc[worklog.issueKey] = { totalSeconds: 0, entries: 0 }; } acc[worklog.issueKey].totalSeconds += worklog.timeSpentSeconds; acc[worklog.issueKey].entries += 1; return acc; }, {} as Record<string, { totalSeconds: number; entries: number }>); // Show summary by issue with issue summary for (const [key, data] of Object.entries(issueGroups)) { const hours = (data.totalSeconds / 3600).toFixed(1); // Get issue summary from first worklog with this key const sampleWorklog = worklogs.find(w => w.issueKey === key); const issueSummary = sampleWorklog?.issueSummary || ''; displayText += `β’ **${key}** (${issueSummary}): ${hours}h (${data.entries} entries)\n`; } // Show recent entries (limit to 100 most recent) const recentWorklogs = worklogs .sort((a, b) => b.started.localeCompare(a.started)) .slice(0, 100); if (recentWorklogs.length > 0) { displayText += `\n**Recent Entries:**\n`; for (const worklog of recentWorklogs) { // Extract date part from datetime string (handles both "2025-09-12 00:00:00.000" and "2025-09-12T00:00:00.000") const datePart = worklog.started.split(/[T\s]/)[0]; // Parse and format the human-readable date const parsedDate = parseISO(datePart); const humanReadableDate = format(parsedDate, "EEEE, MMMM do, yyyy"); // Create hybrid format: ISO date + human-readable in parentheses const formattedDate = `${datePart} (${humanReadableDate})`; const hours = (worklog.timeSpentSeconds / 3600).toFixed(1); let entryText = `β’ ${formattedDate}: **${worklog.issueKey}** (${worklog.issueSummary}) - ${hours}h - [ID: ${worklog.id}]`; if (worklog.comment && worklog.comment.trim()) { entryText += ` - "${worklog.comment}"`; } displayText += `${entryText}\n`; } } if (worklogs.length > 100) { displayText += `\n*Showing 100 most recent of ${worklogs.length} total entries*\n`; displayText += `*π‘ Tip: Use a shorter date range or specific issueKey filter for more targeted results*\n`; } } return { content: [ { type: "text", text: displayText } ], isError: false }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [ { type: "text", text: `Error retrieving worklogs: ${errorMessage}` } ], isError: true }; } }
- src/types/mcp.ts:8-12 (schema)Zod schema for validating input to the get_worklogs tool (startDate required, endDate and issueKey optional).export const GetWorklogsInputSchema = z.object({ startDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "Start date must be in YYYY-MM-DD format"), endDate: z.string().regex(/^\d{4}-\d{2}-\d{2}$/, "End date must be in YYYY-MM-DD format").optional(), issueKey: z.string().optional(), });
- src/index.ts:72-95 (registration)Tool registration in ListToolsRequestSchema handler: defines name, description, and input schema for get_worklogs.{ name: TOOL_NAMES.GET_WORKLOGS, description: "Retrieve worklogs for authenticated user and date range", inputSchema: { type: "object", properties: { startDate: { type: "string", pattern: "^\\d{4}-\\d{2}-\\d{2}$", description: "Start date in YYYY-MM-DD format", }, endDate: { type: "string", pattern: "^\\d{4}-\\d{2}-\\d{2}$", description: "End date in YYYY-MM-DD format (optional, defaults to startDate)", }, issueKey: { type: "string", description: "Optional filter by specific issue key (e.g., PROJ-1234)", }, }, required: ["startDate"], }, },
- src/index.ts:221-224 (registration)Tool execution dispatch in CallToolRequestSchema handler: parses input using schema and invokes the getWorklogs handler function.case TOOL_NAMES.GET_WORKLOGS: { const input = GetWorklogsInputSchema.parse(args); return await getWorklogs(tempoClient, input); }
- src/tools/index.ts:3-3 (helper)Re-exports the getWorklogs handler for use in src/index.ts.export { getWorklogs } from "./get-worklogs.js";