Skip to main content
Glama
create-folder.ts4.19 kB
import BaseTool, { JoplinFolder } from "./base-tool.js" interface CreateFolderOptions { title: string parent_id?: string | undefined } interface CreateFolderResponse extends JoplinFolder { created_time: number updated_time: number } class CreateFolder extends BaseTool { async call(options: CreateFolderOptions): Promise<string> { if (!options || typeof options !== "object") { return 'Please provide folder creation options. Example: create_folder {"title": "My Notebook"}' } // Validate required title if (!options.title || typeof options.title !== "string" || options.title.trim() === "") { return 'Please provide a title for the folder/notebook. Example: create_folder {"title": "My Notebook"}' } // 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 parent notebook ID.\n\nNotebook IDs are long alphanumeric strings like "58a0a29f68bc4141b49c99f5d367638a".\n\nUse list_notebooks to see available notebooks and their IDs, or omit parent_id to create a top-level notebook.` } try { // Prepare the request body const requestBody: CreateFolderOptions = { title: options.title.trim(), } if (options.parent_id) { requestBody.parent_id = options.parent_id } // Create the folder const createdFolder = await this.apiClient.post<CreateFolderResponse>("/folders", requestBody) // Validate response if (!createdFolder || typeof createdFolder !== "object" || !createdFolder.id) { return "Error: Unexpected response format from Joplin API when creating folder" } // Get parent notebook info if available let parentInfo = "Top level" if (createdFolder.parent_id) { try { const parentNotebook = await this.apiClient.get(`/folders/${createdFolder.parent_id}`, { query: { fields: "id,title" }, }) if (parentNotebook && parentNotebook.title) { parentInfo = `Inside "${parentNotebook.title}" (notebook_id: "${createdFolder.parent_id}")` } } catch { // Continue even if we can't get parent info parentInfo = `Parent notebook ID: ${createdFolder.parent_id}` } } // Format success response const resultLines: string[] = [] resultLines.push(`✅ Successfully created notebook!`) resultLines.push("") resultLines.push(`📁 Notebook Details:`) resultLines.push(` Title: "${createdFolder.title}"`) resultLines.push(` Notebook ID: ${createdFolder.id}`) resultLines.push(` Location: ${parentInfo}`) const createdDate = this.formatDate(createdFolder.created_time) resultLines.push(` Created: ${createdDate}`) resultLines.push("") resultLines.push(`🔗 Next steps:`) resultLines.push(` - View notebook: read_notebook notebook_id="${createdFolder.id}"`) resultLines.push(` - Create a note in it: create_note {"title": "My Note", "parent_id": "${createdFolder.id}"}`) resultLines.push(` - View all notebooks: list_notebooks`) return resultLines.join("\n") } catch (error: any) { if (error.response) { // Handle specific API errors if (error.response.status === 400) { return `Error creating notebook: Invalid request data.\n\nPlease check your input parameters. ${error.response.data?.error || ""}` } if (error.response.status === 404 && options.parent_id) { return `Error: Parent notebook with ID "${options.parent_id}" not found.\n\nUse list_notebooks to see available notebooks and their IDs, or omit parent_id to create a top-level notebook.` } if (error.response.status === 409) { return `Error: A notebook with the title "${options.title}" might already exist in this location.\n\nTry a different title or check existing notebooks with list_notebooks.` } } return this.formatError(error, "creating notebook") } } } export default CreateFolder

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