@myceliumhq/tri
v2.6.0
Published
Agent-facing CLI for TriliumNext Notes, over its ETAPI REST API. Also ships a standalone MCP server for shell-less hosts.
Maintainers
Readme
tri
An agent-facing CLI for TriliumNext Notes, talking to its ETAPI REST API. Search, read, write, and lightly organize notes -- covering the same workflows you'd otherwise do by hand in Trilium's own UI.
Built for coding agents: token-cheap --help, deterministic exit codes, file-path-based
attachment I/O (bytes never round-trip through an agent's context), and no prompts in piped/agent
contexts (interactive TTY deletes ask for confirmation).
A standalone MCP server is also included, for hosts without a shell.
Use
Install globally so tri is a plain command on PATH -- the resolve/download-check npx does on
every single call adds up fast across an agent's many small invocations:
npm install --global @myceliumhq/tri
export TRILIUM_URL=https://trilium.example.com
export TRILIUM_TOKEN=your-etapi-token # Options -> ETAPI -> Create new ETAPI token
tri doctor
tri search "#book #year >= 1950"
tri note read abc123
tri note create root --title "Project notes" --content "# Plan"
tri note append abc123 --file notes.md
tri note delete abc123 --yes
tri note undelete abc123
tri note revision list abc123
tri tree root --depth 3
tri journal today
tri attach add abc123 ./diagram.pngNo install available? Fall back to npx @myceliumhq/tri <command> (fetches and caches on first
run, same commands otherwise) -- but prefer the global install whenever you can, per above.
See tri <command> --help for flags on any command, or the bundled skill
(skills/trilium/SKILL.md) for the full command reference and decision guidance.
Semantic search
tri search is Trilium's own lexical/attribute query language by default. Optional semantic
search is available as a separate sidecar, tri-semanticd -- this package's own binary, built on
@myceliumhq/semanticd with this repo's Trilium
adapter wired in directly. Run it alongside your Trilium instance and it syncs a local vector
index:
export TRILIUM_URL=https://trilium.example.com
export TRILIUM_TOKEN=your-etapi-token
export EMBEDDING_PROVIDER=local # zero-API-key CPU model; or openai-compatible, see semanticd's README
tri-semanticd # or: npx -p @myceliumhq/tri tri-semanticdOr as a container: ghcr.io/myceliumhq/tri-semanticd:<version> (built from Dockerfile.semanticd,
published on every tagged release). Once it's running, point both the CLI and the standalone MCP
server below at it with TRILIUM_SEMANTICD_URL -- tri search fuses its own lexical results with
the sidecar's over HTTP (GET /query?q=...) automatically, no separate mode to pick:
export TRILIUM_SEMANTICD_URL=http://localhost:4499
tri search "book recommendations"Unset (or the sidecar unreachable), tri search transparently falls back to lexical-only --
nothing to configure to keep using it without a sidecar.
On "no results": semantic search has no reliable "nothing matches" signal by itself --
cosine-similarity nearest-neighbor search always returns something, and a nonsense query can
score within a few hundredths of a genuinely relevant one against the same index (live-tested, not
theoretical). So the semantic score is not a calibrated confidence measure; don't threshold on it.
When fusion is active, --json rows include match_source (lexical | semantic | both) and,
for semantic hits, semantic_score -- and if a query returns results with zero lexical hits
(match_source is semantic for everything), tri search prints a stderr warning, since that's
the actual "this query likely found nothing real" signal, not an empty result list.
Standalone MCP server
The same functionality also runs outside a shell entirely, as an ordinary MCP server (stdio or
Streamable HTTP), via @myceliumhq/mcp.
Useful for any MCP client -- Claude Desktop, Claude Code, etc.
Configuration is env vars instead of a config file:
| Env var | Required | Notes |
| --- | --- | --- |
| TRILIUM_URL | yes | Base URL of the Trilium instance |
| TRILIUM_TOKEN | yes | ETAPI token |
| TRILIUM_URL_FILE / TRILIUM_TOKEN_FILE | no | Docker-secret variants: path to a file whose trimmed contents are used instead |
| TRILIUM_READ_ONLY | no | Set to exactly true to register only read tools -- write tools aren't registered at all, so they can't be listed or called. Not a substitute for authenticating the HTTP transport |
| TRILIUM_SEMANTICD_URL | no | Base URL of a deployed tri-semanticd sidecar (see "Semantic search" above). Unset falls back to lexical/attribute-only search |
| TRILIUM_SEMANTIC_SEARCH_ENABLED | no | Set to exactly false to skip semantic search even if TRILIUM_SEMANTICD_URL is set |
| MCP_TRANSPORT | no | stdio (default) or http |
| MCP_PORT | no | Only used with MCP_TRANSPORT=http; default 3000 |
| MCP_HOST | no | Only used with MCP_TRANSPORT=http; default 127.0.0.1 (loopback-only). Set to 0.0.0.0 only behind an authenticated reverse proxy, and only with MCP_ALLOWED_HOSTS set (or startup fails) |
| MCP_ALLOWED_HOSTS | no | Comma-separated hostnames the server accepts in Host (DNS-rebinding protection). Required when MCP_HOST=0.0.0.0 |
pnpm run build
TRILIUM_URL=https://trilium.example.com TRILIUM_TOKEN=your-etapi-token pnpm run start:mcpA Dockerfile is included for building a container image locally (Dockerfile.semanticd for the
semantic search sidecar above).
Development
See CONTRIBUTING.md for dev setup, regenerating API types, and commit conventions.
