Skip to main content
Glama
199-mcp

Limitless MCP Server

by 199-mcp

limitless_search_conversations_about

Search all historical conversations from Limitless Pendant recordings using natural language queries, filtering by time, speaker, and content type to find specific discussions.

Instructions

Advanced search across ALL lifelogs (not just recent) with intelligent context, relevance scoring, and comprehensive filtering options. Perfect for finding historical discussions.

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
search_termYesText to search for across ALL lifelogs (not just recent ones).
time_expressionNoNatural time range like 'this week', 'past month', 'today' to limit search scope.
speaker_nameNoFilter results to specific speaker/participant.
content_typesNoFilter by content node types like ['heading1', 'heading2', 'blockquote'].
include_contextNoInclude surrounding context for better understanding.
max_resultsNoMaximum number of results to return.
timezoneNoIANA timezone for time calculations.

Implementation Reference

  • src/server.ts:758-794 (registration)
    Tool registration for 'limitless_search_conversations_about', including thin wrapper handler that delegates to the main implementation in AdvancedSearch.searchConversationsAbout
    // Advanced Search Tool server.tool("limitless_search_conversations_about", "Advanced search across ALL lifelogs (not just recent) with intelligent context, relevance scoring, and comprehensive filtering options. Perfect for finding historical discussions.", AdvancedSearchArgsSchema, async (args, _extra) => { try { let timeRange = undefined; if (args.time_expression) { const parser = new NaturalTimeParser({ timezone: args.timezone }); timeRange = parser.parseTimeExpression(args.time_expression); } const searchOptions: SearchOptions = { includeContext: args.include_context, maxResults: args.max_results, searchInSpeaker: args.speaker_name, searchInContentType: args.content_types, timeRange }; const results = await AdvancedSearch.searchConversationsAbout( limitlessApiKey, args.search_term, searchOptions ); const resultText = results.length === 0 ? `No conversations found about "${args.search_term}".` : `Found ${results.length} relevant conversation(s) about "${args.search_term}":\n\n${JSON.stringify(results, null, 2)}`; return { content: [{ type: "text", text: resultText }] }; } catch (error) { const errorMessage = error instanceof Error ? error.message : String(error); return { content: [{ type: "text", text: `Error searching conversations: ${errorMessage}` }], isError: true }; } } );
  • Core handler function implementing the search logic: fetches lifelogs across time range, identifies relevant content nodes containing the search term (with speaker/content type filters), computes relevance scores, extracts surrounding context, generates summaries, and returns top scored results.
    static async searchConversationsAbout( apiKey: string, searchTerm: string, options: SearchOptions = {} ): Promise<TopicSearchResult[]> { const { includeContext = true, contextLines = 2, maxResults = 20, minRelevanceScore = 0.3, searchInSpeaker, searchInContentType, timeRange } = options; // Fetch all relevant lifelogs const lifelogParams: any = {}; if (timeRange) { lifelogParams.start = timeRange.start; lifelogParams.end = timeRange.end; lifelogParams.timezone = timeRange.timezone; } // Use a large limit to search through more history lifelogParams.limit = 1000; lifelogParams.includeMarkdown = true; lifelogParams.includeHeadings = true; const allLifelogs = await getLifelogs(apiKey, lifelogParams); const results: TopicSearchResult[] = []; const searchTermLower = searchTerm.toLowerCase(); for (const lifelog of allLifelogs) { const matchingNodes = this.findRelevantNodes( lifelog, searchTermLower, searchInSpeaker, searchInContentType ); if (matchingNodes.length === 0) continue; // Calculate relevance score const relevanceScore = this.calculateRelevanceScore(matchingNodes, searchTermLower); if (relevanceScore < minRelevanceScore) continue; // Get context if requested let contextBefore: LifelogContentNode[] = []; let contextAfter: LifelogContentNode[] = []; if (includeContext && lifelog.contents) { const { before, after } = this.extractContext( lifelog.contents, matchingNodes, contextLines ); contextBefore = before; contextAfter = after; } results.push({ lifelog, relevantNodes: matchingNodes, contextBefore, contextAfter, relevanceScore, summary: this.generateSearchSummary(lifelog, matchingNodes, searchTerm) }); } // Sort by relevance and return top results return results .sort((a, b) => b.relevanceScore - a.relevanceScore) .slice(0, maxResults); }
  • Zod schema defining the input arguments for the tool registration.
    const AdvancedSearchArgsSchema = { search_term: z.string().describe("Text to search for across ALL lifelogs (not just recent ones)."), time_expression: z.string().optional().describe("Natural time range like 'this week', 'past month', 'today' to limit search scope."), speaker_name: z.string().optional().describe("Filter results to specific speaker/participant."), content_types: z.array(z.string()).optional().describe("Filter by content node types like ['heading1', 'heading2', 'blockquote']."), include_context: z.boolean().optional().default(true).describe("Include surrounding context for better understanding."), max_results: z.number().optional().default(20).describe("Maximum number of results to return."), timezone: z.string().optional().describe("IANA timezone for time calculations."), };
  • TypeScript interface defining options passed to the search handler, mapping from tool args.
    export interface SearchOptions { includeContext?: boolean; contextLines?: number; maxResults?: number; minRelevanceScore?: number; searchInSpeaker?: string; searchInContentType?: string[]; timeRange?: TimeRange; }
  • Helper method to find content nodes in a lifelog matching the search term and filters.
    private static findRelevantNodes( lifelog: Lifelog, searchTermLower: string, searchInSpeaker?: string, searchInContentType?: string[] ): LifelogContentNode[] { if (!lifelog.contents) return []; return lifelog.contents.filter(node => { // Content match const hasContentMatch = node.content?.toLowerCase().includes(searchTermLower); // Speaker filter if (searchInSpeaker && node.speakerName !== searchInSpeaker) { return false; } // Content type filter if (searchInContentType && !searchInContentType.includes(node.type)) { return false; } return hasContentMatch; }); }

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/199-mcp/mcp-limitless'

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