The Paperclip MCP container image is a production-ready, non-root Alpine image designed exclusively for MCP stdio transport: no network ports are exposed, and the process communicates entirely over stdin/stdout. You can pull the pre-built image from GitHub Container Registry, build it locally with a single command, or bring up the full Paperclip control plane alongside the MCP server using the included Compose file — all without Node.js on the host.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.
Pre-built image
The latest stable image is published at:Building locally
Two-stage build
TheDockerfile uses a two-stage build to keep the final image lean:
| Stage | Base image | Purpose |
|---|---|---|
| builder | node:22-slim (glibc) | Installs all deps (including devDeps) and compiles TypeScript via tsc |
| runtime | node:22-alpine (musl) | Production-only deps, compiled dist/, tini init, non-root mcp user |
@modelcontextprotocol/sdk and zod are pure JavaScript — no native compilation is needed, making the musl libc in Alpine fully compatible. Typical final image size: ~186 MB.
Running via .mcp.json
Add the paperclip entry to your MCP host config file. The -e KEY form (without =value) passes the value from the outer env map into the container without embedding secrets in the args array.
Keep secrets in
env, not args. The -e KEY pattern (no =value in the args array) forwards the value from env into the container at runtime without embedding it in the command string.Environment variables
| Variable | Default | Purpose |
|---|---|---|
PAPERCLIP_API_KEY | — (required) | Bearer token for the Paperclip API |
PAPERCLIP_API_URL | — (required) | Base URL, e.g. http://127.0.0.1:3100 |
PAPERCLIP_AGENT_ID | — (required) | UUID of the agent running this MCP session |
PAPERCLIP_COMPANY_ID | — (required) | UUID of the Paperclip company/tenant |
PAPERCLIP_RUN_ID | (auto) | Optional execution run ID for mutation tracing |
PAPERCLIP_REQUEST_TIMEOUT_MS | 30000 | HTTP request timeout in milliseconds |
Networking
Local Paperclip server
When the Paperclip API runs on the same host (e.g.http://127.0.0.1:3100), use --network=host so the container can reach the host’s loopback interface:
Remote Paperclip server
When connecting to a remote API, omit--network=host and set PAPERCLIP_API_URL to the full public URL:
Security hardening
The image is built with defence-in-depth from the start:- Non-root execution — A dedicated
mcpuser (uid 1001, gid 1001) is created in the runtime stage. The Node.js process always runs as this user; root is never required at runtime. - No network ports — The image has no
EXPOSEdirective. The MCP server communicates exclusively via stdio, so there is no inbound network attack surface. - Minimal runtime image — Only
dist/, productionnode_modules, andtiniare present in the final stage. DevDependencies, test files, TypeScript source, and.husky/hooks are excluded. - Alpine base, 0 OS CVEs —
node:22-alpinecarries zero OS-layer CVEs at release time (verified with Trivy). The only Trivy findings are in npm’s own bundled modules (/usr/local/lib/node_modules/npm/), which are not part of the application and are unreachable from a stdio-only server. - No capabilities required — Run with
--cap-drop=allfor maximum hardening if your container runtime supports it.
Signal handling
tini runs as PID 1 via the image entrypoint:
tini forwards SIGTERM to the Node.js process, which the MCP SDK translates into a clean shutdown — draining in-flight requests and closing the stdio transport gracefully. This ensures that podman stop or docker stop results in a clean exit rather than a hard SIGKILL after the stop timeout. tini is installed from Alpine’s official package registry (apk add --no-cache tini).
Smoke testing the image
After building locally, verify the image boots and enumerates tools correctly:initialize handshake followed by tools/list and asserts that the response contains exactly 104 tools.
Compose stack
To run the full Paperclip control plane server alongside the MCP process, use the included Compose file. This is the fastest way to get a complete local Paperclip environment running.Start the stack
paperclip service (the control plane API) on 127.0.0.1:3100 by default.The Compose file also includes an optional
postgres service under the external-db profile. To use an external PostgreSQL database instead of the default embedded storage, run: podman-compose --profile external-db up -d and set DATABASE_URL in your .env file.See also
- Claude Code guide — wiring the container into Claude Code
- Cursor guide — wiring the container into Cursor
- VS Code guide — wiring the container into VS Code
- Troubleshooting — container not starting, network errors, auth failures