Skip to main content
Glama
search-notes.ts3.2 kB
import BaseTool, { JoplinNote, JoplinFolder } from "./base-tool.js" interface SearchResult { items: JoplinNote[] } class SearchNotes extends BaseTool { async call(query: string): Promise<string> { if (!query) { return "Please provide a search query." } try { // Search for notes with the given query const searchResults = await this.apiClient.get<SearchResult>("/search", { query: { query, fields: "id,title,body,parent_id,updated_time", }, }) // Handle case where the API doesn't return the expected structure if (!searchResults || typeof searchResults !== "object") { return `Error: Unexpected response format from Joplin API` } // Handle case where no items were found if (!searchResults.items || !Array.isArray(searchResults.items) || searchResults.items.length === 0) { return `No notes found matching query: "${query}"` } // Get all folders to be able to show notebook names const folders = await this.apiClient.getAllItems<JoplinFolder>("/folders", { query: { fields: "id,title", }, }) // Create a map of folder IDs to folder titles for quick lookup const folderMap: Record<string, string> = {} folders.forEach((folder) => { folderMap[folder.id] = folder.title }) // Format the search results const resultLines: string[] = [] resultLines.push(`Found ${searchResults.items.length} notes matching query: "${query}"\n`) resultLines.push(`NOTE: To read a notebook, use the notebook ID (not the note title)\n`) // If multiple notes were found, add a hint about read_multinote if (searchResults.items.length > 1) { const noteIds = searchResults.items.map((note) => note.id) resultLines.push(`TIP: To read all ${searchResults.items.length} notes at once, use:\n`) resultLines.push(`read_multinote note_ids=${JSON.stringify(noteIds)}\n`) } searchResults.items.forEach((note) => { const notebookTitle = folderMap[note.parent_id || ""] || "Unknown notebook" const notebookId = note.parent_id || "unknown" const updatedDate = this.formatDate(note.updated_time) resultLines.push(`- Note: "${note.title}" (note_id: "${note.id}")`) resultLines.push(` Notebook: "${notebookTitle}" (notebook_id: "${notebookId}")`) resultLines.push(` Updated: ${updatedDate}`) // Add a snippet of the note body if available if (note.body) { const snippet = note.body.substring(0, 100).replace(/\n/g, " ") + (note.body.length > 100 ? "..." : "") resultLines.push(` Snippet: ${snippet}`) } // Add hints for using related commands resultLines.push(` To read this note: read_note note_id="${note.id}"`) resultLines.push(` To read this notebook: read_notebook notebook_id="${notebookId}"`) resultLines.push("") // Empty line between notes }) return resultLines.join("\n") } catch (error: unknown) { return this.formatError(error, "searching notes") } } } export default SearchNotes

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/jordanburke/joplin-mcp-server'

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