Skip to main content
Glama
RadonX
by RadonX

search_notes

Find specific notes in TriliumNext using fulltext or structured queries. Specify a search term and limit results to streamline your knowledge base navigation.

Instructions

Search for notes in TriliumNext

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
limitNoMaximum number of results to return
queryYesSearch query (fulltext or structured, max 500 characters)

Implementation Reference

  • Core handler function that validates input, queries TriliumNext API for notes matching the search query, formats results with structured JSON, and handles various error cases with detailed responses.
    export async function searchNotes(triliumClient, args) { try { // Validate inputs const query = validators.searchQuery(args.query); const limit = validators.limit(args.limit); logger.debug(`Searching notes: query="${query}", limit=${limit}`); // Prepare search parameters for TriliumNext API const params = new URLSearchParams({ search: query, limit: limit.toString(), }); // Search notes via TriliumNext API const response = await triliumClient.get(`notes?${params}`); if (!response || typeof response !== 'object' || !Array.isArray(response.results)) { throw new TriliumAPIError('Invalid response from TriliumNext API - expected object with results array'); } const results = response.results; logger.info(`Found ${results.length} notes matching query "${query}"`); // Prepare structured response data const searchData = { query, limit, totalResults: results.length, hasMore: results.length === limit, // Might be more results if we hit the limit timestamp: new Date().toISOString(), notes: results.map(note => ({ noteId: note.noteId, title: note.title || 'Untitled', type: note.type || 'text', dateCreated: note.dateCreated, dateModified: note.dateModified, parentNoteIds: note.parentNoteIds || [], isProtected: note.isProtected || false, // Preserve additional fields that might be useful ...(note.mime && { mime: note.mime }), ...(note.attributes && { attributes: note.attributes }), ...(note.contentLength && { contentLength: note.contentLength }) })) }; if (results.length === 0) { return { content: [ { type: 'text', text: `No notes found for "${query}"` }, { type: 'application/json', text: JSON.stringify(searchData, null, 2) } ], }; } // Create concise summary const summary = `Found ${results.length} note${results.length === 1 ? '' : 's'} for "${query}"${searchData.hasMore ? ' (showing first ' + limit + ')' : ''}`; return { content: [ { type: 'text', text: summary }, { type: 'application/json', text: JSON.stringify(searchData, null, 2) } ], }; } catch (error) { logger.error(`Failed to search notes: ${error.message}`); // Create structured error response const errorData = { query: args.query, limit: args.limit, timestamp: new Date().toISOString(), error: { type: error.constructor.name, message: error.message, ...(error instanceof TriliumAPIError && { status: error.status }), ...(error instanceof TriliumAPIError && error.details && { details: error.details }) } }; if (error instanceof ValidationError) { return { content: [ { type: 'text', text: `Validation error: ${error.message}` }, { type: 'application/json', text: JSON.stringify(errorData, null, 2) } ], isError: true, }; } if (error instanceof TriliumAPIError) { return { content: [ { type: 'text', text: `TriliumNext API error: ${error.message}` }, { type: 'application/json', text: JSON.stringify(errorData, null, 2) } ], isError: true, }; } // Unknown error return { content: [ { type: 'text', text: `Search failed: ${error.message}` }, { type: 'application/json', text: JSON.stringify(errorData, null, 2) } ], isError: true, }; } }
  • MCP input schema defining the expected arguments for the search_notes tool: required 'query' string and optional 'limit' number.
    inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query (fulltext or structured, max 500 characters)', }, limit: { type: 'number', minimum: 1, maximum: 100, default: 10, description: 'Maximum number of results to return', }, }, required: ['query'],
  • src/index.js:146-147 (registration)
    Registration in the tool dispatch switch statement that routes 'search_notes' calls to the wrapper method.
    case 'search_notes': return await this.searchNotes(request.params.arguments);
  • src/index.js:82-101 (registration)
    Tool metadata registration in the ListTools response, including name, description, and schema.
    { name: 'search_notes', description: 'Search for notes in TriliumNext', inputSchema: { type: 'object', properties: { query: { type: 'string', description: 'Search query (fulltext or structured, max 500 characters)', }, limit: { type: 'number', minimum: 1, maximum: 100, default: 10, description: 'Maximum number of results to return', }, }, required: ['query'], },
  • Internal validator function for the search query parameter, enforcing non-empty string up to 500 characters.
    searchQuery: (query) => { if (!query || typeof query !== 'string') { throw new ValidationError('Search query must be a non-empty string'); } const trimmed = query.trim(); if (trimmed.length === 0) { throw new ValidationError('Search query cannot be empty'); } if (trimmed.length > 500) { throw new ValidationError('Search query cannot exceed 500 characters'); } return trimmed; },

Other Tools

Related Tools

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/RadonX/mcp-trilium'

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