search_entries
Find journal entries using date ranges, tags, or keywords to locate specific content in your personal journal.
Instructions
Search journal entries by date range, tags, or keywords
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| dateFrom | No | Start date in YYYY-MM-DD format | |
| dateTo | No | End date in YYYY-MM-DD format | |
| tags | No | Tags to filter by (all must match) | |
| keywords | No | Keywords to search in content | |
| limit | No | Maximum number of results (default 50) | |
| offset | No | Offset for pagination (default 0) |
Implementation Reference
- src/mcp-server.ts:62-119 (registration)MCP server tool registration for 'search_entries', defining the tool name, description, input schema (Zod), and execution handler that formats search results into a readable text response.
this.server.tool( 'search_entries', 'Search journal entries by date range, tags, or keywords', { dateFrom: z .string() .optional() .describe('Start date in YYYY-MM-DD format'), dateTo: z.string().optional().describe('End date in YYYY-MM-DD format'), tags: z .array(z.string()) .optional() .describe('Tags to filter by (all must match)'), keywords: z .string() .optional() .describe('Keywords to search in content'), limit: z .number() .optional() .describe('Maximum number of results (default 50)'), offset: z .number() .optional() .describe('Offset for pagination (default 0)'), }, async (args): Promise<CallToolResult> => { const result = await searchEntries(args); let response = `š Found ${result.total} journal entries`; if (result.hasMore) { response += ` (showing ${result.entries.length})`; } response += '\n\n'; for (const file of result.entries) { response += `**${file.date}** - ${file.entries_count} entries\n`; response += `Tags: ${file.tags.join(', ') || 'None'}\n`; for (const entry of file.entries) { response += `\nš ${entry.timestamp} - ${entry.title}\n`; response += `${entry.content.slice(0, 200)}${ entry.content.length > 200 ? '...' : '' }\n`; } response += '\n---\n\n'; } return { content: [ { type: 'text', text: response, }, ], }; } ); - src/journal/manager.ts:316-360 (handler)Core implementation of searchEntries: discovers journal .md files, parses content into JournalFile structures using gray-matter and custom parsers, filters by date/tags/keywords, sorts by date descending, applies pagination, returns JournalSearchResult.
export async function searchEntries( options: JournalSearchOptions = {} ): Promise<JournalSearchResult> { const entriesDir = getEntriesDir(); await ensureDir(entriesDir); // Find all markdown files const pattern = `${entriesDir}/**/*.md`; const files = await glob(pattern, { onlyFiles: true }); let journalFiles: JournalFile[] = []; // Parse all files for (const filePath of files) { const content = await readFileIfExists(filePath); if (!content) continue; try { const journalFile = await parseJournalFile(filePath, content); journalFiles.push(journalFile); } catch (error) { console.warn(`Failed to parse journal file ${filePath}:`, error); } } // Apply filters journalFiles = filterJournalFiles(journalFiles, options); // Sort by date (newest first) journalFiles.sort( (a, b) => new Date(b.date).getTime() - new Date(a.date).getTime() ); // Apply pagination const offset = options.offset || 0; const limit = options.limit || 50; const total = journalFiles.length; const paginatedFiles = journalFiles.slice(offset, offset + limit); return { entries: paginatedFiles, total, hasMore: offset + limit < total, }; }