paperless-mcp
An authenticated Model Context Protocol server that exposes a Paperless-ngx instance over streamable HTTP with static bearer-token authentication, built with FastMCP.
Use it to: search and read archived documents, inspect Paperless metadata, download files, update document properties, and upload new documents from any HTTP-capable MCP client.
Why Paperless MCP?
- Useful document access: eight focused tools cover retrieval, metadata, downloads, updates, and ingestion.
- Read-only mode: one environment variable disables every mutating tool.
- Authenticated transport: every MCP request requires a dedicated bearer token independent from the Paperless API token.
- Self-hosted deployment: runs beside Paperless-ngx or on another private Linux host with the included systemd unit.
- No live-instance tests: the test suite uses mocked HTTP requests and never needs access to real documents.
Quick Start
Requirements: Python 3.11 or newer, a reachable Paperless-ngx instance, and uv.
The package is published on PyPI as trsdn-paperless-mcp; the command it
installs is paperless-mcp and the import name is paperless_mcp.
export PAPERLESS_URL=http://127.0.0.1:8000
export PAPERLESS_TOKEN=your-paperless-api-token
export PAPERLESS_MCP_TOKEN="$(openssl rand -hex 32)"
export PAPERLESS_READ_ONLY=1
uvx --from trsdn-paperless-mcp paperless-mcp
Alternatively install it permanently:
pip install trsdn-paperless-mcp
paperless-mcp # or: python -m paperless_mcp
To run from a checkout instead:
git clone https://github.com/trsdn/paperless-mcp.git
cd paperless-mcp
uv sync --locked --no-dev
uv run paperless-mcp
The server listens on http://0.0.0.0:8770/mcp by default. Keep the generated
MCP token secret and configure the same value in the client.
Available Tools
| Tool | Access | Purpose |
|---|---|---|
search_documents |
Read | Full-text and filtered document search |
get_document |
Read | Return metadata and optional OCR content |
download_document |
Read | Return an archived or original file as base64 |
list_tags |
Read | List Paperless tags |
list_correspondents |
Read | List Paperless correspondents |
list_document_types |
Read | List Paperless document types |
update_document |
Write | Update title, correspondent, type, or tags |
upload_document |
Write | Upload a file to the consume pipeline |
update_document and upload_document are disabled when
PAPERLESS_READ_ONLY=1. The compatibility default remains 0, so set the
variable explicitly for a read-only deployment.
Configuration
All configuration is via environment variables — see
deploy/paperless-mcp.env.example.
| Variable | Required | Default | Description |
|---|---|---|---|
PAPERLESS_URL |
yes | none | Base URL, e.g. http://127.0.0.1:8000 |
PAPERLESS_TOKEN |
yes | none | Paperless API token (Settings > API Tokens) |
PAPERLESS_MCP_TOKEN |
yes | none | Bearer token clients must send |
PAPERLESS_MCP_HOST |
no | 0.0.0.0 |
Bind host |
PAPERLESS_MCP_PORT |
no | 8770 |
Bind port |
PAPERLESS_MCP_PATH |
no | /mcp |
HTTP path |
PAPERLESS_READ_ONLY |
no | 0 |
Set 1 to disable writes |
Linux Service
curl -fsSLO https://raw.githubusercontent.com/trsdn/paperless-mcp/main/deploy/install.sh
less install.sh
sudo bash install.sh
sudoedit /etc/paperless-mcp/env
systemctl enable --now paperless-mcp
journalctl -u paperless-mcp -f
Generate a dedicated bearer token before editing the environment file:
openssl rand -hex 32
Development
uv sync --locked --all-groups
uv run ruff check .
uv run ruff format --check .
uv run pytest --cov=paperless_mcp --cov-fail-under=85
uv build
Tests use mocked HTTP requests and never require a live Paperless-ngx instance. CI runs on Python 3.11, 3.12, 3.13, and 3.14.
Client config
Local stdio-free launch (any client that spawns a command)
Clients that start the server themselves can invoke it via uvx:
{
"mcpServers": {
"paperless": {
"command": "uvx",
"args": ["--from", "trsdn-paperless-mcp", "paperless-mcp"],
"env": {
"PAPERLESS_URL": "http://127.0.0.1:8000",
"PAPERLESS_TOKEN": "your-paperless-api-token",
"PAPERLESS_MCP_TOKEN": "your-generated-mcp-token",
"PAPERLESS_READ_ONLY": "1"
}
}
}
}
The server then serves streamable HTTP on http://0.0.0.0:8770/mcp; point the
client at that URL as shown below.
Claude Desktop
Claude Desktop currently only speaks MCP over stdio, so use the
mcp-remote bridge:
// ~/Library/Application Support/Claude/claude_desktop_config.json
{
"mcpServers": {
"paperless": {
"command": "npx",
"args": [
"-y",
"mcp-remote",
"https://paperless-mcp.example.com/mcp",
"--header",
"Authorization: Bearer YOUR_PAPERLESS_MCP_TOKEN"
]
}
}
}
VS Code (mcp.json)
{
"servers": {
"paperless": {
"type": "http",
"url": "https://paperless-mcp.example.com/mcp",
"headers": {
"Authorization": "Bearer YOUR_PAPERLESS_MCP_TOKEN"
}
}
}
}
Security Model
- Prefer
PAPERLESS_READ_ONLY=1. Enable writes only for clients that require them and that you trust with document access. - Do not expose port 8770 directly to the public internet. Restrict network access and place the service behind a maintained reverse proxy with TLS.
- Use long, independent values for the Paperless API token and MCP bearer token. Never commit either token.
- The bearer token only protects the MCP layer. The Paperless API token
stored in
/etc/paperless-mcp/envcarries full account permissions, so the file is0640, owned bypaperless-mcp. - To rotate the bearer token: edit
/etc/paperless-mcp/env, thensystemctl restart paperless-mcp. - See SECURITY.md for vulnerability reporting and the supported security boundary.
Project
Licensed under the MIT License.
Metadata
Release files for trsdn-paperless-mcp 0.1.3
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| trsdn_paperless_mcp-0.1.3.tar.gz | 9.7 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| trsdn_paperless_mcp-0.1.3-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 19.1 kB
Release files / trsdn_paperless_mcp-0.1.3.tar.gz
| Download URL | trsdn_paperless_mcp-0.1.3.tar.gz |
|---|---|
| Size | 9.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f0731c8b80b3fbd7adc55804575280188f1efa3ec5eb60eb1d4a2e9fb7e03b91
|
|
BLAKE2b-256 checksum How to use checksums |
cb085aff5273548e4cc1b4cf70213cc1414c00a1f10650369dc3f542deaf9b8f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.
Transparency logRelease files / trsdn_paperless_mcp-0.1.3-py3-none-any.whl
| Download URL | trsdn_paperless_mcp-0.1.3-py3-none-any.whl |
|---|---|
| Size | 9.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
39efcd0c758d853df1ca6ecea11bb650c4fd61ed66267108f163f216b0765931
|
|
BLAKE2b-256 checksum How to use checksums |
c8a90aa10c3b7ffc0ead2b5a93badd33d3a933d42266706d78b2d7852538ecbf
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 24, 2026.
Transparency log