limitless_search_lifelogs
Search recent lifelog recordings for specific keywords in titles and content, returning matching results from a defined scope of recent entries.
Instructions
Performs a simple text search for specific keywords/phrases within the title and content of recent logs/Pendant recordings. Use ONLY for keywords, NOT for concepts like 'action items' or 'summaries'. Searches only recent logs (limited scope).
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| search_term | Yes | The text to search for within lifelog titles and content. | |
| fetch_limit | No | How many *recent* lifelogs to fetch from the API to search within (Default: 20, Max: 100). This defines the scope of the search, NOT the number of results returned. | |
| limit | No | Maximum number of lifelogs to return per request (Max: 10 per API constraint). Use cursor for pagination. | |
| timezone | No | IANA timezone for date/time parameters (defaults to server's local timezone). | |
| includeMarkdown | No | Include markdown content in the response. | |
| includeHeadings | No | Include headings content in the response. | |
| isStarred | No | Filter for starred lifelogs only. |
Implementation Reference
- src/server.ts:602-644 (handler)The handler function fetches recent lifelogs via getLifelogs API call, performs case-insensitive substring search on log.title and log.markdown, limits results, and returns formatted matches with token limit handling.async (args, _extra) => { const fetchLimit = args.fetch_limit ?? 20; console.error(`[Server Tool] Search initiated for term: "${args.search_term}", fetch_limit: ${fetchLimit}`); try { const logsToSearch = await getLifelogs(limitlessApiKey, { limit: fetchLimit, direction: 'desc', timezone: args.timezone, includeMarkdown: args.includeMarkdown ?? true, includeHeadings: args.includeHeadings ?? true, isStarred: args.isStarred }); if (logsToSearch.length === 0) { return { content: [{ type: "text", text: "No recent lifelogs found to search within." }] }; } const searchTermLower = args.search_term.toLowerCase(); const matchingLogs = logsToSearch.filter(log => log.title?.toLowerCase().includes(searchTermLower) || (log.markdown && log.markdown.toLowerCase().includes(searchTermLower)) ); const finalLimit = args.limit; // This limit applies to the *results* const limitedResults = finalLimit ? matchingLogs.slice(0, finalLimit) : matchingLogs; if (limitedResults.length === 0) { return { content: [{ type: "text", text: `No matches found for "${args.search_term}" within the ${logsToSearch.length} most recent lifelogs searched.` }] }; } // Use createSafeResponse to handle token limits return createSafeResponse( limitedResults, `Found ${limitedResults.length} match(es) for "${args.search_term}" within the ${logsToSearch.length} most recent lifelogs searched${finalLimit !== undefined ? ` (displaying up to ${finalLimit})` : ''}`, { hasMore: matchingLogs.length > limitedResults.length, totalFetched: logsToSearch.length } ); } catch (error) { return handleToolApiCall(() => Promise.reject(error)); } }
- src/server.ts:210-218 (schema)Input argument schema using Zod, defining search_term (required), fetch_limit (scope of lifelogs to search), and common pagination/filter options.const SearchArgsSchema = { search_term: z.string().describe("The text to search for within lifelog titles and content."), fetch_limit: z.number().int().positive().max(MAX_TOTAL_FETCH_LIMIT).optional().default(20).describe(`How many *recent* lifelogs to fetch from the API to search within (Default: 20, Max: ${MAX_TOTAL_FETCH_LIMIT}). This defines the scope of the search, NOT the number of results returned.`), limit: CommonListArgsSchema.limit, timezone: CommonListArgsSchema.timezone, includeMarkdown: CommonListArgsSchema.includeMarkdown, includeHeadings: CommonListArgsSchema.includeHeadings, isStarred: CommonListArgsSchema.isStarred, };
- src/server.ts:599-645 (registration)MCP server registration of the tool, providing name, detailed description emphasizing keyword-only usage on recent logs, input schema, and handler callback.server.tool( "limitless_search_lifelogs", "Performs a simple text search for specific keywords/phrases within the title and content of *recent* logs/Pendant recordings. Use ONLY for keywords, NOT for concepts like 'action items' or 'summaries'. Searches only recent logs (limited scope).", SearchArgsSchema, async (args, _extra) => { const fetchLimit = args.fetch_limit ?? 20; console.error(`[Server Tool] Search initiated for term: "${args.search_term}", fetch_limit: ${fetchLimit}`); try { const logsToSearch = await getLifelogs(limitlessApiKey, { limit: fetchLimit, direction: 'desc', timezone: args.timezone, includeMarkdown: args.includeMarkdown ?? true, includeHeadings: args.includeHeadings ?? true, isStarred: args.isStarred }); if (logsToSearch.length === 0) { return { content: [{ type: "text", text: "No recent lifelogs found to search within." }] }; } const searchTermLower = args.search_term.toLowerCase(); const matchingLogs = logsToSearch.filter(log => log.title?.toLowerCase().includes(searchTermLower) || (log.markdown && log.markdown.toLowerCase().includes(searchTermLower)) ); const finalLimit = args.limit; // This limit applies to the *results* const limitedResults = finalLimit ? matchingLogs.slice(0, finalLimit) : matchingLogs; if (limitedResults.length === 0) { return { content: [{ type: "text", text: `No matches found for "${args.search_term}" within the ${logsToSearch.length} most recent lifelogs searched.` }] }; } // Use createSafeResponse to handle token limits return createSafeResponse( limitedResults, `Found ${limitedResults.length} match(es) for "${args.search_term}" within the ${logsToSearch.length} most recent lifelogs searched${finalLimit !== undefined ? ` (displaying up to ${finalLimit})` : ''}`, { hasMore: matchingLogs.length > limitedResults.length, totalFetched: logsToSearch.length } ); } catch (error) { return handleToolApiCall(() => Promise.reject(error)); } } );