Skip to main content
Glama

search_messages

Find messages in Microsoft Teams by searching across channels and chats using KQL queries for sender, mentions, attachments, and other filters.

Instructions

Search for messages across all Microsoft Teams channels and chats using Microsoft Search API. Supports advanced KQL syntax for filtering by sender, mentions, attachments, and more.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
queryYesSearch query. Supports KQL syntax like 'from:user mentions:userId hasAttachment:true'
scopeNoScope of searchall
limitNoNumber of results to return
enableTopResultsNoEnable relevance-based ranking

Implementation Reference

  • The handler function that implements the core logic of the 'search_messages' tool. It constructs a SearchRequest for Microsoft Graph's /search/query endpoint, applies scope filters, processes search hits into results, and returns formatted JSON output or error messages.
    async ({ query, scope, limit, enableTopResults }) => { try { const client = await graphService.getClient(); // Build the search request const searchRequest: SearchRequest = { entityTypes: ["chatMessage"], query: { queryString: query, }, from: 0, size: limit, enableTopResults, }; // Add scope-specific filters to the query if needed let enhancedQuery = query; if (scope === "channels") { enhancedQuery = `${query} AND (channelIdentity/channelId:*)`; } else if (scope === "chats") { enhancedQuery = `${query} AND (chatId:* AND NOT channelIdentity/channelId:*)`; } searchRequest.query.queryString = enhancedQuery; const response = (await client .api("/search/query") .post({ requests: [searchRequest] })) as SearchResponse; if (!response?.value?.length || !response.value[0]?.hitsContainers?.length) { return { content: [ { type: "text", text: "No messages found matching your search criteria.", }, ], }; } const hits = response.value[0].hitsContainers[0].hits; const searchResults = hits.map((hit: SearchHit) => ({ id: hit.resource.id, summary: hit.summary, rank: hit.rank, content: hit.resource.body?.content || "No content", from: hit.resource.from?.user?.displayName || "Unknown", createdDateTime: hit.resource.createdDateTime, chatId: hit.resource.chatId, teamId: hit.resource.channelIdentity?.teamId, channelId: hit.resource.channelIdentity?.channelId, })); return { content: [ { type: "text", text: JSON.stringify( { query, scope, totalResults: response.value[0].hitsContainers[0].total, results: searchResults, moreResultsAvailable: response.value[0].hitsContainers[0].moreResultsAvailable, }, null, 2 ), }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; return { content: [ { type: "text", text: `❌ Error searching messages: ${errorMessage}`, }, ], }; } }
  • Zod schema defining the input parameters for the 'search_messages' tool: query (required string), scope (enum: all/channels/chats, default 'all'), limit (1-100, default 25), enableTopResults (boolean, default true).
    { query: z .string() .describe( "Search query. Supports KQL syntax like 'from:user mentions:userId hasAttachment:true'" ), scope: z .enum(["all", "channels", "chats"]) .optional() .default("all") .describe("Scope of search"), limit: z .number() .min(1) .max(100) .optional() .default(25) .describe("Number of results to return"), enableTopResults: z .boolean() .optional() .default(true) .describe("Enable relevance-based ranking"), },
  • The server.tool() call that registers the 'search_messages' tool with the MCP server, including name, description, input schema, and handler function.
    server.tool( "search_messages", "Search for messages across all Microsoft Teams channels and chats using Microsoft Search API. Supports advanced KQL syntax for filtering by sender, mentions, attachments, and more.", { query: z .string() .describe( "Search query. Supports KQL syntax like 'from:user mentions:userId hasAttachment:true'" ), scope: z .enum(["all", "channels", "chats"]) .optional() .default("all") .describe("Scope of search"), limit: z .number() .min(1) .max(100) .optional() .default(25) .describe("Number of results to return"), enableTopResults: z .boolean() .optional() .default(true) .describe("Enable relevance-based ranking"), }, async ({ query, scope, limit, enableTopResults }) => { try { const client = await graphService.getClient(); // Build the search request const searchRequest: SearchRequest = { entityTypes: ["chatMessage"], query: { queryString: query, }, from: 0, size: limit, enableTopResults, }; // Add scope-specific filters to the query if needed let enhancedQuery = query; if (scope === "channels") { enhancedQuery = `${query} AND (channelIdentity/channelId:*)`; } else if (scope === "chats") { enhancedQuery = `${query} AND (chatId:* AND NOT channelIdentity/channelId:*)`; } searchRequest.query.queryString = enhancedQuery; const response = (await client .api("/search/query") .post({ requests: [searchRequest] })) as SearchResponse; if (!response?.value?.length || !response.value[0]?.hitsContainers?.length) { return { content: [ { type: "text", text: "No messages found matching your search criteria.", }, ], }; } const hits = response.value[0].hitsContainers[0].hits; const searchResults = hits.map((hit: SearchHit) => ({ id: hit.resource.id, summary: hit.summary, rank: hit.rank, content: hit.resource.body?.content || "No content", from: hit.resource.from?.user?.displayName || "Unknown", createdDateTime: hit.resource.createdDateTime, chatId: hit.resource.chatId, teamId: hit.resource.channelIdentity?.teamId, channelId: hit.resource.channelIdentity?.channelId, })); return { content: [ { type: "text", text: JSON.stringify( { query, scope, totalResults: response.value[0].hitsContainers[0].total, results: searchResults, moreResultsAvailable: response.value[0].hitsContainers[0].moreResultsAvailable, }, null, 2 ), }, ], }; } catch (error: unknown) { const errorMessage = error instanceof Error ? error.message : "Unknown error occurred"; return { content: [ { type: "text", text: `❌ Error searching messages: ${errorMessage}`, }, ], }; } } );
  • src/index.ts:136-136 (registration)
    Invocation of registerSearchTools in the main MCP server setup, which registers the 'search_messages' tool along with other search-related tools.
    registerSearchTools(server, graphService);

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