Docker Deployment¶
Quick start¶
docker compose up -d
The server listens on port 8000 with HTTP transport by default.
Image tags¶
| Tag | Contents | Updated by |
|---|---|---|
latest |
Newest stable release | Each stable release that is newest across all series |
vX.Y.Z |
That exact release (pre-releases included, as vX.Y.Z-rc.N) |
Never (immutable) |
vX.Y, vX |
Newest stable release in that series | Each stable release that is newest in its series |
rc |
Newest release candidate | Each pre-release still ahead of latest |
edge |
Newest commit on main |
Every merge to main |
Rolling tags are ordering-aware: a patch release cut from an old release/X.Y branch after a newer stable has shipped updates its own series tags but never latest. The same rule governs rc: a candidate only moves the tag while its version is still ahead of the newest stable, so a candidate for an already-released version never pulls rc behind latest.
The three rolling tags answer different questions. Use latest to run released code, rc to test the candidate for the next release, and edge to run the newest merged commit. Note that rc is not cleared when its release ships: it keeps pointing at the last candidate until the next one is cut, so latest is the tag to follow in production. To find the commit behind an edge image, read its org.opencontainers.image.revision label:
docker inspect --format '{{ index .Config.Labels "org.opencontainers.image.revision" }}' \
ghcr.io/pvliesdonk/paperless-mcp:edge
Environment variables¶
| Variable | Default | Description |
|---|---|---|
PAPERLESS_MCP_BEARER_TOKEN |
n/a | Enable bearer token auth |
FASTMCP_LOG_LEVEL |
INFO |
Log level (DEBUG / INFO / WARNING / ERROR) |
PAPERLESS_MCP_INSTRUCTIONS |
(computed at startup) | System instructions for LLM context |
PAPERLESS_MCP_DEBUG_PORT |
n/a | Remote-debugger TCP port (see Remote debugging; requires --build-arg DEBUG=true image) |
PAPERLESS_MCP_DEBUG_WAIT |
false |
Block startup until IDE attaches (see Remote debugging) |
For OIDC auth variables, see Authentication.
Running behind a reverse proxy on a path prefix (https://mcp.example.com/myservice/mcp) rather than its own hostname needs two routing rules, one of which sits outside the prefix: see Subpath Deployments.
Volumes¶
| Path | Purpose |
|---|---|
/data/service |
Your service data (bind-mount or named volume) |
/data/state |
State files (FastMCP OIDC state, etc.) |
UID/GID¶
Set PUID and PGID in your .env file to match the owner of bind-mounted
directories (default 1000/1000).
Remote debugging¶
Production images ship without debugpy to keep the image lean. To attach a remote Python debugger from VS Code or PyCharm:
-
Build with the debug extra:
docker build --build-arg DEBUG=true -t paperless-mcp:debug .This installs the
[debug]optional-dependency group (which pullsdebugpytransitively fromfastmcp-pvl-core). Default builds (DEBUG=false) skip it. -
Run with the debug env vars set and the port mapped:
docker run --rm \ -e PAPERLESS_MCP_DEBUG_PORT=5678 \ -e PAPERLESS_MCP_DEBUG_WAIT=true \ -p 127.0.0.1:5678:5678 \ -p 8000:8000 \ paperless-mcp:debugEnv var Effect PAPERLESS_MCP_DEBUG_PORTTCP port the debugger listens on (any value parsing to 0disables; non-numeric or out-of-range values log a WARNING and the listener stays off)PAPERLESS_MCP_DEBUG_WAITWhen truthy ( 1/true/yes/on), block startup until the IDE attaches. Default is non-blocking. -
Attach from VS Code, adding a launch config:
{ "name": "Attach to paperless-mcp", "type": "debugpy", "request": "attach", "connect": { "host": "localhost", "port": 5678 } }PyCharm uses Run → Edit Configurations → Python Debug Server with the same host/port.
Never publish the debug port on a public network
The debug listener binds 0.0.0.0 inside the container so the IDE can reach it from the host, but debugpy's DAP protocol is unauthenticated: any peer that can reach the port has arbitrary code execution as the server process. Always bind the port mapping to localhost (-p 127.0.0.1:5678:5678) or tunnel via kubectl port-forward / SSH. Production images should be built with default DEBUG=false.
When the helper is invoked but debugpy isn't installed (say, someone sets DEBUG_PORT on a non-debug image), it logs a WARNING and continues; this is the safe failure mode.