Running the full Paperclip stack locally lets you develop agent workflows against a real control plane without touching a production environment. The compose files ship two configurations: a default stack using an embedded PGlite database (zero configuration required), and an external-db profile that adds a full PostgreSQL container for teams needing a durable relational backend. The MCP server (Documentation Index
Fetch the complete documentation index at: https://mintlify.com/bruhsb/paperclip-mcp/llms.txt
Use this file to discover all available pages before exploring further.
paperclip-mcp) is not a compose service — it is a stdio subprocess spawned by Claude Code that communicates with the running Paperclip server over HTTP.
Prerequisites
| Requirement | Minimum version | Check |
|---|---|---|
| Podman | 3.4 | podman --version |
| podman-compose | 1.0 | podman-compose --version |
| Docker (alternative) | 20.10 | docker --version |
| docker compose plugin (alternative) | v2.1 | docker compose version |
| Free RAM | 2 GB | — |
| Free disk | 1 GB | — |
What the compose stack includes
Bothpodman-compose.yaml and docker-compose.yaml define the same two services:
| Service | Container name | Image | Profile |
|---|---|---|---|
paperclip | paperclip | ghcr.io/paperclipai/paperclip:${PAPERCLIP_VERSION} | Always active |
postgres | paperclip-postgres | docker.io/library/postgres:${POSTGRES_VERSION:-17.9-alpine} | external-db only |
network_mode: host. The Paperclip server binds to 127.0.0.1:3100 (configurable via PORT). Telemetry is disabled by default (PAPERCLIP_TELEMETRY_DISABLED=1).
Named volumes:
| Volume | Mounted at | Contents |
|---|---|---|
paperclip-data | /paperclip | Embedded PGlite database, uploaded files, secrets, workspace data |
paperclip-pg-data | /var/lib/postgresql/data | PostgreSQL data directory (external-db profile only) |
Starting the stack
Set
BETTER_AUTH_SECRET to any string of at least 32 characters. The server will refuse to start without it — even in local_trusted mode.curl -s http://localhost:3100/api/health
# Expected: HTTP 200 with a JSON body indicating healthy status.
Environment variables
The following variables are read from.env (or the host environment):
| Variable | Required | Default | Description |
|---|---|---|---|
BETTER_AUTH_SECRET | Yes | — | Auth secret, minimum 32 characters. Server throws at startup if absent. |
PAPERCLIP_VERSION | No | sha-b8725c5 | Image tag for the Paperclip server. |
PORT | No | 3100 | HTTP port the server binds to. |
PAPERCLIP_DEPLOYMENT_MODE | No | local_trusted | Deployment mode. local_trusted removes auth overhead for local dev. |
SERVE_UI | No | true | Serve the React dashboard from the same process. |
PAPERCLIP_TELEMETRY_DISABLED | No | 1 | Set to 1 to disable telemetry (also honours DO_NOT_TRACK=1). |
DATABASE_URL | No (external-db only) | — | PostgreSQL connection string, e.g. postgres://paperclip:CHANGE_ME@127.0.0.1:5432/paperclip. |
POSTGRES_PASSWORD | No (external-db only) | — | Required when using the external-db profile. |
POSTGRES_USER | No | paperclip | PostgreSQL user. |
POSTGRES_DB | No | paperclip | PostgreSQL database name. |
POSTGRES_PORT | No | 5432 | PostgreSQL port. |
External PostgreSQL (optional)
Theexternal-db profile adds a postgres service. Use this when you need a full relational backend — for larger teams or when you want to inspect the database directly.
In .env, set or uncomment:
127.0.0.1:5432 without any port publishing. Paperclip has built-in retry logic and connects as soon as PostgreSQL is ready (expect ~5–10 seconds of ECONNREFUSED log noise before the first successful migration query — this is harmless and self-recovering).
Connecting Claude Code to the local stack
paperclip-mcp is a stdio subprocess — not a compose service. Add the following to your Claude Code .mcp.json to point it at the local server:
--network=host is required so the containerized MCP process can reach http://127.0.0.1:3100 on the host loopback. The image tag should match MCP_VERSION in your .env.Common operations
Version upgrades
Stopping and cleanup
Troubleshooting
Server fails to start: auth-secret error
Server fails to start: auth-secret error
BETTER_AUTH_SECRET is mandatory in all deployment modes, including local_trusted. Set it in .env to any string of at least 32 characters:Port conflict on 3100
Port conflict on 3100
Another process is listening on port 3100. Find and stop it:Alternatively, set
PORT in .env to a different port and update PAPERCLIP_API_URL in .mcp.json to match.Rootless UID mismatch — permission denied on volume
Rootless UID mismatch — permission denied on volume
If you see
EACCES: permission denied, mkdir '/paperclip/...' in container logs, the volume mount path or ownership is incorrect. The Paperclip image runs as the node user (UID 1000). The /paperclip directory is pre-owned by node:node in the image, so named volumes require no extra chown step — but the volume must mount at /paperclip, not /root/.paperclip.Ensure PAPERCLIP_HOME=/paperclip (the default in both compose files). For a clean start:Healthcheck failing / container stuck in (health: starting)
Healthcheck failing / container stuck in (health: starting)
First boot runs all database migrations. Allow up to 30 seconds (Common causes: missing
start_period: 30s is set in the healthcheck). If the container remains unhealthy after 2–3 minutes:BETTER_AUTH_SECRET, DATABASE_URL pointing to an unreachable host, or a stale volume from a failed previous run (try down -v for a clean start).SELinux permission denied (Fedora / RHEL)
SELinux permission denied (Fedora / RHEL)
If Podman reports an SELinux denial when accessing the volume, verify that the volume mounts in
podman-compose.yaml include :Z. The :Z label sets the SELinux private unshared context on the volume’s backing directory. It is present in the provided podman-compose.yaml by default. The docker-compose.yaml omits :Z intentionally — Docker Desktop does not require it.