A model context protocol server for TriliumNext Notes
This is a well-structured MCP server with 11 tools covering note management operations. Strengths: all tools have names starting with action verbs (create_, update_, delete_, get_, list_, move_, patch_, search_, resolve_, read_, manage_); comprehensive parameter descriptions with detailed guidance on content types and validation rules; clear documentation of write vs read operations and risk levels. Weaknesses: output schemas are NOT documented anywhere in the provided source code, we cannot see what get_note, list_children_notes, search_notes, or resolve_note_id actually return; descriptions for several tools are extremely long (1000+ chars) and contain example values ('data:application/pdf;base64,JVBERi0xLjcK...') that LLMs may hallucinate; error handling guidance is minimal; no tool annotations (readOnlyHint, destructiveHint, idempotentHint) present in schema definitions; some parameters lack enum constraints where they should have them (e.g., searchCriteria in search_notes is an open object with no structure).
Create a new note in TriliumNext with duplicate title detection. When a note with the same title already exists in the same directory, you'll be presented with choices: skip creation, create anyway (with forceCreate: true), or update the existing note. ONLY use this tool when the user explicitly requests note creation (e.g., 'create a note', 'make a new note'). DO NOT use this tool proactively or when the user is only asking questions about their notes. TIP: For code notes, content is plain text (no HTML processing).
Delete a note permanently. ONLY use this tool when the user explicitly requests note deletion (e.g., 'delete the note', 'remove this note', 'delete this permanently')
Retrieve a note by ID with optional content inclusion and search functionality. Returns note metadata including ID, title, type, MIME type, content hash (blobId), and optionally the full content or search results. Use includeContent=false for metadata-only queries to improve performance.
List all child notes of a given parent note. Returns metadata for each child including ID, title, type, MIME type, and modification date. Useful for exploring note hierarchies.
Output schemas are completely undocumented. The rubric requires tools to document what fields they return so LLMs can plan downstream calls and extract needed data. None of the 11 tools show return type documentation in the provided source.
Tool descriptions contain concrete example values (e.g. 'data:application/pdf;base64,JVBERi0xLjcK...' in fileUri description, '[email protected]' implicitly referenced). Use enums and format constraints instead of examples in prose.
Several descriptions exceed 1024 characters (create_note content param: 900+ chars; update_note description itself is 1200+ chars), violating the rubric baseline of 10-1024 chars per description. Long descriptions waste tokens and bury key details.
| Scored | Grade | Overall | Spec posture | Rubric |
|---|---|---|---|---|
| 2026-09-22 | D | 57 | 2026-07-28+ | v2 |
| 2026-03-09 | F | 40 | - | v1 |
Create, update, delete, or batch create attributes (labels and relations) on a note. Supports single attribute operations and batch operations for efficiency.
Move a note to a different parent note. Maintains all note properties while changing its position in the hierarchy.
Apply partial updates to a note using JSON Patch format (RFC 6902). Allows targeted modifications without affecting other properties.
Read all attributes (labels and relations) for a specific note. Returns structured list of all labels and relations attached to the note.
Resolve a note name or title to its ID. Returns the note ID and metadata for notes matching the provided name, with options for exact matching and automatic selection.
Search notes by text content and optional criteria. Returns matching notes with metadata. Supports full-text search across all accessible notes.
Update note with support for title-only updates, content overwrite, content append, or file replacement. ⚠️ REQUIRED: ALWAYS call get_note first to obtain current hash. ⚠️ SIMPLER RULES: Note type and MIME type are IMMUTABLE - cannot be changed after creation. MODE SELECTION: Use 'append' when user wants to add/insert content (e.g., 'append to note', 'add to the end', 'insert content', 'add more content', 'continue writing', 'add to bottom'). Use 'overwrite' when replacing entire content (e.g., 'replace content', 'overwrite note', 'update the whole note', 'completely replace'). TITLE-ONLY: Efficient title changes without content modification. FILE UPDATES: Replace file content only with SAME file type (image→image, file→file). To change file types, create a new note instead. PREVENTS: Type mismatches, file type conflicts, and overwriting changes made by other users. ONLY use when user explicitly requests note update. WORKFLOW: get_note → review content → update_note with returned hash
searchCriteria parameter in search_notes is defined as type:'object' with no properties schema. This is unstructured and invites LLM hallucination. Either enumerate the supported criteria (type, attributes, dateRange) with their own schemas, or remove the parameter and add dedicated tools (search_notes_by_type, search_notes_by_date).
No tool annotations present. The schema definitions lack readOnlyHint (for get_, list_, search_, read_ tools), destructiveHint (for delete_, update_ on irreversible ops), and idempotentHint. Modern MCP servers declare these to guide agent behavior and safety.
Error handling is minimal. Tool descriptions like delete_note ('Delete a note permanently') do not include guidance on recovery ('Use get_note first to confirm the note exists; consider archiving instead of deletion if you need audit trails').
create_note and update_note accept parentNoteId and noteId as free-form strings. The description does not explain the expected format (is it a UUID? a path? a numeric ID?). Consider adding a resolve_note_id call guidance in the description.
search_notes accepts 'limit' but no pagination parameters (page, offset, cursor). Add page/offset or cursor parameters and return total_count or next_cursor.
create_note forceCreate parameter defaults to false (safe) but update_note revision parameter defaults to true. If an LLM omits revision, it will create revisions by default, good for safety but inconsistent with the forceCreate pattern. Document the rationale or make both default to safe values.