Changes
diff --git a/skills/trilium/SKILL.md b/skills/trilium/SKILL.md
index b88aed6..479fbaa 100644
--- a/skills/trilium/SKILL.md
+++ b/skills/trilium/SKILL.md
@@ -44,3 +44,12 @@ Keep your notes up to date or capture new information.
## Notes on HTML Content
Trilium stores notes as HTML. When creating or updating notes, ensure the content is wrapped in appropriate HTML tags (e.g., `<p>`, `<ul>`, `<li>`) for best rendering in the Trilium UI.
+
+**Important formatting rules:**
+1. **Do NOT** include the note's title inside the HTML content (e.g., as an `<h1>`). Trilium displays the title separately at the top of the UI.
+2. Use semantic tags for sections, but start from `<h2>` or below if sub-headers are needed.
+
+## Templates and Attributes
+You can create notes that inherit from a specific template and set attributes in a single call.
+- **Template**: Use `templateNoteId` in `create_note`.
+- **Attributes**: Use the `attributes` array in `create_note` or `create_attribute` separately for setting labels and relations.
diff --git a/skills/trilium/mcp/src/handlers.py b/skills/trilium/mcp/src/handlers.py
index 188fd2f..77bede8 100644
--- a/skills/trilium/mcp/src/handlers.py
+++ b/skills/trilium/mcp/src/handlers.py
@@ -55,18 +55,48 @@ class ToolHandlers:
},
{
"name": "create_note",
- "description": "Create a new note in Trilium.",
+ "description": "Create a new note in Trilium. Can optionally specify a template and attributes.",
"inputSchema": {
"type": "object",
"properties": {
"parentNoteId": {"type": "string", "description": "ID of parent note (default 'root')."},
"title": {"type": "string", "description": "Title of the note."},
"content": {"type": "string", "description": "HTML content for the note."},
- "type": {"type": "string", "description": "Type of note (e.g., 'text').", "default": "text"}
+ "type": {"type": "string", "description": "Type of note (e.g., 'text').", "default": "text"},
+ "templateNoteId": {"type": "string", "description": "Optional: ID of a template note to inherit from."},
+ "attributes": {
+ "type": "array",
+ "description": "Optional: List of attributes (labels or relations) to add.",
+ "items": {
+ "type": "object",
+ "properties": {
+ "type": {"type": "string", "enum": ["label", "relation"]},
+ "name": {"type": "string"},
+ "value": {"type": "string"},
+ "isInheritable": {"type": "boolean", "default": False}
+ },
+ "required": ["type", "name", "value"]
+ }
+ }
},
"required": ["title", "content"]
}
},
+ {
+ "name": "create_attribute",
+ "description": "Create a new attribute (label or relation) for a note.",
+ "inputSchema": {
+ "type": "object",
+ "properties": {
+ "noteId": {"type": "string", "description": "ID of the note to add the attribute to."},
+ "type": {"type": "string", "enum": ["label", "relation"]},
+ "name": {"type": "string", "description": "Name of the attribute."},
+ "value": {"type": "string", "description": "Value of the attribute."},
+ "isInheritable": {"type": "boolean", "description": "Whether the attribute is inheritable.", "default": False}
+ },
+ "required": ["noteId", "type", "name", "value"]
+ }
+ },
{
"name": "update_note_content",
"description": "Update the content of an existing note.",
@@ -93,12 +123,39 @@ class ToolHandlers:
return self.client.getNoteChildren(params["noteId"])
elif name == "create_note":
parent_note_id = params.get("parentNoteId", "root")
- return self.client.createNote(
+ note_data = self.client.createNote(
parent_note_id,
params["title"],
params["content"],
params.get("type", "text")
)
+ note_id = note_data["note"]["noteId"]
+
+ # Handle optional template inheritance
+ if params.get("templateNoteId"):
+ self.client.createAttribute(
+ note_id, "relation", "template", params["templateNoteId"]
+ )
+
+ # Handle additional attributes
+ if params.get("attributes"):
+ for attr in params["attributes"]:
+ self.client.createAttribute(
+ note_id,
+ attr["type"],
+ attr["name"],
+ attr["value"],
+ attr.get("isInheritable", False)
+ )
+ return note_data
+ elif name == "create_attribute":
+ return self.client.createAttribute(
+ params["noteId"],
+ params["type"],
+ params["name"],
+ params["value"],
+ params.get("isInheritable", False)
+ )
elif name == "update_note_content":
self.client.updateNoteContent(params["noteId"], params["content"])
return f"Successfully updated note content for {params['noteId']}."
diff --git a/skills/trilium/mcp/src/trilium_client.py b/skills/trilium/mcp/src/trilium_client.py
index 460e271..64b006b 100644
--- a/skills/trilium/mcp/src/trilium_client.py
+++ b/skills/trilium/mcp/src/trilium_client.py
@@ -49,12 +49,19 @@ class TriliumClient:
def getNoteChildren(self, note_id: str) -> List[Dict[str, Any]]:
"""List children of a specified note."""
- # ETAPI pattern to list notes with a specific parent
+ # Note: In some versions, parentNoteId must be explicitly in query or the search query
response = requests.get(
f"{self.url}/etapi/notes",
params={"parentNoteId": note_id},
headers=self._get_headers()
)
+ if response.status_code == 400:
+ # Fallback to searching for children if direct query fails
+ response = requests.get(
+ f"{self.url}/etapi/notes",
+ params={"search": f"parent.noteId = '{note_id}'"},
+ headers=self._get_headers()
+ )
response.raise_for_status()
return response.json()
@@ -66,8 +73,26 @@ class TriliumClient:
"content": content,
"type": type
}
+ # Note: Using /etapi/create-note instead of /etapi/notes for compatibility
response = requests.post(
- f"{self.url}/etapi/notes",
+ f"{self.url}/etapi/create-note",
+ json=payload,
+ headers=self._get_headers("application/json")
+ )
+ response.raise_for_status()
+ return response.json()
+
+ def createAttribute(self, note_id: str, type: str, name: str, value: str, is_inheritable: bool = False) -> Dict[str, Any]:
+ """Create a new attribute (label or relation) for a note."""
+ payload = {
+ "noteId": note_id,
+ "type": type,
+ "name": name,
+ "value": value,
+ "isInheritable": is_inheritable
+ }
+ response = requests.post(
+ f"{self.url}/etapi/attributes",
json=payload,
headers=self._get_headers("application/json")
)