create_note
Add new notes to your TriliumNext knowledge base with specified titles, content, and organizational structure for information management.
Instructions
Create a new note in TriliumNext
Input Schema
TableJSON Schema
| Name | Required | Description | Default |
|---|---|---|---|
| title | Yes | The title of the note (max 200 characters) | |
| content | Yes | The content of the note (max 1MB) | |
| type | No | The type of note to create | text |
| parentNoteId | No | ID of the parent note (defaults to "root" if not provided) |
Implementation Reference
- src/tools/create-note.js:5-131 (handler)The primary handler function that executes the create_note tool logic: validates inputs, interacts with TriliumNext API to create a note, formats success/error responses in MCP format.export async function createNote(triliumClient, args) { try { // Validate inputs const title = validators.title(args.title); const content = validators.content(args.content); const type = validators.noteType(args.type); // TriliumNext API requires parentNoteId - default to 'root' if not provided const parentNoteId = args.parentNoteId ? validators.noteId(args.parentNoteId) : 'root'; logger.debug(`Creating note: title="${title}", type="${type}", parent="${parentNoteId}"`); // Prepare note data for TriliumNext API const noteData = { title, content, type, parentNoteId, // Always required by TriliumNext API }; // Create the note via TriliumNext API const result = await triliumClient.post('create-note', noteData); if (!result || !result.note || !result.note.noteId) { throw new TriliumAPIError('Invalid response from TriliumNext API - missing note ID'); } const noteId = result.note.noteId; logger.info(`Note created successfully with ID: ${noteId}`); // Prepare structured response data const creationData = { operation: 'create_note', timestamp: new Date().toISOString(), request: { title, type, contentLength: content.length, parentNoteId }, result: { noteId, ...result.note, // Include any additional data from API response triliumUrl: `trilium://note/${noteId}` // Add direct link if useful } }; return { content: [ { type: 'text', text: `Note created: "${title}" (ID: ${noteId})` }, { type: 'application/json', text: JSON.stringify(creationData, null, 2) } ], }; } catch (error) { logger.error(`Failed to create note: ${error.message}`); // Create structured error response const errorData = { operation: 'create_note', timestamp: new Date().toISOString(), request: { title: args.title, type: args.type, contentLength: args.content?.length, parentNoteId: args.parentNoteId }, error: { type: error.constructor.name, message: error.message, ...(error instanceof TriliumAPIError && { status: error.status }), ...(error instanceof TriliumAPIError && error.details && { details: error.details }) } }; if (error instanceof ValidationError) { return { content: [ { type: 'text', text: `Validation error: ${error.message}` }, { type: 'application/json', text: JSON.stringify(errorData, null, 2) } ], isError: true, }; } if (error instanceof TriliumAPIError) { return { content: [ { type: 'text', text: `TriliumNext API error: ${error.message}` }, { type: 'application/json', text: JSON.stringify(errorData, null, 2) } ], isError: true, }; } // Unknown error return { content: [ { type: 'text', text: `Note creation failed: ${error.message}` }, { type: 'application/json', text: JSON.stringify(errorData, null, 2) } ], isError: true, }; } }
- src/index.js:54-81 (schema)The MCP tool schema definition for 'create_note', including input schema with properties, types, descriptions, enums, and required fields.{ name: 'create_note', description: 'Create a new note in TriliumNext', inputSchema: { type: 'object', properties: { title: { type: 'string', description: 'The title of the note (max 200 characters)', }, content: { type: 'string', description: 'The content of the note (max 1MB)', }, type: { type: 'string', enum: ['text', 'code', 'file', 'image', 'search', 'book', 'relationMap', 'canvas'], default: 'text', description: 'The type of note to create', }, parentNoteId: { type: 'string', description: 'ID of the parent note (defaults to "root" if not provided)', }, }, required: ['title', 'content'], }, },
- src/index.js:144-145 (registration)Registration of the create_note tool in the CallToolRequestSchema dispatch switch statement, routing calls to the handler.case 'create_note': return await this.createNote(request.params.arguments);
- src/index.js:201-203 (registration)Wrapper method on the server class that delegates create_note execution to the core handler function.async createNote(args) { return await createNote(this.triliumClient, args); }
- src/utils/validation.js:8-81 (helper)Validation helper functions used by the create_note handler for input sanitization and validation (title, content, type, noteId).export const validators = { noteId: (noteId) => { if (!noteId || typeof noteId !== 'string') { throw new ValidationError('Note ID must be a non-empty string'); } if (noteId.trim().length === 0) { throw new ValidationError('Note ID cannot be empty'); } return noteId.trim(); }, title: (title) => { if (!title || typeof title !== 'string') { throw new ValidationError('Title must be a non-empty string'); } const trimmed = title.trim(); if (trimmed.length === 0) { throw new ValidationError('Title cannot be empty'); } if (trimmed.length > 200) { throw new ValidationError('Title cannot exceed 200 characters'); } return trimmed; }, content: (content) => { if (content === null || content === undefined) { throw new ValidationError('Content cannot be null or undefined'); } if (typeof content !== 'string') { throw new ValidationError('Content must be a string'); } if (content.length > 1000000) { // 1MB limit throw new ValidationError('Content cannot exceed 1MB'); } return content; }, noteType: (type) => { const validTypes = ['text', 'code', 'file', 'image', 'search', 'book', 'relationMap', 'canvas']; if (type && !validTypes.includes(type)) { throw new ValidationError(`Note type must be one of: ${validTypes.join(', ')}`); } return type || 'text'; }, searchQuery: (query) => { if (!query || typeof query !== 'string') { throw new ValidationError('Search query must be a non-empty string'); } const trimmed = query.trim(); if (trimmed.length === 0) { throw new ValidationError('Search query cannot be empty'); } if (trimmed.length > 500) { throw new ValidationError('Search query cannot exceed 500 characters'); } return trimmed; }, limit: (limit) => { if (limit === undefined || limit === null) { return 10; // default } const num = parseInt(limit, 10); if (isNaN(num) || num < 1) { throw new ValidationError('Limit must be a positive integer'); } if (num > 100) { throw new ValidationError('Limit cannot exceed 100'); } return num; } };