8.1 KiB
Running OverLeaf_MCP in Docker with Authentik Authentication
Run the OverLeaf_MCP server in Docker, secured with OAuth 2.1 via your existing Authentik instance, using mcp-auth-proxy. Only authenticated Qumo users can access your Overleaf account.
What this sets up
A single Docker container running:
- OverLeaf_MCP — the MCP server (stdio)
- mcp-auth-proxy — wraps it with OAuth 2.1 + automatic HTTPS (Let's Encrypt)
mcp-auth-proxy acts as the OAuth 2.1 authorization server toward Claude.ai (handling Dynamic Client Registration, PKCE, token issuance). It delegates user authentication to Authentik via standard OIDC. Authentik never touches the MCP protocol — it only answers "who is this person?".
Claude.ai ──OAuth 2.1──► mcp-auth-proxy ──stdio──► OverLeaf_MCP
│
(OIDC client)
│
▼
Authentik
(identity only)
Prerequisites
- A server with a public IP and ports 80 + 443 open
- A domain pointed at that IP (e.g.
overleaf-mcp.qumo.io) - Docker and Docker Compose
- Your existing Authentik instance (e.g.
auth.qumo.io) - A free Overleaf account
- Claude Pro/Team/Enterprise subscription
Step 1: Create the Authentik provider and application
In the Authentik admin UI at https://auth.qumo.io:
Create the provider
- Go to Applications → Providers → Create
- Select OAuth2/OpenID Provider (not Proxy Provider)
- Configure:
- Name:
Overleaf MCP Provider - Authentication flow: default
- Authorization flow:
default-provider-authorization-implicit-consent - Redirect URI (strict):
https://overleaf-mcp.qumo.io/oauth/callback - Signing key: select any available key
- Scopes: make sure
email,profile, andopenidare included
- Name:
- Click Finish
- Copy the Client ID and Client Secret
Create the application
- Go to Applications → Applications → Create
- Configure:
- Name:
Overleaf MCP - Slug:
overleaf-mcp - Provider: select the provider you just created
- Name:
- Click Create
Find the issuer URL
The OIDC issuer URL for Authentik follows this pattern:
https://auth.qumo.io/application/o/overleaf-mcp/
Where overleaf-mcp is the application slug. You can verify it works by visiting:
https://auth.qumo.io/application/o/overleaf-mcp/.well-known/openid-configuration
This should return a JSON document with authorization_endpoint, token_endpoint, etc.
Step 2: DNS
Create an A record for the MCP server subdomain:
overleaf-mcp.qumo.io → A → <your-server-ip>
If you're running this on the same VPS as Caddy, see the note at the bottom about using Caddy instead of Let's Encrypt.
Step 3: Configure the project
mkdir ~/apps/overleaf-mcp && cd ~/apps/overleaf-mcp
Place the Dockerfile, docker-compose.yml, and .env.example in this directory, then:
cp .env.example .env
nano .env
Fill in all values:
OVERLEAF_EMAIL=your@email.com
OVERLEAF_PASSWORD=your-overleaf-password
MCP_DOMAIN=overleaf-mcp.qumo.io
AUTHENTIK_ISSUER_URL=https://auth.qumo.io/application/o/overleaf-mcp/
AUTHENTIK_CLIENT_ID=<from step 1>
AUTHENTIK_CLIENT_SECRET=<from step 1>
ALLOWED_USER=you@qumo.io
The ALLOWED_USER field matches against the OIDC claims returned by Authentik. This is typically the email address. You can also use glob patterns like *@qumo.io to allow all users in your Authentik instance with a Qumo email.
Step 4: Build and start
docker compose up -d --build
Check logs:
docker compose logs -f
You should see mcp-auth-proxy provision a Let's Encrypt certificate and start listening on port 443.
Step 5: Connect Claude.ai
- Open claude.ai → Settings → Integrations
- Add a new MCP integration:
https://overleaf-mcp.qumo.io/mcp - Claude initiates the OAuth flow → you're redirected to Authentik to log in
- After authenticating, Claude is connected
Test it:
Call the ping tool
Step 6: First-time Overleaf login
If Overleaf shows a CAPTCHA during headless login:
- Install OverLeaf_MCP locally and log in once (outside Docker)
- Copy the session data into the Docker volume:
docker volume inspect overleaf-mcp_browser-data
sudo cp -r ~/.overleaf-mcp/browser-data/* \
/var/lib/docker/volumes/overleaf-mcp_browser-data/_data/
docker compose restart
Running on the same VPS as Caddy
If this runs on the same VPS where Caddy already occupies ports 80/443, you have two options:
Option A: Let mcp-auth-proxy handle its own TLS on different ports
Not ideal — Claude.ai expects standard HTTPS on 443.
Option B: Put it behind Caddy (recommended)
Remove the port bindings and Let's Encrypt from the container, and let Caddy handle TLS and proxying:
- In
docker-compose.yml, remove theports:section entirely and add the shared network:
services:
overleaf-mcp:
# ... everything else stays the same ...
# Remove ports: section
networks:
- qumo_services_proxy_network
command:
- --external-url
- https://${MCP_DOMAIN}
- --no-tls
- --port
- "8080"
- --oidc-issuer
- ${AUTHENTIK_ISSUER_URL}
- --oidc-client-id
- ${AUTHENTIK_CLIENT_ID}
- --oidc-client-secret
- ${AUTHENTIK_CLIENT_SECRET}
- --allowed-user
- ${ALLOWED_USER}
- --
- node
- /app/dist/index.js
networks:
qumo_services_proxy_network:
external: true
- Add to your Caddyfile (no
import authentik— mcp-auth-proxy handles auth):
overleaf-mcp.qumo.io {
reverse_proxy overleaf-mcp:8080
}
- Reload Caddy:
cd ~/networking/caddy
docker compose exec caddy caddy reload --config /etc/caddy/Caddyfile
Note: Check whether
mcp-auth-proxysupports--no-tlsand--portflags. If not, you can bind it to a high port with TLS disabled by using--tls-cert-fileand--tls-key-filewith self-signed certs, and let Caddy terminate real TLS in front. Consult the mcp-auth-proxy docs for current flags.
Fallback: password-only auth
If the OIDC flow doesn't work cleanly with Claude.ai's Dynamic Client Registration, you can fall back to password auth (confirmed working with Claude.ai):
command:
- --external-url
- https://${MCP_DOMAIN}
- --tls-accept-tos
- --password
- ${MCP_PASSWORD}
- --
- node
- /app/dist/index.js
Add MCP_PASSWORD=a-strong-random-password to .env. Claude.ai will prompt for this password when connecting.
Useful commands
# Logs
docker compose logs -f
# Restart
docker compose restart
# Full rebuild
docker compose down && docker compose build --no-cache && docker compose up -d
# Shell into the container
docker compose exec overleaf-mcp bash
# Extract PDFs
docker compose cp overleaf-mcp:/data/resumes/. ./my-resumes/
Troubleshooting
Let's Encrypt certificate fails — Ports 80 and 443 must be open and DNS must resolve. If Caddy already holds these ports, use the "behind Caddy" setup above.
OAuth callback error — Verify the redirect URI in Authentik matches exactly: https://overleaf-mcp.qumo.io/oauth/callback
"User not allowed" — Check that ALLOWED_USER matches what Authentik returns in its OIDC claims. Try *@qumo.io as a glob pattern, or check the claims by decoding the JWT token.
"Browser closed unexpectedly" — The compose file sets shm_size: "2gb" for Chromium. Make sure it's there.
Overleaf login times out — CAPTCHA issue. Use the session-copying approach from Step 6.
Claude.ai can't connect — Visit https://overleaf-mcp.qumo.io/.well-known/oauth-authorization-server in your browser. You should see a JSON metadata document. If not, the container isn't running or TLS isn't working.