Skip to main content
Glama

get_recent_messages

Retrieve recent Microsoft Teams messages with filters for time, scope, users, attachments, importance, and keywords to find specific conversations.

Instructions

Get recent messages from across Teams with advanced filtering options. Can filter by time range, scope (channels vs chats), teams, channels, and users.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
hoursNoGet messages from the last N hours (max 168 = 1 week)
limitNoMaximum number of messages to return
mentionsUserNoFilter messages that mention this user ID
fromUserNoFilter messages from this user ID
hasAttachmentsNoFilter messages with attachments
importanceNoFilter by message importance
includeChannelsNoInclude channel messages
includeChatsNoInclude chat messages
teamIdsNoSpecific team IDs to search in
keywordsNoKeywords to search for in message content

Implementation Reference

  • The main execution logic for the 'get_recent_messages' tool. It attempts to use the Microsoft Graph Search API for advanced filtering (keywords, mentions, attachments, importance) and falls back to direct queries on user chats if the search results are poor quality or fail. Supports filtering by time (hours), limit, users, attachments, importance, channels/chats inclusion, teams, and keywords. Returns formatted JSON with message details.
    async ({ hours, limit, mentionsUser, fromUser, hasAttachments, importance, includeChannels, includeChats, teamIds, keywords, }) => { try { const client = await graphService.getClient(); let attemptedAdvancedSearch = false; // Try using the Search API first for rich filtering if (keywords || mentionsUser || hasAttachments !== undefined || importance) { attemptedAdvancedSearch = true; // Calculate the date threshold const since = new Date(Date.now() - hours * 60 * 60 * 1000).toISOString(); // Build KQL query for Microsoft Search API const queryParts: string[] = []; // Add time filter - use a more permissive date format queryParts.push(`sent>=${since.split("T")[0]}`); // Use just the date part // Add user filters if (mentionsUser) { queryParts.push(`mentions:${mentionsUser}`); } if (fromUser) { queryParts.push(`from:${fromUser}`); } // Add content filters if (hasAttachments !== undefined) { queryParts.push(`hasAttachment:${hasAttachments}`); } if (importance) { queryParts.push(`importance:${importance}`); } // Add keyword search if (keywords) { queryParts.push(`"${keywords}"`); } // If no specific filters, search for all recent messages if (queryParts.length === 1) { // Only has the time filter queryParts.push("*"); // Match all messages } const searchQuery = queryParts.join(" AND "); const searchRequest: SearchRequest = { entityTypes: ["chatMessage"], query: { queryString: searchQuery, }, from: 0, size: Math.min(limit, 100), enableTopResults: false, // For recent messages, prefer chronological order }; try { const response = (await client .api("/search/query") .post({ requests: [searchRequest] })) as SearchResponse; if (response?.value?.length && response.value[0]?.hitsContainers?.length) { const hits = response.value[0].hitsContainers[0].hits; const recentMessages = hits .filter((hit) => { // Apply scope filters const isChannelMessage = hit.resource.channelIdentity?.channelId; const isChatMessage = hit.resource.chatId && !isChannelMessage; if (!includeChannels && isChannelMessage) return false; if (!includeChats && isChatMessage) return false; // Apply team filter if specified if (teamIds?.length && isChannelMessage) { return teamIds.includes(hit.resource.channelIdentity?.teamId || ""); } return true; }) .map((hit: SearchHit) => ({ id: hit.resource.id, content: hit.resource.body?.content || "No content", from: hit.resource.from?.user?.displayName || "Unknown", fromUserId: hit.resource.from?.user?.id, createdDateTime: hit.resource.createdDateTime, chatId: hit.resource.chatId, teamId: hit.resource.channelIdentity?.teamId, channelId: hit.resource.channelIdentity?.channelId, type: hit.resource.channelIdentity?.channelId ? "channel" : "chat", })) .slice(0, limit); // Apply final limit after filtering // Check if Search API returned poor quality results (No content/Unknown) const poorQualityResults = recentMessages.filter( (msg) => msg.content === "No content" || msg.from === "Unknown" ).length; const qualityThreshold = 0.5; // If more than 50% of results are poor quality, fall back if ( recentMessages.length > 0 && poorQualityResults / recentMessages.length > qualityThreshold ) { console.log( "Search API returned poor quality results, falling back to direct queries" ); // Fall through to direct chat queries } else { return { content: [ { type: "text", text: JSON.stringify( { method: "search_api", timeRange: `Last ${hours} hours`, filters: { mentionsUser, fromUser, hasAttachments, importance, keywords, }, totalFound: recentMessages.length, messages: recentMessages, }, null, 2 ), }, ], }; } } } catch (searchError) { console.error("Search API failed, falling back to direct queries:", searchError); } } // Fallback: Get recent messages from user's chats directly // This method is more reliable but doesn't support advanced filtering const chatsResponse = await client.api("/me/chats?$expand=members").get(); const chats = chatsResponse?.value || []; const allMessages: Array<{ id: string; content: string; from: string; fromUserId?: string; createdDateTime: string; chatId: string; type: string; }> = []; const since = new Date(Date.now() - hours * 60 * 60 * 1000); // Get recent messages from each chat for (const chat of chats.slice(0, 10)) { // Limit to first 10 chats to avoid rate limits try { let queryString = `$top=${Math.min(limit, 50)}&$orderby=createdDateTime desc`; // Apply user filter if specified if (fromUser) { queryString += `&$filter=from/user/id eq '${fromUser}'`; } const messagesResponse = await client .api(`/me/chats/${chat.id}/messages?${queryString}`) .get(); const messages = messagesResponse?.value || []; for (const message of messages) { // Filter by time if (message.createdDateTime) { const messageDate = new Date(message.createdDateTime); if (messageDate < since) continue; } // Apply scope filter for chats if (!includeChats) { continue; // Skip chat messages if includeChats is false } // Apply keyword filter (simple text search) if ( keywords && message.body?.content && !message.body.content.toLowerCase().includes(keywords.toLowerCase()) ) { continue; } allMessages.push({ id: message.id || "", content: message.body?.content || "No content", from: message.from?.user?.displayName || "Unknown", fromUserId: message.from?.user?.id, createdDateTime: message.createdDateTime || "", chatId: message.chatId || "", type: "chat", }); if (allMessages.length >= limit) break; } if (allMessages.length >= limit) break; } catch (chatError) { console.error(`Error getting messages from chat ${chat.id}:`, chatError); } } // Sort by creation date (newest first) allMessages.sort( (a, b) => new Date(b.createdDateTime).getTime() - new Date(a.createdDateTime).getTime() ); return { content: [ { type: "text", text: JSON.stringify( { method: attemptedAdvancedSearch ? "direct_chat_queries_fallback" : "direct_chat_queries", timeRange: `Last ${hours} hours`, filters: { mentionsUser, fromUser, hasAttachments, importance, keywords, }, note: attemptedAdvancedSearch ? "Search API returned poor quality results, using direct chat queries as fallback" : "Using direct chat queries for better content reliability", totalFound: allMessages.slice(0, limit).length, messages: allMessages.slice(0, limit), }, null, 2 ), }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; return { content: [ { type: "text", text: `❌ Error getting recent messages: ${errorMessage}`, }, ], }; } }
  • Zod schema defining input parameters for the tool: hours (1-168, default 24), limit (1-100, default 50), mentionsUser, fromUser, hasAttachments, importance (low/normal/high/urgent), includeChannels (default true), includeChats (default true), teamIds array, keywords.
    { hours: z .number() .min(1) .max(168) .optional() .default(24) .describe("Get messages from the last N hours (max 168 = 1 week)"), limit: z .number() .min(1) .max(100) .optional() .default(50) .describe("Maximum number of messages to return"), mentionsUser: z.string().optional().describe("Filter messages that mention this user ID"), fromUser: z.string().optional().describe("Filter messages from this user ID"), hasAttachments: z.boolean().optional().describe("Filter messages with attachments"), importance: z .enum(["low", "normal", "high", "urgent"]) .optional() .describe("Filter by message importance"), includeChannels: z.boolean().optional().default(true).describe("Include channel messages"), includeChats: z.boolean().optional().default(true).describe("Include chat messages"), teamIds: z.array(z.string()).optional().describe("Specific team IDs to search in"), keywords: z.string().optional().describe("Keywords to search for in message content"), },
  • Registration of the 'get_recent_messages' tool using server.tool(), including name, description, schema, and handler function.
    server.tool( "get_recent_messages", "Get recent messages from across Teams with advanced filtering options. Can filter by time range, scope (channels vs chats), teams, channels, and users.",

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/floriscornel/teams-mcp'

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