{
  "markdown": "# trilium-mcp\n\nAn [MCP](https://modelcontextprotocol.io) server that lets AI agents (Claude Desktop, Claude Code, any MCP-compatible client) read and write a self-hosted [TriliumNext](https://github.com/TriliumNext/Notes) knowledge base over its [ETAPI](https://github.com/TriliumNext/Notes/wiki/ETAPI).\n\nSingle static Go binary. No runtime dependencies. Talks to your local Trilium over HTTP(S) and to the client over stdio.\n\n## Why\n\nTriliumNext is a strong personal KB: tree-of-notes with attributes (labels, relations) that double as table columns / board lanes / calendar events. This MCP exposes the right slice of ETAPI so an agent can:\n\n- Capture stuff into your notes (reading lists, decisions, research dumps).\n- Maintain structured \"tables\" by creating notes-as-rows under a parent and tagging them with labels-as-columns.\n- Search your existing KB and feed snippets back into a conversation.\n\nIt is intentionally minimal: ten tools, ~600 lines of Go, zero clever abstractions.\n\n## Tools\n\n| Tool | Purpose |\n| --- | --- |\n| `create_note` | Create a note (optionally under a parent, with labels in one shot). |\n| `batch_create_notes` | Create many notes in one call — saves per-call schema overhead during restructuring. |\n| `get_note` | Fetch note metadata; optionally include body content. |\n| `get_note_subtree` | Recursively fetch a note + descendants up to N levels as a nested tree — replaces N+1 `get_note` calls. |\n| `update_note` | Partial update: include only the fields you want to change; omitted fields stay as-is. |\n| `append_content` | Append text to the body with a configurable separator. |\n| `delete_note` | Delete a note and its subtree. |\n| `batch_delete_notes` | Delete many notes; partial failures don't stop the rest. |\n| `move_note` | Re-parent a note in two ETAPI calls (vs the old read-recreate-delete dance). |\n| `clone_note` | Add the note under an additional parent — Trilium-native multi-parent links. |\n| `delete_branch` | Remove one parent-child link without deleting the note (un-clone). |\n| `search_notes` | Full-power Trilium search (`#label`, `~relation`, `note.title %= \"regex\"`, ancestor scoping, etc.). |\n| `add_label` | Attach a label (`#key=value`) — acts as a \"column\" in collection views. |\n| `add_relation` | Attach a relation (`~name → noteId`) — like a foreign key between notes. |\n| `remove_attribute` | Remove a label or relation by its attribute id. |\n| `list_attributes` | List all labels and relations on a note. |\n\n## Quick start\n\n### 1. Run TriliumNext\n\nIf you don't already have one:\n\n```yaml\n# docker-compose.yml\nservices:\n  trilium:\n    image: triliumnext/notes:latest\n    ports:\n      - \"8092:8080\"\n    volumes:\n      - ./data:/home/node/trilium-data\n```\n\n```bash\ndocker compose up -d\n```\n\nOpen `http://localhost:8092/`, finish the setup wizard, then **Options → ETAPI → Create new ETAPI token**. Copy the token (shown only once).\n\n### 2. Install trilium-mcp\n\n**Pre-built binary** (recommended) — grab the right archive from [Releases](https://github.com/OVDEN13/trilium-mcp/releases).\n\n**From source** with Go 1.23+:\n\n```bash\ngo install github.com/OVDEN13/trilium-mcp@latest\n```\n\n**With Docker** (no Go on host):\n\n```bash\ngit clone https://github.com/OVDEN13/trilium-mcp && cd trilium-mcp\ndocker build -t trilium-mcp .\n```\n\n### 3. Configure\n\nCopy `.env.example` to `.env` next to the binary:\n\n```env\nTRILIUM_URL=http://localhost:8092\nTRILIUM_TOKEN=your-etapi-token-here\n# Optional:\n# TRILIUM_HTTP_TIMEOUT_SECONDS=30\n```\n\nOr pass the same as real environment variables — the server reads either.\n\n### 4. Register with your MCP client\n\n**Claude Code** (CLI):\n\n```bash\nclaude mcp add --scope user trilium /path/to/trilium-mcp \\\n  --env TRILIUM_URL=http://localhost:8092 \\\n  --env TRILIUM_TOKEN=your-token\n```\n\n**Claude Desktop** — add to `~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) or the equivalent on your OS:\n\n```json\n{\n  \"mcpServers\": {\n    \"trilium\": {\n      \"command\": \"/absolute/path/to/trilium-mcp\",\n      \"env\": {\n        \"TRILIUM_URL\": \"http://localhost:8092\",\n        \"TRILIUM_TOKEN\": \"your-token\"\n      }\n    }\n  }\n}\n```\n\nRestart the client. The ten tools should show up as `trilium__*`.\n\n## Usage patterns\n\n### \"Database\" of notes (the killer feature)\n\nTrilium's collection views (Table / Board / Calendar) render any note's children based on shared labels. So a \"table\" is just a parent note + child notes + a consistent label schema:\n\n```\nBooks (parent)\n├── \"Atomic Habits\"   #status=read    #rating=9   #author=Clear\n├── \"Antifragile\"     #status=read    #rating=8   #author=Taleb\n└── \"Деньги\"          #status=reading             #author=Жонсон\n```\n\nAn agent populates it like this:\n\n```jsonc\n// 1. Create the row\ncreate_note({\n  parent_note_id: \"<id of Books>\",\n  title: \"Atomic Habits\",\n  labels: { \"status\": \"read\", \"rating\": \"9\", \"author\": \"Clear\" }\n})\n\n// 2. Query rows later\nsearch_notes({ query: \"#status=read #rating>=8\", ancestor_note_id: \"<id of Books>\" })\n```\n\nFlip the parent's view to **Table** (or **Board** by `status`, or **Calendar** by a date label) in the Trilium UI and you have a database without ever leaving notes.\n\n### Append-only log\n\n```jsonc\nappend_content({ note_id: \"<journal id>\", content: \"Decided to ship v0.2 on Monday.\" })\n```\n\n`append_content` is non-destructive — handy for daily journals, decision logs, ideation dumps.\n\n## Trilium search cheat sheet\n\n- `#tag` — note has label `tag`.\n- `#status=active` — label equals.\n- `#rating>=8` — numeric comparison.\n- `~author.title *= \"Clear\"` — follow a relation, match relation target's title.\n- `note.title %= \"^Re:\"` — regex on title.\n- `note.content *= \"kubernetes\"` — substring in body.\n- `#status=active OR #status=pending` — boolean.\n- Combine with `ancestor_note_id` to scope to a subtree.\n\nFull reference: [Trilium search docs](https://github.com/TriliumNext/Notes/wiki/Search).\n\n## Environment variables\n\n| Var | Default | Notes |\n| --- | --- | --- |\n| `TRILIUM_URL` | *required* | Base URL of your Trilium instance, e.g. `http://localhost:8092`. The `/etapi` path is added automatically, but a trailing `/etapi` is tolerated and stripped (so `http://localhost:8092/etapi` also works). Accepts multiple URLs separated by commas — the server tries them in order and falls back to the next one on transport errors (DNS/connection/timeout). HTTP errors like 404 are returned immediately without retry. Example: `http://192.168.0.10:8092,https://memo.example.com` (fast LAN first, public fallback). |\n| `TRILIUM_TOKEN` | *required* | ETAPI token from Trilium settings |\n| `TRILIUM_HTTP_TIMEOUT_SECONDS` | `30` | Per-request timeout |\n| `TRILIUM_MCP_LOG` | `info` | `off` / `info` / `debug`. Logs are written to **stderr** (stdout is reserved for the MCP JSON-RPC stream). `info` shows one line per tool call with name + duration + ok/error. `debug` also shows the request arguments and a truncated preview of the response. |\n\n## Building from source\n\n```bash\ngit clone https://github.com/OVDEN13/trilium-mcp\ncd trilium-mcp\ngo build -ldflags=\"-s -w\" -o trilium-mcp .\n```\n\nCross-compile (e.g. for macOS from Linux):\n\n```bash\nGOOS=darwin GOARCH=arm64 CGO_ENABLED=0 go build -o trilium-mcp-darwin-arm64 .\n```\n\n## Security notes\n\n- The server reads `TRILIUM_TOKEN` from env. Treat it like a password — anyone with it can read and write your entire KB. Keep `.env` out of git (it is in `.gitignore`).\n- The binary speaks **only** to your configured Trilium URL. It does not phone home, log to disk, or open any listening ports.\n- HTTPS works automatically (the binary ships with system CAs when run from the host; the Docker image includes `ca-certificates`).\n\n## Contributing\n\nPRs welcome. Useful directions:\n\n- Stream large note bodies instead of buffering.\n- `move_note` / `clone_note` tools.\n- Bulk operations (`add_label_to_many`).\n- ETAPI v2 features as TriliumNext adds them.\n- Tests against an ephemeral TriliumNext container.\n\nFor substantive changes, please open an issue first to discuss the shape.\n\n## License\n\n[MIT](./LICENSE).\n\n`trilium-mcp` is an independent project; it is not endorsed by or affiliated with the TriliumNext project. TriliumNext itself is AGPL-3.0; this MCP server talks to it only over its public ETAPI.\n",
  "bytes": 8228,
  "sha": "691f5624a7ee13ab5a9f054757bfa8b2664db5b0bc9c4d7e01a6302dc05afe83",
  "repo_slug": "ovden13/trilium-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_ovden13_trilium_mcp_64369298/readme"
}