Since 0.106, Trilium has an MCP server built in, at /mcp. That’s great news for anyone who uses Claude or another assistant with their notes: no more third-party server translating ETAPI into tools. It also meant the end of my own trilium-mcp, which did exactly that for two months and is archived now.
One thing was left: the login. Trilium’s MCP server takes an ETAPI token in the Authorization header. So for every client you create a token under Options → ETAPI, paste it into that client’s configuration, and remember where you put it. trilium-mcp-proxy removes that step.
What it does
You add the proxy’s URL to any MCP client (claude.ai, Claude Code, the Claude desktop and mobile apps) and log in once in the browser with your Trilium password. That’s it.
- Your password stays on your server. The login page is the proxy’s own, next to Trilium. The password goes from your browser to it and on to Trilium’s
/etapi/auth/login, which creates an ETAPI token for that client. The proxy never stores or logs the password, and the client only ever sees opaque OAuth tokens that work nowhere else. - Two-factor works. With TOTP switched on in Trilium, the login page asks for the code (since 0.1.1).
- It’s transparent. Every
/mcprequest goes to Trilium unchanged, with onlyAuthorizationswapped. The tools are exactly Trilium’s, so new ones arrive with Trilium updates, without a proxy release. - House rules. Optionally,
MCP_INSTRUCTIONSadds standing instructions to Trilium’sinitializeanswer, which every client reads when it connects. Mine says: there is an LLM wiki here, read its schema before writing, mark pages as AI-assisted, never write under Sources. - Revoking is simple. Each login is its own ETAPI token in Options → ETAPI. Delete it there, and that client is out.
Running it
Switch on Trilium’s MCP server (Options → AI / LLM → MCP server), then add one service next to Trilium:
trilium-mcp-proxy:
image: ghcr.io/marceltov/trilium-mcp-proxy:latest
restart: unless-stopped
environment:
TRILIUM_SERVER_URL: http://trilium:8080
MCP_BASE_URL: https://trilium-mcp-proxy.example.org # public URL, behind your TLS proxy
MCP_OAUTH_SECRET: ${MCP_OAUTH_SECRET} # openssl rand -hex 32
volumes:
- mcp-proxy-oauth:/data
ports:
- "8081:8081"
On claude.ai: Customize → Connectors → Add custom connector with https://trilium-mcp-proxy.example.org/mcp. In Claude Code:
claude mcp add --transport http trilium https://trilium-mcp-proxy.example.org/mcp -s user
# then /mcp → Authenticate
It uses about 20 MiB. I run one per Trilium instance (three in our household); I built a mode that serves several instances from one container and threw it away, because it saved little and tied all three to one secret and one failure point.
Gotchas with the built-in tools
Moving my plugins from trilium-mcp to Trilium’s own tools turned up a few differences worth knowing: they read and write Markdown, not HTML; set_attribute replaces an attribute of the same name; move_note on a cloned note moves only its original placement; and there is no tool for day notes, note maps or ZIP export yet. trilium-plugin and trilium-llm-wiki work around these.
The goal: retire it
The proxy is a stopgap. Trilium already has a login with password, TOTP and OpenID; it only needs to speak OAuth for MCP clients. I’ve proposed that upstream in TriliumNext/Trilium#12309: Trilium’s normal login plus a consent page, the access token being an ETAPI token named after the client, off by default, no schema change. If the maintainers agree, I’d like to build it, and then this proxy can go.
It’s licensed AGPL-3.0-or-later. Setup details are in the docs.
Discussion on GitHub: TriliumNext discussion #12310.