search_entries
Filter and retrieve journal entries by date range, tags, or keywords to efficiently manage and analyze content on the Journal MCP Server.
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 | |
| keywords | No | Keywords to search in content | |
| limit | No | Maximum number of results (default 50) | |
| offset | No | Offset for pagination (default 0) | |
| tags | No | Tags to filter by (all must match) |
Input Schema (JSON Schema)
{
"$schema": "http://json-schema.org/draft-07/schema#",
"additionalProperties": false,
"properties": {
"dateFrom": {
"description": "Start date in YYYY-MM-DD format",
"type": "string"
},
"dateTo": {
"description": "End date in YYYY-MM-DD format",
"type": "string"
},
"keywords": {
"description": "Keywords to search in content",
"type": "string"
},
"limit": {
"description": "Maximum number of results (default 50)",
"type": "number"
},
"offset": {
"description": "Offset for pagination (default 0)",
"type": "number"
},
"tags": {
"description": "Tags to filter by (all must match)",
"items": {
"type": "string"
},
"type": "array"
}
},
"type": "object"
}
Implementation Reference
- src/mcp-server.ts:88-118 (handler)MCP tool handler for 'search_entries' that calls the core searchEntries function from manager and formats a markdown response with search results.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/mcp-server.ts:65-87 (schema)Zod input schema defining parameters for the search_entries MCP tool: date range, tags, keywords, limit, offset.{ 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)'), },
- src/mcp-server.ts:62-119 (registration)Registration of the 'search_entries' MCP tool using McpServer.tool(), including name, description, input schema, and handler.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 (helper)Core helper function searchEntries that discovers journal .md files, parses them into JournalFile structures, applies filters (date, tags, keywords), sorts, paginates, and 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, }; }