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",
Behavior2/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

No annotations are provided, so the description carries full burden. It states 'Create a new worklog entry,' which implies a write/mutation operation, but doesn't disclose behavioral traits like required permissions, whether it's idempotent, error handling, or rate limits. The mention of 'get_schedule' hints at prerequisites but isn't comprehensive.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is two sentences, front-loaded with the core purpose and followed by a helpful usage tip. Every sentence adds value with zero waste, making it efficient and well-structured.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness3/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given no annotations and no output schema, the description is incomplete for a mutation tool. It covers the basic purpose and a usage tip but lacks details on behavioral traits, error cases, or return values. This is adequate but has clear gaps, fitting a minimum viable score.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so the schema fully documents all 6 parameters. The description adds no parameter-specific information beyond what's in the schema, such as explaining relationships between parameters (e.g., how startDate and endDate interact). Baseline 3 is appropriate when schema does all the work.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose4/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description clearly states the action ('Create a new worklog entry') and resource ('worklog'), which is specific and unambiguous. However, it doesn't explicitly differentiate from sibling tools like 'bulk_post_worklogs' or 'delete_worklog', which would be needed for a perfect score.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

The description provides explicit guidance to 'consider using get_schedule first to verify working days and expected hours,' which gives clear context for when to use this tool. However, it doesn't specify when NOT to use it or mention alternatives like 'bulk_post_worklogs' for multiple entries, which would be required for a top score.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Install Server

Other Tools

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