get_hourly_productivity
Analyze hourly productivity patterns to identify peak performance times and optimize work scheduling for better focus.
Instructions
Get productivity breakdown by hour.
Args: date_str: Date to query - 'today', 'yesterday', or 'YYYY-MM-DD'
Shows when during the day you were most/least productive. Useful for identifying peak productivity hours and scheduling deep work.
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| date_str | No | today |
Implementation Reference
- src/rescuetime_mcp/server.py:243-314 (handler)The core handler function for the 'get_hourly_productivity' tool. Decorated with @mcp.tool() for automatic registration and schema inference from type hints. Fetches hourly data using RescueTimeClient, aggregates by hour, computes weighted productivity scores, generates visual bars and indicators, and formats a detailed hourly breakdown report.@mcp.tool() async def get_hourly_productivity(date_str: str = "today") -> str: """Get productivity breakdown by hour. Args: date_str: Date to query - 'today', 'yesterday', or 'YYYY-MM-DD' Shows when during the day you were most/least productive. Useful for identifying peak productivity hours and scheduling deep work. """ try: client = RescueTimeClient() resolved_date = resolve_date(date_str) hourly = await client.get_hourly_data( restrict_begin=resolved_date, restrict_end=resolved_date, ) if not hourly: return f"No hourly data for {resolved_date}." lines = [f"Hourly Productivity ({resolved_date}):", ""] # Group by hour and find the peak hour_data = {} for h in hourly: if h.hour not in hour_data: hour_data[h.hour] = {"seconds": 0, "productivity_sum": 0, "count": 0} hour_data[h.hour]["seconds"] += h.time_seconds hour_data[h.hour]["productivity_sum"] += h.productivity * h.time_seconds hour_data[h.hour]["count"] += 1 if not hour_data: return f"No hourly data for {resolved_date}." # Display each hour for hour in sorted(hour_data.keys()): data = hour_data[hour] mins = data["seconds"] / 60 if mins < 1: continue # Weighted average productivity avg_prod = data["productivity_sum"] / data["seconds"] if data["seconds"] > 0 else 0 # Visual representation bar_len = min(int(mins / 6), 10) # 60 mins = 10 blocks bar = "\u2588" * bar_len + "\u2591" * (10 - bar_len) # Productivity indicator prod_char = { 2: "++", 1: "+ ", 0: " ", -1: " -", -2: "--" }.get(round(avg_prod), " ") hour_str = f"{hour:02d}:00" lines.append(f"{hour_str} [{prod_char}] {bar} {mins:.0f}m") # Summary total_mins = sum(d["seconds"] for d in hour_data.values()) / 60 if hour_data: peak_hour = max(hour_data.keys(), key=lambda h: hour_data[h]["seconds"]) lines.append("") lines.append(f"Peak hour: {peak_hour:02d}:00 ({hour_data[peak_hour]['seconds']/60:.0f}m)") lines.append(f"Total: {total_mins:.0f} minutes logged") return "\n".join(lines) except RescueTimeAuthError as e: return f"Authentication error: {e}" except RescueTimeAPIError as e: return f"API error: {e}"
- src/rescuetime_mcp/client.py:146-189 (helper)Supporting method in RescueTimeClient that queries the RescueTime API for hourly productivity interval data and parses the response into HourlyData model instances. Called directly by the tool handler.async def get_hourly_data( self, restrict_begin: Optional[str] = None, restrict_end: Optional[str] = None, ) -> list[HourlyData]: """Get hourly productivity breakdown. Args: restrict_begin: Start date (YYYY-MM-DD), defaults to today restrict_end: End date (YYYY-MM-DD), defaults to today """ today = date.today().isoformat() params = { "perspective": "interval", "resolution_time": "hour", "restrict_kind": "productivity", "restrict_begin": restrict_begin or today, "restrict_end": restrict_end or today, } data = await self._request("data", params) if not data or "rows" not in data: return [] hourly = [] for row in data["rows"]: # Row format for interval: [date, time_seconds, num_people, productivity] # Date is like "2024-01-15T14:00:00" date_str = row[0] hour = int(date_str.split("T")[1].split(":")[0]) date_part = date_str.split("T")[0] hourly.append( HourlyData( hour=hour, date=date_part, time_seconds=row[1], productivity=row[3] if len(row) > 3 else 0, ) ) return hourly
- src/rescuetime_mcp/models.py:79-91 (schema)Pydantic model used to validate and structure the hourly data returned from the RescueTime API, providing type safety and convenience properties for the tool implementation.class HourlyData(BaseModel): """Hourly productivity data from interval perspective.""" hour: int # 0-23 date: str time_seconds: int productivity: int @property def time_minutes(self) -> float: """Time in minutes.""" return self.time_seconds / 60
- src/rescuetime_mcp/server.py:36-43 (helper)Utility function used by the tool handler (and others) to resolve human-readable date strings like 'today' into ISO date formats required by the API.def resolve_date(date_str: str) -> str: """Resolve 'today', 'yesterday', or return as-is.""" if date_str.lower() == "today": return date.today().isoformat() elif date_str.lower() == "yesterday": return (date.today() - timedelta(days=1)).isoformat() return date_str