Skip to main content
Glama
jordanburke

joplin-mcp-server

delete_note

Remove a specific note from Joplin by providing its ID and confirmation flag using the Joplin MCP Server.

Instructions

Delete a note from Joplin (requires confirmation)

Input Schema

TableJSON Schema
NameRequiredDescriptionDefault
confirmNoConfirmation flag
note_idYesID of the note to delete

Implementation Reference

  • The DeleteNote class provides the core handler logic for the 'delete_note' tool. It validates inputs, requires confirmation, fetches note details, deletes the note via Joplin API, and returns a formatted response with details.
    class DeleteNote extends BaseTool {
      async call(options: DeleteNoteOptions): Promise<string> {
        if (!options || typeof options !== "object") {
          return 'Please provide note deletion options. Example: delete_note {"note_id": "abc123", "confirm": true}'
        }
    
        // Validate required note_id
        if (!options.note_id) {
          return 'Please provide note deletion options. Example: delete_note {"note_id": "abc123", "confirm": true}'
        }
    
        const noteIdError = this.validateId(options.note_id, "note")
        if (noteIdError) {
          return noteIdError
        }
    
        // Require explicit confirmation for safety
        if (!options.confirm) {
          return `⚠️  This will permanently delete the note!\n\nTo confirm deletion, use:\ndelete_note {"note_id": "${options.note_id}", "confirm": true}\n\n⚠️  This action cannot be undone!`
        }
    
        try {
          // First, get the note details to show what's being deleted
          const noteToDelete = await this.apiClient.get<JoplinNote>(`/notes/${options.note_id}`, {
            query: { fields: "id,title,body,parent_id,is_todo,todo_completed,created_time,updated_time" },
          })
    
          if (!noteToDelete || !noteToDelete.id) {
            return `Note with ID "${options.note_id}" not found.\n\nUse search_notes to find notes and their IDs.`
          }
    
          // Get notebook info if available
          let notebookInfo = "Root level"
          if (noteToDelete.parent_id) {
            try {
              const notebook = await this.apiClient.get(`/folders/${noteToDelete.parent_id}`, {
                query: { fields: "title" },
              })
              if (notebook?.title) {
                notebookInfo = `"${notebook.title}" (notebook_id: "${noteToDelete.parent_id}")`
              }
            } catch {
              notebookInfo = `Notebook ID: ${noteToDelete.parent_id}`
            }
          }
    
          // Delete the note
          await this.apiClient.delete(`/notes/${options.note_id}`)
    
          // Format success response
          const resultLines: string[] = []
          resultLines.push(`🗑️  Successfully deleted note!`)
          resultLines.push("")
          resultLines.push(`📝 Deleted Note Details:`)
          resultLines.push(`   Title: "${noteToDelete.title || "Untitled"}"`)
          resultLines.push(`   Note ID: ${noteToDelete.id}`)
          resultLines.push(`   Location: ${notebookInfo}`)
    
          if (noteToDelete.is_todo) {
            const status = noteToDelete.todo_completed ? "Completed" : "Not completed"
            resultLines.push(`   Type: Todo (${status})`)
          } else {
            resultLines.push(`   Type: Regular note`)
          }
    
          const createdDate = this.formatDate(noteToDelete.created_time)
          const updatedDate = this.formatDate(noteToDelete.updated_time)
          resultLines.push(`   Created: ${createdDate}`)
          resultLines.push(`   Last Updated: ${updatedDate}`)
    
          // Show content preview if available
          if (noteToDelete.body) {
            const preview = noteToDelete.body.substring(0, 100).replace(/\n/g, " ")
            const truncated = noteToDelete.body.length > 100 ? "..." : ""
            resultLines.push(`   Content Preview: ${preview}${truncated}`)
          }
    
          resultLines.push("")
          resultLines.push(`⚠️  This note has been permanently deleted and cannot be recovered.`)
    
          if (noteToDelete.parent_id) {
            resultLines.push("")
            resultLines.push(`🔗 Related actions:`)
            resultLines.push(`   - View containing notebook: read_notebook notebook_id="${noteToDelete.parent_id}"`)
            resultLines.push(`   - Search for similar notes: search_notes query="${noteToDelete.title}"`)
          }
    
          return resultLines.join("\n")
        } catch (error: any) {
          if (error.response) {
            if (error.response.status === 404) {
              return `Note with ID "${options.note_id}" not found.\n\nUse search_notes to find notes and their IDs.`
            }
            if (error.response.status === 403) {
              return `Permission denied: Cannot delete note with ID "${options.note_id}".\n\nThis might be a protected system note.`
            }
          }
          return this.formatError(error, "deleting note")
        }
      }
    }
    
    export default DeleteNote
  • TypeScript interface defining the input schema for the delete_note tool handler.
    interface DeleteNoteOptions {
      note_id: string
      confirm?: boolean | undefined
    }
  • src/index.ts:189-200 (registration)
    Registration of 'delete_note' tool in the MCP list_tools handler, including metadata, description, and input schema.
    {
      name: "delete_note",
      description: "Delete a note from Joplin (requires confirmation)",
      inputSchema: {
        type: "object",
        properties: {
          note_id: { type: "string", description: "ID of the note to delete" },
          confirm: { type: "boolean", description: "Confirmation flag" },
        },
        required: ["note_id"],
      },
    },
  • src/index.ts:301-308 (registration)
    Dispatch logic in MCP call_tool handler: routes 'delete_note' calls to manager.deleteNote().
    case "delete_note": {
      const deleteNoteResult = await manager.deleteNote(
        args as {
          note_id: string
          confirm?: boolean | undefined
        },
      )
      return { content: [{ type: "text", text: deleteNoteResult }], isError: false }
  • JoplinServerManager.deleteNote method proxies calls to the DeleteNote tool instance.
    async deleteNote(params: { note_id: string; confirm?: boolean | undefined }): Promise<string> {
      return await this.tools.deleteNote.call(params)
    }
  • Instantiation of DeleteNote tool in JoplinServerManager constructor.
    deleteNote: new DeleteNote(this.apiClient),
Install Server

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

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