Skip to main content
Glama
read-multi-note.ts4.56 kB
import BaseTool, { JoplinNote, JoplinFolder } from "./base-tool.js" class ReadMultiNote extends BaseTool { async call(noteIds: string[]): Promise<string> { if (!noteIds || !Array.isArray(noteIds) || noteIds.length === 0) { return 'Please provide an array of note IDs. Example: read_multinote note_ids=["id1", "id2", "id3"]' } // Validate that all IDs look like valid note IDs const invalidIds = noteIds.filter((id) => !id || id.length < 10 || !id.match(/[a-f0-9]/i)) if (invalidIds.length > 0) { return `Error: Some IDs do not appear to be valid note IDs: ${invalidIds.join(", ")}\n\nNote IDs are long alphanumeric strings like "58a0a29f68bc4141b49c99f5d367638a".\n\nUse search_notes to find notes and their IDs.` } const resultLines: string[] = [] const notFound: string[] = [] const errors: string[] = [] const successful: string[] = [] // Add a header resultLines.push(`# Reading ${noteIds.length} notes\n`) // Process each note ID for (let i = 0; i < noteIds.length; i++) { const noteId = noteIds[i] resultLines.push(`## Note ${i + 1} of ${noteIds.length} (ID: ${noteId})\n`) try { // Get the note details with all relevant fields const note = await this.apiClient.get<JoplinNote>(`/notes/${noteId}`, { query: { fields: "id,title,body,parent_id,created_time,updated_time,is_todo,todo_completed,todo_due", }, }) // Validate note response if (!note || typeof note !== "object" || !note.id) { errors.push(noteId) resultLines.push(`Error: Unexpected response format from Joplin API when fetching note ${noteId}\n`) continue } successful.push(noteId) // Get the notebook info to show where this note is located let notebookInfo = "Unknown notebook" if (note.parent_id) { try { const notebook = await this.apiClient.get<JoplinFolder>(`/folders/${note.parent_id}`, { query: { fields: "id,title" }, }) if (notebook && notebook.title) { notebookInfo = `"${notebook.title}" (notebook_id: "${note.parent_id}")` } } catch (err: unknown) { process.stderr.write(`Error fetching notebook info for note ${noteId}: ${err}\n`) // Continue even if we can't get the notebook info } } // Add note metadata resultLines.push(`### Note: "${note.title}"`) resultLines.push(`Notebook: ${notebookInfo}`) // Add todo status if applicable if (note.is_todo) { const status = note.todo_completed ? "Completed" : "Not completed" resultLines.push(`Status: ${status}`) if (note.todo_due) { const dueDate = this.formatDate(note.todo_due) resultLines.push(`Due: ${dueDate}`) } } // Add timestamps const createdDate = this.formatDate(note.created_time) const updatedDate = this.formatDate(note.updated_time) resultLines.push(`Created: ${createdDate}`) resultLines.push(`Updated: ${updatedDate}`) // Add a separator before the note content resultLines.push("\n---\n") // Add the note body if (note.body) { resultLines.push(note.body) } else { resultLines.push("(This note has no content)") } // Add a separator after the note resultLines.push("\n---\n") } catch (error: any) { process.stderr.write(`Error reading note ${noteId}: ${error}\n`) if (error.response && error.response.status === 404) { notFound.push(noteId) resultLines.push(`Note with ID "${noteId}" not found.\n`) } else { errors.push(noteId) resultLines.push(`Error reading note: ${error.message || "Unknown error"}\n`) } } } // Add a summary at the end resultLines.push("# Summary") resultLines.push(`Total notes requested: ${noteIds.length}`) resultLines.push(`Successfully retrieved: ${successful.length}`) if (notFound.length > 0) { resultLines.push(`Notes not found: ${notFound.length}`) resultLines.push(`IDs not found: ${notFound.join(", ")}`) } if (errors.length > 0) { resultLines.push(`Errors encountered: ${errors.length}`) resultLines.push(`IDs with errors: ${errors.join(", ")}`) } return resultLines.join("\n") } } export default ReadMultiNote

Implementation Reference

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