Skip to main content
Glama
create-note.ts4.23 kB
import BaseTool, { JoplinNote } from "./base-tool.js" interface CreateNoteOptions { title?: string | undefined body?: string | undefined body_html?: string | undefined parent_id?: string | undefined is_todo?: boolean | undefined image_data_url?: string | undefined } type CreateNoteResponse = JoplinNote class CreateNote extends BaseTool { async call(options: CreateNoteOptions): Promise<string> { if (!options || typeof options !== "object") { return 'Please provide note creation options. Example: create_note {"title": "My Note", "body": "Note content"}' } // Validate that we have at least a title or body if (!options.title && !options.body && !options.body_html) { return "Please provide at least a title, body, or body_html for the note." } // Validate parent_id if provided if (options.parent_id && (options.parent_id.length < 10 || !options.parent_id.match(/[a-f0-9]/i))) { return `Error: "${options.parent_id}" does not appear to be a valid notebook ID.\n\nNotebook IDs are long alphanumeric strings like "58a0a29f68bc4141b49c99f5d367638a".\n\nUse list_notebooks to see available notebooks and their IDs.` } try { // Prepare the request body const requestBody: CreateNoteOptions = {} if (options.title) requestBody.title = options.title if (options.body) requestBody.body = options.body if (options.body_html) requestBody.body_html = options.body_html if (options.parent_id) requestBody.parent_id = options.parent_id if (options.is_todo !== undefined) requestBody.is_todo = options.is_todo if (options.image_data_url) requestBody.image_data_url = options.image_data_url // Create the note const createdNote = await this.apiClient.post<CreateNoteResponse>("/notes", requestBody) // Validate response if (!createdNote || typeof createdNote !== "object" || !createdNote.id) { return "Error: Unexpected response format from Joplin API when creating note" } // Get notebook info if available let notebookInfo = "Root level" if (createdNote.parent_id) { try { const notebook = await this.apiClient.get(`/folders/${createdNote.parent_id}`, { query: { fields: "id,title" }, }) if (notebook && notebook.title) { notebookInfo = `"${notebook.title}" (notebook_id: "${createdNote.parent_id}")` } } catch { // Continue even if we can't get notebook info notebookInfo = `Notebook ID: ${createdNote.parent_id}` } } // Format success response const resultLines: string[] = [] resultLines.push(`✅ Successfully created note!`) resultLines.push("") resultLines.push(`📝 Note Details:`) resultLines.push(` Title: "${createdNote.title || "Untitled"}"`) resultLines.push(` Note ID: ${createdNote.id}`) resultLines.push(` Location: ${notebookInfo}`) if (createdNote.is_todo) { resultLines.push(` Type: Todo item`) } const createdDate = this.formatDate(createdNote.created_time) resultLines.push(` Created: ${createdDate}`) resultLines.push("") resultLines.push(`🔗 Next steps:`) resultLines.push(` - Read the note: read_note note_id="${createdNote.id}"`) if (createdNote.parent_id) { resultLines.push(` - View notebook: read_notebook notebook_id="${createdNote.parent_id}"`) } resultLines.push(` - Search for it: search_notes query="${createdNote.title}"`) return resultLines.join("\n") } catch (error: any) { if (error.response) { // Handle specific API errors if (error.response.status === 400) { return `Error creating note: Invalid request data.\n\nPlease check your input parameters. ${error.response.data?.error || ""}` } if (error.response.status === 404 && options.parent_id) { return `Error: Notebook with ID "${options.parent_id}" not found.\n\nUse list_notebooks to see available notebooks and their IDs.` } } return this.formatError(error, "creating note") } } } export default CreateNote

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