Skip to main content
Glama

gmail_daily_summary

Summarize recent Gmail emails by category, showing unread counts and top messages in Navy, Kids, Financial, and Action Items categories.

Instructions

Generate a summary of recent emails organized by category. Shows unread counts and top emails in each category (Navy, Kids, Financial, Action Items).

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
hoursNoHow many hours back to look for emails. Default is 24 hours.
include_readNoWhether to include already-read emails. Default is false (unread only).

Implementation Reference

  • Core handler function in GmailClient that fetches recent emails within the specified hours, categorizes them using configured rules, limits per category, sorts by priority, and returns a structured DailySummary.
    async def get_daily_summary(
        self, lookback_hours: Optional[int] = None, include_read: bool = False
    ) -> DailySummary:
        """Generate a daily email summary organized by category."""
        if lookback_hours is None:
            lookback_hours = self.categories.summary_settings.get("daily_lookback_hours", 24)
    
        max_per_category = self.categories.summary_settings.get("max_per_category", 10)
        if include_read is None:
            include_read = self.categories.summary_settings.get("include_read", False)
    
        now = datetime.now(timezone.utc)
        period_start = now - timedelta(hours=lookback_hours)
    
        # Search for recent emails
        search = SearchQuery(
            after_date=period_start,
            is_unread=None if include_read else True,
            max_results=100,
        )
    
        all_emails = await self.list_emails(search)
    
        # Organize by category
        categorized: dict[str, list[EmailSummary]] = {
            cat_key: [] for cat_key in self.categories.categories.keys()
        }
        uncategorized: list[EmailSummary] = []
    
        for email in all_emails:
            if email.categories:
                for cat in email.categories:
                    if cat in categorized:
                        categorized[cat].append(email)
            else:
                uncategorized.append(email)
    
        # Build category summaries
        category_summaries = []
        for cat_key, category in self.categories.categories.items():
            emails = categorized.get(cat_key, [])[:max_per_category]
            if emails:
                category_summaries.append(
                    CategorySummary(
                        category_key=cat_key,
                        category_name=category.name,
                        priority=category.priority,
                        total_count=len(categorized.get(cat_key, [])),
                        unread_count=sum(1 for e in categorized.get(cat_key, []) if not e.is_read),
                        emails=emails,
                    )
                )
    
        # Sort by priority
        priority_order = {"critical": 0, "high": 1, "normal": 2, "low": 3}
        category_summaries.sort(key=lambda c: priority_order.get(c.priority, 2))
    
        return DailySummary(
            generated_at=now,
            period_start=period_start,
            period_end=now,
            total_emails=len(all_emails),
            unread_emails=sum(1 for e in all_emails if not e.is_read),
            categories=category_summaries,
            uncategorized=uncategorized[:max_per_category],
        )
  • Tool schema definition including input schema with optional 'hours' and 'include_read' parameters for the gmail_daily_summary tool.
        name="gmail_daily_summary",
        description="Generate a daily summary of emails organized by category "
        "(Navy, Kids, Financial, Action Items)",
        inputSchema={
            "type": "object",
            "properties": {
                "hours": {
                    "type": "integer",
                    "description": "How many hours back to look (default: 24)",
                    "default": 24,
                },
                "include_read": {
                    "type": "boolean",
                    "description": "Include already read emails (default: false)",
                    "default": False,
                },
            },
        },
    ),
  • Tool dispatch/registration in the MCP server's call_tool handler that extracts arguments, calls GmailClient.get_daily_summary, formats the result, and returns TextContent.
    elif name == "gmail_daily_summary":
        hours = arguments.get("hours", 24)
        include_read = arguments.get("include_read", False)
        summary = await client.get_daily_summary(hours, include_read)
        return [
            TextContent(
                type="text",
                text=_format_daily_summary(summary),
            )
        ]
  • Helper function to format the DailySummary object into a human-readable markdown string for the tool response.
    def _format_daily_summary(summary) -> str:
        """Format daily summary for display."""
        lines = [
            f"# 📧 Daily Email Summary",
            f"**Period:** {summary.period_start.strftime('%Y-%m-%d %H:%M')} to {summary.period_end.strftime('%Y-%m-%d %H:%M')}",
            f"**Total Emails:** {summary.total_emails} ({summary.unread_emails} unread)",
            "",
        ]
    
        for cat in summary.categories:
            priority_icon = {"critical": "🔴", "high": "🟠", "normal": "🟢", "low": "⚪"}.get(
                cat.priority, "🟢"
            )
            lines.append(f"\n## {priority_icon} {cat.category_name} ({cat.unread_count} unread)")
    
            for email in cat.emails[:5]:
                lines.append(f"- **{email.subject}** - {email.sender.email}")
                lines.append(f"  {email.snippet[:80]}...")
    
            if cat.total_count > 5:
                lines.append(f"  _...and {cat.total_count - 5} more_")
    
        if summary.uncategorized:
            lines.append(f"\n## 📋 Other ({len(summary.uncategorized)} emails)")
            for email in summary.uncategorized[:5]:
                lines.append(f"- **{email.subject}** - {email.sender.email}")
    
        return "\n".join(lines)
Behavior2/5

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

With no annotations provided, the description carries the full burden of behavioral disclosure. It mentions 'shows unread counts and top emails' but doesn't specify what 'top emails' means (e.g., by recency, importance), whether this is a read-only operation, if it requires authentication, or any rate limits. For a tool that processes email data, this leaves critical behavioral aspects undocumented.

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

Conciseness4/5

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

The description is concise and front-loaded, stating the core purpose in the first sentence. The second sentence adds useful detail about the summary content. Both sentences earn their place by clarifying the tool's output, though it could be slightly more structured (e.g., explicitly separating purpose from features).

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

Completeness2/5

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

Given the complexity of email summarization, no annotations, and no output schema, the description is incomplete. It doesn't explain the return format (e.g., structured data vs. text), how categories are determined, or what 'top emails' entails. For a tool with behavioral nuances and no structured output documentation, this leaves significant gaps for the agent.

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 both parameters (hours and include_read). The description adds no parameter-specific information beyond what's in the schema, such as how hours affects categorization or the implications of include_read. With high schema coverage, the baseline score of 3 is appropriate as the description doesn't enhance parameter understanding.

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 tool's purpose: 'Generate a summary of recent emails organized by category' with specific categories listed (Navy, Kids, Financial, Action Items). It distinguishes from siblings like gmail_list_unread or gmail_inbox_stats by focusing on categorized summaries rather than raw lists or statistics. However, it doesn't explicitly differentiate from gmail_category_summary, which appears similar.

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

Usage Guidelines2/5

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

The description provides no guidance on when to use this tool versus alternatives. It doesn't mention when to choose this over gmail_category_summary, gmail_inbox_stats, or gmail_list_unread, nor does it specify prerequisites or exclusions. The lack of usage context leaves the agent guessing about appropriate scenarios.

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/murphy360/mcp_gmail'

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