Skip to main content
Glama

analyze_meeting_patterns

Analyze across meetings to identify patterns in topics, participants, and frequency. Apply optional date range filters to focus on specific time periods.

Instructions

Analyze patterns across multiple meetings

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
pattern_typeYesType of pattern to analyze (topics, participants, frequency)
date_rangeNoOptional date range for analysis

Implementation Reference

  • Main handler for analyze_meeting_patterns - dispatches to sub-handlers based on pattern_type (participants, frequency, topics)
    async def _analyze_meeting_patterns(self, pattern_type: str, date_range: Optional[Dict] = None) -> List[TextContent]:
        """Analyze patterns across meetings."""
        if not self.cache_data:
            return [TextContent(type="text", text="No meeting data available")]
        
        meetings = list(self.cache_data.meetings.values())
        
        # Filter by date range if provided
        if date_range:
            start_date_str = date_range.get("start_date", "1900-01-01")
            end_date_str = date_range.get("end_date", "2100-01-01")
            
            # Parse dates and ensure timezone-aware
            naive_start = datetime.fromisoformat(start_date_str)
            naive_end = datetime.fromisoformat(end_date_str)
            
            # Localize naive datetimes to UTC
            if naive_start.tzinfo is None:
                start_date = naive_start.replace(tzinfo=zoneinfo.ZoneInfo('UTC'))
            else:
                start_date = naive_start
                
            if naive_end.tzinfo is None:
                end_date = naive_end.replace(tzinfo=zoneinfo.ZoneInfo('UTC'))
            else:
                end_date = naive_end
                
            meetings = [m for m in meetings if start_date <= m.date <= end_date]
        
        if pattern_type == "participants":
            return await self._analyze_participant_patterns(meetings)
        elif pattern_type == "frequency":
            return await self._analyze_frequency_patterns(meetings)
        elif pattern_type == "topics":
            return await self._analyze_topic_patterns(meetings)
        else:
            return [TextContent(type="text", text=f"Unknown pattern type: {pattern_type}")]
  • Sub-handler for participant pattern analysis - counts meetings per participant
    async def _analyze_participant_patterns(self, meetings: List[MeetingMetadata]) -> List[TextContent]:
        """Analyze participant patterns."""
        participant_counts = {}
        
        for meeting in meetings:
            for participant in meeting.participants:
                participant_counts[participant] = participant_counts.get(participant, 0) + 1
        
        if not participant_counts:
            return [TextContent(type="text", text="No participant data found")]
        
        sorted_participants = sorted(participant_counts.items(), key=lambda x: x[1], reverse=True)
        
        output = [
            f"# Participant Analysis ({len(meetings)} meetings)\n",
            "## Most Active Participants\n"
        ]
        
        for participant, count in sorted_participants[:10]:
            output.append(f"• **{participant}:** {count} meetings")
        
        return [TextContent(type="text", text="\n".join(output))]
  • Sub-handler for frequency pattern analysis - groups meetings by month
    async def _analyze_frequency_patterns(self, meetings: List[MeetingMetadata]) -> List[TextContent]:
        """Analyze meeting frequency patterns."""
        if not meetings:
            return [TextContent(type="text", text="No meetings found for analysis")]
        
        # Group by month
        monthly_counts = {}
        for meeting in meetings:
            month_key = meeting.date.strftime("%Y-%m")
            monthly_counts[month_key] = monthly_counts.get(month_key, 0) + 1
        
        output = [
            f"# Meeting Frequency Analysis ({len(meetings)} meetings)\n",
            "## Meetings by Month\n"
        ]
        
        for month, count in sorted(monthly_counts.items()):
            output.append(f"• **{month}:** {count} meetings")
        
        avg_per_month = len(meetings) / len(monthly_counts) if monthly_counts else 0
        output.append(f"\n**Average per month:** {avg_per_month:.1f}")
        
        return [TextContent(type="text", text="\n".join(output))]
  • Sub-handler for topic pattern analysis - keyword extraction from meeting titles
    async def _analyze_topic_patterns(self, meetings: List[MeetingMetadata]) -> List[TextContent]:
        """Analyze topic patterns from meeting titles."""
        if not meetings:
            return [TextContent(type="text", text="No meetings found for analysis")]
        
        # Simple keyword extraction from titles
        word_counts = {}
        for meeting in meetings:
            words = meeting.title.lower().split()
            for word in words:
                # Filter out common words
                if len(word) > 3 and word not in ['meeting', 'call', 'sync', 'with']:
                    word_counts[word] = word_counts.get(word, 0) + 1
        
        if not word_counts:
            return [TextContent(type="text", text="No significant topics found in meeting titles")]
        
        sorted_topics = sorted(word_counts.items(), key=lambda x: x[1], reverse=True)
        
        output = [
            f"# Topic Analysis ({len(meetings)} meetings)\n",
            "## Most Common Topics (from titles)\n"
        ]
        
        for topic, count in sorted_topics[:15]:
            output.append(f"• **{topic}:** {count} mentions")
        
        return [TextContent(type="text", text="\n".join(output))]
  • Tool registration with name and inputSchema (pattern_type enum, optional date_range)
    Tool(
        name="analyze_meeting_patterns",
        description="Analyze patterns across multiple meetings",
        inputSchema={
            "type": "object",
            "properties": {
                "pattern_type": {
                    "type": "string",
                    "description": "Type of pattern to analyze (topics, participants, frequency)",
                    "enum": ["topics", "participants", "frequency"]
                },
                "date_range": {
                    "type": "object",
                    "properties": {
                        "start_date": {"type": "string", "format": "date"},
                        "end_date": {"type": "string", "format": "date"}
                    },
                    "description": "Optional date range for analysis"
                }
            },
            "required": ["pattern_type"]
        }
    )
  • Call-tool dispatch routing 'analyze_meeting_patterns' to the handler method
    elif name == "analyze_meeting_patterns":
        return await self._analyze_meeting_patterns(
            pattern_type=arguments["pattern_type"],
            date_range=arguments.get("date_range")
        )
Behavior2/5

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

With no annotations, the description should disclose behavioral traits like read-only nature or response behavior. It does not add any such information beyond the tool's name.

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, but it is minimal. It could benefit from a bit more detail without being verbose.

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?

Despite complete schema coverage, the description lacks context about output, behavior, and proper usage. For a tool with nested objects and no output schema, more information is needed.

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 coverage is 100%, so baseline is 3. The description adds no additional meaning to the parameters beyond what the schema provides.

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 function of analyzing patterns across meetings, which distinguishes it from sibling tools that retrieve individual meeting details or documents. However, it could be more specific about what patterns are analyzed.

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?

No guidance is provided on when to use this tool versus alternatives. The description does not mention prerequisites, context, or when not to use it.

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/maxgerlach1/granola-ai-mcp-server'

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