Skip to main content
Glama
TRANZACT

Tempo Filler MCP Server

Official
by TRANZACT

post_worklog

Log work hours in JIRA Tempo by creating time entries with issue keys, dates, and descriptions for accurate time tracking.

Instructions

Create a new worklog entry. For better results, consider using get_schedule first to verify working days and expected hours.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
issueKeyYesJIRA issue key (e.g., PROJ-1234)
hoursYesHours worked (decimal)
startDateYesStart date in YYYY-MM-DD format
endDateNoEnd date in YYYY-MM-DD format (optional, defaults to startDate)
billableNoWhether the time is billable (default: true)
descriptionNoWork description (optional)

Implementation Reference

  • The postWorklog function implementing the core tool logic: parses input, creates Tempo worklog payload, calls API, handles response and errors with formatted markdown output.
    export async function postWorklog(
      tempoClient: TempoClient,
      input: PostWorklogInput
    ): Promise<CallToolResult> {
      try {
        const { 
          issueKey, 
          hours, 
          startDate, 
          endDate, 
          billable = true, 
          description 
        } = input;
    
        // Create the worklog payload using the Tempo client (automatically uses authenticated user)
        const payload = await tempoClient.createWorklogPayload({
          issueKey,
          hours,
          startDate,
          endDate,
          billable,
          description
        });
    
        // Create the worklog
        const worklogResponse = await tempoClient.createWorklog(payload);
    
        // Handle the response - API returns an array with a single worklog object
        const worklog = Array.isArray(worklogResponse) ? worklogResponse[0] : worklogResponse;
    
        // Format success response
        const actualEndDate = endDate || startDate;
        const billableHours = billable ? hours : 0;
        
        let displayText = `## Worklog Created Successfully\n\n`;
        displayText += `**Issue:** ${issueKey} - ${worklog.issue.summary}\n`;
        displayText += `**Hours:** ${hours}h`;
        if (billableHours !== hours) {
          displayText += ` (${billableHours}h billable)`;
        }
        displayText += `\n`;
        displayText += `**Date:** ${startDate}`;
        if (actualEndDate !== startDate) {
          displayText += ` to ${actualEndDate}`;
        }
        displayText += `\n`;
        
        if (description) {
          displayText += `**Description:** ${description}\n`;
        }
        
        displayText += `**Worklog ID:** ${worklog.tempoWorklogId || worklog.id}\n`;
        displayText += `**Time Spent:** ${worklog.timeSpent}\n`;
        
        // Add some helpful information
        displayText += `\n### Details\n`;
        displayText += `- Created at: ${new Date().toISOString()}\n`;
        displayText += `- Total seconds: ${worklog.timeSpentSeconds}\n`;
        displayText += `- Billable seconds: ${worklog.billableSeconds}\n`;
        
        return {
          content: [
            {
              type: "text",
              text: displayText
            }
          ],
          isError: false
        };
    
      } catch (error) {
        let errorMessage = error instanceof Error ? error.message : String(error);
        
        // Provide more helpful error messages for common issues
        if (errorMessage.includes('not found')) {
          errorMessage += `\n\nTip: Make sure the issue key '${input.issueKey}' exists and you have access to it.`;
        } else if (errorMessage.includes('Authentication failed')) {
          errorMessage += `\n\nTip: Check your Personal Access Token (PAT) in the TEMPO_PAT environment variable.`;
        } else if (errorMessage.includes('Access forbidden')) {
          errorMessage += `\n\nTip: Make sure you have permission to log time to this issue and that Tempo is properly configured.`;
        }
        
        return {
          content: [
            {
              type: "text",
              text: `## Error Creating Worklog\n\n**Issue:** ${input.issueKey}\n**Hours:** ${input.hours}\n**Date:** ${input.startDate}\n\n**Error:** ${errorMessage}`
            }
          ],
          isError: true
        };
      }
    }
  • Zod schema defining input validation for post_worklog tool parameters.
    export const PostWorklogInputSchema = z.object({
      issueKey: z.string().min(1, "Issue key is required"),
      hours: z.number().min(0.1, "Hours must be at least 0.1").max(24, "Hours cannot exceed 24"),
      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(),
      billable: z.boolean().optional(),
      description: z.string().optional(),
    });
  • src/index.ts:226-229 (registration)
    MCP server registration: handles execution of post_worklog tool by parsing input schema and calling the handler function.
    case TOOL_NAMES.POST_WORKLOG: {
      const input = PostWorklogInputSchema.parse(args);
      return await postWorklog(tempoClient, input);
    }
  • src/index.ts:97-133 (registration)
    MCP server registration: declares post_worklog tool metadata including name, description, and input schema for ListTools requests.
      name: TOOL_NAMES.POST_WORKLOG,
      description: "Create a new worklog entry. For better results, consider using get_schedule first to verify working days and expected hours.",
      inputSchema: {
        type: "object",
        properties: {
          issueKey: {
            type: "string",
            description: "JIRA issue key (e.g., PROJ-1234)",
          },
          hours: {
            type: "number",
            minimum: 0.1,
            maximum: 24,
            description: "Hours worked (decimal)",
          },
          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)",
          },
          billable: {
            type: "boolean",
            description: "Whether the time is billable (default: true)",
          },
          description: {
            type: "string",
            description: "Work description (optional)",
          },
        },
        required: ["issueKey", "hours", "startDate"],
      },
    },
  • Tool name constant used for registration and identification.
    POST_WORKLOG: "post_worklog",

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/TRANZACT/tempo-filler-mcp-server'

If you have feedback or need assistance with the MCP directory API, please join our Discord server