Skip to main content
Glama

log_time

Track and record time spent on tasks in ClickUp by specifying task ID, duration, and optional description. Simplify time management for project workflows.

Instructions

Log time spent on a task

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
descriptionNoOptional description
durationYesDuration (e.g., '2h 30m')
task_idYesTask ID

Implementation Reference

  • The core handler function for the 'log_time' tool. Resolves the task ID using _resolve_task_id, parses the duration string to milliseconds, builds the time entry payload, determines the workspace ID if needed, and sends a POST request to the ClickUp time_entries endpoint.
    async def log_time( self, task_id: str, duration: str, description: Optional[str] = None, ) -> Dict[str, Any]: """Log time spent on a task.""" try: # First resolve the task to get the internal ID resolved_task = await self._resolve_task_id(task_id) duration_ms = parse_duration(duration) except ClickUpAPIError as e: return {"error": f"Failed to resolve task '{task_id}': {e!s}"} # Create time entry payload = { "duration": duration_ms, "task_id": resolved_task.id, } if description: payload["description"] = description workspace_id = self.client.config.default_workspace_id if not workspace_id: workspaces = await self.client.get_workspaces() workspace_id = workspaces[0].id await self.client._request("POST", f"/team/{workspace_id}/time_entries", json=payload) return { "logged": True, "duration": duration, "duration_ms": duration_ms, "task_id": resolved_task.id, }
  • The input schema definition for the 'log_time' tool, defining parameters task_id (required string), duration (required string), and optional description.
    Tool( name="log_time", description="Log time spent on a task", inputSchema={ "type": "object", "properties": { "task_id": {"type": "string", "description": "Task ID"}, "duration": {"type": "string", "description": "Duration (e.g., '2h 30m')"}, "description": {"type": "string", "description": "Optional description"}, }, "required": ["task_id", "duration"], }, ),
  • Registration of the log_time handler method in the ClickUpTools._tools dictionary, mapping the tool name to its implementation function.
    self._tools: Dict[str, Callable] = { "create_task": self.create_task, "get_task": self.get_task, "update_task": self.update_task, "delete_task": self.delete_task, "list_tasks": self.list_tasks, "search_tasks": self.search_tasks, "get_subtasks": self.get_subtasks, "get_task_comments": self.get_task_comments, "create_task_comment": self.create_task_comment, "get_task_status": self.get_task_status, "update_task_status": self.update_task_status, "get_assignees": self.get_assignees, "assign_task": self.assign_task, "list_spaces": self.list_spaces, "list_folders": self.list_folders, "list_lists": self.list_lists, "find_list_by_name": self.find_list_by_name, # Bulk operations "bulk_update_tasks": self.bulk_update_tasks, "bulk_move_tasks": self.bulk_move_tasks, # Time tracking "get_time_tracked": self.get_time_tracked, "log_time": self.log_time, # Templates "create_task_from_template": self.create_task_from_template, "create_task_chain": self.create_task_chain, # Analytics "get_team_workload": self.get_team_workload, "get_task_analytics": self.get_task_analytics, # User management "list_users": self.list_users, "get_current_user": self.get_current_user, "find_user_by_name": self.find_user_by_name, }
  • MCP server registration of tool handlers. list_tools returns definitions including log_time schema; call_tool dispatches to tools.call_tool for execution.
    @self.server.list_tools() async def list_tools() -> List[Tool]: """List all available tools.""" return self.tools.get_tool_definitions() @self.server.call_tool() async def call_tool( name: str, arguments: Optional[Dict[str, Any]] = None ) -> List[TextContent | ImageContent | EmbeddedResource]: """Call a specific tool.""" logger.debug(f"Calling tool: {name} with arguments: {arguments}") try: result = await self.tools.call_tool(name, arguments or {}) return [TextContent(type="text", text=result)] except Exception as e: logger.error(f"Error calling tool {name}: {e}", exc_info=True) return [TextContent(type="text", text=f"Error: {e!s}")]
  • Utility function parse_duration used by log_time to convert human-readable duration strings (e.g., '2h 30m') to milliseconds for the API payload.
    def parse_duration(duration_str: str) -> int: """ Parse duration string to milliseconds. Examples: - "1h" -> 3600000 - "30m" -> 1800000 - "1h 30m" -> 5400000 - "90m" -> 5400000 """ duration_str = duration_str.strip().lower() total_ms = 0 # Match hours hours_match = re.search(r"(\d+)\s*h", duration_str) if hours_match: total_ms += int(hours_match.group(1)) * 60 * 60 * 1000 # Match minutes minutes_match = re.search(r"(\d+)\s*m", duration_str) if minutes_match: total_ms += int(minutes_match.group(1)) * 60 * 1000 # If no unit specified, assume minutes if not hours_match and not minutes_match: try: total_ms = int(duration_str) * 60 * 1000 except ValueError as e: raise ValueError(f"Invalid duration format: {duration_str}") from e return total_ms

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/DiversioTeam/clickup-mcp'

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