Quick start¶
You need Trilium Notes 0.106 or later, Docker Compose, and a reverse proxy that serves HTTPS (Caddy, Traefik, nginx, Cloudflare Tunnel, …).
1. Turn on Trilium's MCP server¶
In Trilium Notes: Options → AI / LLM, switch on MCP server. Trilium now serves /mcp.
2. Add the proxy next to Trilium¶
In the same docker-compose.yaml as Trilium:
services:
trilium:
image: triliumnext/trilium:v0.106.1
# ...
trilium-mcp-proxy:
image: ghcr.io/marceltov/trilium-mcp-proxy:latest # or pin a version
restart: unless-stopped
environment:
TRILIUM_SERVER_URL: http://trilium:8080
MCP_BASE_URL: https://trilium-mcp-proxy.example.org # the public URL, behind your TLS proxy
MCP_OAUTH_SECRET: ${MCP_OAUTH_SECRET} # openssl rand -hex 32
MCP_INSTRUCTIONS: |
Optional standing instructions every client sees at connect.
volumes:
- mcp-proxy-oauth:/data
ports:
- "8081:8081"
volumes:
mcp-proxy-oauth:
Put the secret in a .env file next to the compose file:
echo "MCP_OAUTH_SECRET=$(openssl rand -hex 32)" >> .env
docker compose up -d trilium-mcp-proxy
TRILIUM_SERVER_URL is Trilium as the proxy reaches it: in the same compose project that's the service name, here http://trilium:8080.
3. Publish it over HTTPS¶
Point your reverse proxy at port 8081 under the hostname in MCP_BASE_URL. With Caddy:
trilium-mcp-proxy.example.org {
reverse_proxy localhost:8081
}
MCP_BASE_URL must match the public URL exactly: it's the OAuth issuer, and clients compare it byte for byte. Plain http is only accepted for localhost.
Check it:
curl https://trilium-mcp-proxy.example.org/health
# {"status": "ok", "trilium": "ok"}
"trilium": "unreachable" means the proxy runs but can't reach TRILIUM_SERVER_URL.
4. Connect a client¶
Add https://trilium-mcp-proxy.example.org/mcp to your client and log in with your Trilium Notes password. See Connect a client.