Marcel Bruckner

#trilium#ai#claude

trilium-mcp-proxy: log in to Trilium's MCP server with your password

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 /mcp request goes to Trilium unchanged, with only Authorization swapped. The tools are exactly Trilium’s, so new ones arrive with Trilium updates, without a proxy release.
  • House rules. Optionally, MCP_INSTRUCTIONS adds standing instructions to Trilium’s initialize answer, 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.

← All posts

This post also lives on notefeed ↗