Skip to main content
Glama

get_hourly_productivity

Analyze hourly productivity patterns to identify peak performance times and schedule focused work sessions effectively.

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
NameRequiredDescriptionDefault
date_strNotoday

Implementation Reference

  • Implements the get_hourly_productivity tool using @mcp.tool() decorator. Resolves date, fetches hourly data via RescueTimeClient, aggregates by hour, computes weighted productivity, and formats a visual hourly breakdown with bars and peak summary.
    @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}"
  • Pydantic BaseModel HourlyData defines the structure for hourly productivity data used by the tool's client method.
    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
  • RescueTimeClient.get_hourly_data() method fetches raw hourly productivity data from RescueTime API using interval perspective, parses rows into HourlyData objects.
    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
  • resolve_date() utility function converts 'today'/'yesterday' to ISO date strings, used in the tool.
    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

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/JasonBates/rescuetime-mcp'

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