Paperless-ngx Document Management
Orchestrate Paperless-ngx through 42 MCP tools across 9 domains.
Tool Catalog
Documents (7 tools)
| Tool |
Operation |
Key Params |
search_documents |
Full-text search |
query, page, page_size |
get_document |
Full details |
id |
update_document |
Patch single doc |
id, title, archive_serial_number, custom_fields, note |
delete_document_note |
Remove a note |
id, note_id |
post_document |
Upload file |
file_path (local) or file (base64), metadata |
download_document |
Get file base64 |
id, original (bool) |
bulk_edit_documents |
Batch operations |
documents (IDs), method, params |
Tags (6 tools)
| Tool |
Operation |
list_tags |
All tags + colors + matching |
get_tag |
Single tag by ID |
create_tag |
New tag, optional auto-match |
update_tag |
Modify name/color/matching |
delete_tag |
Deprecated — use bulk_edit_tags operation=delete |
bulk_edit_tags |
Batch permissions/deletion |
Correspondents (5 tools)
| Tool |
Operation |
list_correspondents |
All correspondents |
get_correspondent |
Single correspondent by ID |
create_correspondent |
New, optional auto-match |
update_correspondent |
Modify name/matching rules |
bulk_edit_correspondents |
Batch permissions/delete |
Document Types (5 tools)
| Tool |
Operation |
list_document_types |
All document types |
get_document_type |
Single type by ID |
create_document_type |
New, optional auto-match |
update_document_type |
Modify name/matching rules |
bulk_edit_document_types |
Batch permissions/delete |
Storage Paths (4 tools)
| Tool |
Operation |
list_storage_paths |
All storage paths |
create_storage_path |
New path template + auto-match |
update_storage_path |
Modify name/template/matching |
bulk_edit_storage_paths |
Batch permissions/delete |
Custom Fields (4 tools)
| Tool |
Operation |
list_custom_fields |
All field definitions + IDs |
create_custom_field |
New field (name + data type) |
update_custom_field |
Modify name/data type/options |
delete_custom_field |
Delete one field + its values everywhere |
Tasks (2 tools)
| Tool |
Operation |
get_task |
Status + resulting doc IDs for a post_document UUID |
list_tasks |
Recent tasks newest-first; filter status/name, max 100 |
Trash (3 tools)
| Tool |
Operation |
list_trash |
Soft-deleted documents awaiting purge |
restore_from_trash |
Bring documents back with metadata intact |
empty_trash |
PERMANENTLY purge (all, or specific IDs) |
Mail (6 tools)
| Tool |
Operation |
list_mail_accounts |
Polled accounts (credentials stripped) |
process_mail_account |
Trigger an immediate mail poll |
list_mail_rules |
Filters that decide what gets imported |
create_mail_rule |
New import rule (filters + assignments) |
update_mail_rule |
Modify filters/assignments/enabled |
delete_mail_rule |
Remove a rule (future ingestion only) |
Decision Trees
Find a Document
What do you know?
├─ Keywords/content → search_documents(query="term1 term2")
├─ Document ID → get_document(id=N)
├─ By tag → search_documents(query="tag:tagname")
├─ By type → search_documents(query="type:typename")
├─ By correspondent → search_documents(query="correspondent:name")
├─ By date → search_documents(query="created:[2024 to 2025]")
└─ Combined → search_documents(query="tag:X correspondent:Y created:[2024 to 2025]")
Organize Documents
What operation?
├─ Rename title → update_document(id=N, title="...")
├─ Set/clear ASN → update_document(id=N, archive_serial_number=N|null)
├─ Custom fields → update_document(id=N, custom_fields=[{field, value}]) (IDs via list_custom_fields)
├─ Add note → update_document(id=N, note="...")
├─ Remove note → delete_document_note(id=N, note_id=NID)
├─ Add tag → bulk_edit_documents(method="add_tag", tag=ID)
├─ Remove tag → bulk_edit_documents(method="remove_tag", tag=ID)
├─ Multi-tag → bulk_edit_documents(method="modify_tags", add_tags=[...], remove_tags=[...])
├─ Set type → bulk_edit_documents(method="set_document_type", document_type=ID)
├─ Set sender → bulk_edit_documents(method="set_correspondent", correspondent=ID)
├─ Merge PDFs → bulk_edit_documents(method="merge", metadata_document_id=ID)
├─ Rotate pages → bulk_edit_documents(method="rotate", degrees=90|180|270)
├─ Delete pages → bulk_edit_documents(method="delete_pages", pages=[1, 3, 5])
├─ Reprocess OCR → bulk_edit_documents(method="reprocess")
├─ Delete → bulk_edit_documents(method="delete") → goes to TRASH
├─ Undo a delete → list_trash → restore_from_trash(documents=[...])
└─ Purge for good → empty_trash(documents=[...]) !! PERMANENT !!
Upload a Document
1. Resolve metadata IDs first:
├─ list_tags → find or create_tag
├─ list_correspondents → find or create_correspondent
└─ list_document_types → find or create_document_type
2. post_document(file_path="~/Downloads/name.pdf", tags=[...], correspondent=ID, ...)
→ returns a task UUID, not a document ID
(file=<base64> + filename also works, but only for small files)
3. get_task(task_id=<uuid>) until status="SUCCESS"
→ related_document holds the new document ID
Lost the UUID? → list_tasks(task_name="consume_file") shows recent uploads;
list_tasks(status="FAILURE") shows rejected ones (e.g. duplicates)
Manage Taxonomy (Tags/Correspondents/Types)
Need to change metadata objects?
├─ View all → list_tags / list_correspondents / list_document_types /
│ list_storage_paths / list_custom_fields
│ (all take an optional name= substring filter)
├─ Resolve one ID → get_tag / get_correspondent / get_document_type
├─ Create new → create_tag / create_correspondent / create_document_type /
│ create_storage_path / create_custom_field
├─ Edit tag → update_tag(id, name, color, match, matching_algorithm)
├─ Edit sender → update_correspondent(id, name, match, matching_algorithm)
├─ Edit type → update_document_type(id, name, match, matching_algorithm)
├─ Edit storage path → update_storage_path(id, name, path, match, matching_algorithm)
├─ Edit custom field → update_custom_field(id, name, data_type, extra_data)
├─ Batch delete/perm → bulk_edit_tags / bulk_edit_correspondents /
│ bulk_edit_document_types / bulk_edit_storage_paths
└─ Del custom field → delete_custom_field(id) !! drops values from all docs !!
Critical Notes
- search_documents strips
content to save tokens. Use get_document for
full OCR text.
- post_document prefers
file_path: the MCP server reads the file from
its own filesystem, so size doesn't matter. Inline base64 (file +
filename) passes through the model: small files only. file_path works
on the stdio transport only; the HTTP transport rejects it.
- matching_algorithm is integer
0-6 across all endpoints (tags,
correspondents, document types): 0=none, 1=any, 2=all, 3=exact,
4=regex, 5=fuzzy, 6=auto. See tools.md.
- Mail rules shape FUTURE ingestion. create/update/delete_mail_rule change
what the next mail polls import; already-consumed documents are untouched.
Pause with
enabled=false instead of deleting. Mail account credentials
never appear in responses and cannot be set via MCP (web UI only).
- Document binaries are MCP resources: read
paperless://documents/{id}/archive|original|thumbnail via resources/read
instead of pulling base64 through download_document; pass
as_resource_link=true to download_document to get the link. Thumbnail =
cheap preview without the full file.
- Document delete is a soft-delete:
bulk_edit_documents(method="delete")
moves documents to the trash, restorable via restore_from_trash until the
retention period expires or empty_trash purges them. Taxonomy deletes
(tags, correspondents, document types, storage paths, custom fields) are
immediate and permanent.
- download_document returns base64 blob + filename from content-disposition.
- list_tags, list_correspondents, and list_document_types return
complete paginated result sets; use IDs from
results, not the bare all ID
list alone.
- bulk_edit_documents accepts top-level MCP fields, but Paperless receives a
nested
parameters object internally. The MCP tool forwards only the fields
relevant to the selected method.
- update_document is single-document only (title/ASN/custom fields/note).
The backend bulk endpoint has no
set_title method — use update_document
to rename; keep tags/correspondent/type in bulk_edit_documents. note
appends a note (notes live on a separate Paperless endpoint internally);
remove one with delete_document_note.
- Notes are an append-only log. A document can hold multiple notes, each
with its own timestamp and author. There is no edit operation — not in the
API, not in the web UI; this is by design (log semantics). To correct an
earlier note, append a new one (e.g. "correction: ..."). Reserve
delete_document_note for entries that truly must go — deleting rewrites
history.
- post_document returns a task UUID, not a document ID. Poll
get_task(task_id) until status="SUCCESS"; related_document then
holds the resulting document ID.
- custom field values need IDs from list_custom_fields. Resolve the field
name → numeric ID there before calling
update_document.custom_fields or
bulk_edit_documents.modify_custom_fields.
- delete_tag is deprecated (removal in v3.0.0) — use
bulk_edit_tags with
operation="delete", consistent with correspondents, document types, and
storage paths.
- delete_custom_field is single-delete only — the backend has no bulk
endpoint for custom fields. Deletion is permanent and drops the field's
values from every document that uses it.
References
| Task |
File |
| Tool parameters & types |
tools.md |
| Search query syntax |
query-syntax.md |
| Multi-step workflows |
workflows.md |
1---2name: paperless-ngx3description: Manages documents in Paperless-ngx via MCP tools. Searches, uploads, tags, organizes, and bulk-edits documents, correspondents, and document types. Use when working with Paperless-ngx, document management, OCR, or any mcp_paperless_* tool task.4license: MIT5---67# Paperless-ngx Document Management89Orchestrate Paperless-ngx through 42 MCP tools across 9 domains.1011## Tool Catalog1213### Documents (7 tools)1415| Tool | Operation | Key Params |16| ---------------------- | ---------------- | --------------------------------------------------------------- |17| `search_documents` | Full-text search | `query`, `page`, `page_size` |18| `get_document` | Full details | `id` |19| `update_document` | Patch single doc | `id`, `title`, `archive_serial_number`, `custom_fields`, `note` |20| `delete_document_note` | Remove a note | `id`, `note_id` |21| `post_document` | Upload file | `file_path` (local) or `file` (base64), metadata |22| `download_document` | Get file base64 | `id`, `original` (bool) |23| `bulk_edit_documents` | Batch operations | `documents` (IDs), `method`, params |2425### Tags (6 tools)2627| Tool | Operation |28| ---------------- | -------------------------------------------------------- |29| `list_tags` | All tags + colors + matching |30| `get_tag` | Single tag by ID |31| `create_tag` | New tag, optional auto-match |32| `update_tag` | Modify name/color/matching |33| `delete_tag` | **Deprecated** — use `bulk_edit_tags` `operation=delete` |34| `bulk_edit_tags` | Batch permissions/deletion |3536### Correspondents (5 tools)3738| Tool | Operation |39| -------------------------- | -------------------------- |40| `list_correspondents` | All correspondents |41| `get_correspondent` | Single correspondent by ID |42| `create_correspondent` | New, optional auto-match |43| `update_correspondent` | Modify name/matching rules |44| `bulk_edit_correspondents` | Batch permissions/delete |4546### Document Types (5 tools)4748| Tool | Operation |49| -------------------------- | -------------------------- |50| `list_document_types` | All document types |51| `get_document_type` | Single type by ID |52| `create_document_type` | New, optional auto-match |53| `update_document_type` | Modify name/matching rules |54| `bulk_edit_document_types` | Batch permissions/delete |5556### Storage Paths (4 tools)5758| Tool | Operation |59| ------------------------- | ------------------------------ |60| `list_storage_paths` | All storage paths |61| `create_storage_path` | New path template + auto-match |62| `update_storage_path` | Modify name/template/matching |63| `bulk_edit_storage_paths` | Batch permissions/delete |6465### Custom Fields (4 tools)6667| Tool | Operation |68| --------------------- | ---------------------------------------- |69| `list_custom_fields` | All field definitions + IDs |70| `create_custom_field` | New field (name + data type) |71| `update_custom_field` | Modify name/data type/options |72| `delete_custom_field` | Delete one field + its values everywhere |7374### Tasks (2 tools)7576| Tool | Operation |77| ------------ | ------------------------------------------------------ |78| `get_task` | Status + resulting doc IDs for a `post_document` UUID |79| `list_tasks` | Recent tasks newest-first; filter status/name, max 100 |8081### Trash (3 tools)8283| Tool | Operation |84| -------------------- | ----------------------------------------- |85| `list_trash` | Soft-deleted documents awaiting purge |86| `restore_from_trash` | Bring documents back with metadata intact |87| `empty_trash` | PERMANENTLY purge (all, or specific IDs) |8889### Mail (6 tools)9091| Tool | Operation |92| ---------------------- | --------------------------------------- |93| `list_mail_accounts` | Polled accounts (credentials stripped) |94| `process_mail_account` | Trigger an immediate mail poll |95| `list_mail_rules` | Filters that decide what gets imported |96| `create_mail_rule` | New import rule (filters + assignments) |97| `update_mail_rule` | Modify filters/assignments/enabled |98| `delete_mail_rule` | Remove a rule (future ingestion only) |99100## Decision Trees101102### Find a Document103104```txt105What do you know?106├─ Keywords/content → search_documents(query="term1 term2")107├─ Document ID → get_document(id=N)108├─ By tag → search_documents(query="tag:tagname")109├─ By type → search_documents(query="type:typename")110├─ By correspondent → search_documents(query="correspondent:name")111├─ By date → search_documents(query="created:[2024 to 2025]")112└─ Combined → search_documents(query="tag:X correspondent:Y created:[2024 to 2025]")113```114115### Organize Documents116117```txt118What operation?119├─ Rename title → update_document(id=N, title="...")120├─ Set/clear ASN → update_document(id=N, archive_serial_number=N|null)121├─ Custom fields → update_document(id=N, custom_fields=[{field, value}]) (IDs via list_custom_fields)122├─ Add note → update_document(id=N, note="...")123├─ Remove note → delete_document_note(id=N, note_id=NID)124├─ Add tag → bulk_edit_documents(method="add_tag", tag=ID)125├─ Remove tag → bulk_edit_documents(method="remove_tag", tag=ID)126├─ Multi-tag → bulk_edit_documents(method="modify_tags", add_tags=[...], remove_tags=[...])127├─ Set type → bulk_edit_documents(method="set_document_type", document_type=ID)128├─ Set sender → bulk_edit_documents(method="set_correspondent", correspondent=ID)129├─ Merge PDFs → bulk_edit_documents(method="merge", metadata_document_id=ID)130├─ Rotate pages → bulk_edit_documents(method="rotate", degrees=90|180|270)131├─ Delete pages → bulk_edit_documents(method="delete_pages", pages=[1, 3, 5])132├─ Reprocess OCR → bulk_edit_documents(method="reprocess")133├─ Delete → bulk_edit_documents(method="delete") → goes to TRASH134├─ Undo a delete → list_trash → restore_from_trash(documents=[...])135└─ Purge for good → empty_trash(documents=[...]) !! PERMANENT !!136```137138### Upload a Document139140```txt1411. Resolve metadata IDs first:142 ├─ list_tags → find or create_tag143 ├─ list_correspondents → find or create_correspondent144 └─ list_document_types → find or create_document_type1452. post_document(file_path="~/Downloads/name.pdf", tags=[...], correspondent=ID, ...)146 → returns a task UUID, not a document ID147 (file=<base64> + filename also works, but only for small files)1483. get_task(task_id=<uuid>) until status="SUCCESS"149 → related_document holds the new document ID150Lost the UUID? → list_tasks(task_name="consume_file") shows recent uploads;151 list_tasks(status="FAILURE") shows rejected ones (e.g. duplicates)152```153154### Manage Taxonomy (Tags/Correspondents/Types)155156```txt157Need to change metadata objects?158├─ View all → list_tags / list_correspondents / list_document_types /159│ list_storage_paths / list_custom_fields160│ (all take an optional name= substring filter)161├─ Resolve one ID → get_tag / get_correspondent / get_document_type162├─ Create new → create_tag / create_correspondent / create_document_type /163│ create_storage_path / create_custom_field164├─ Edit tag → update_tag(id, name, color, match, matching_algorithm)165├─ Edit sender → update_correspondent(id, name, match, matching_algorithm)166├─ Edit type → update_document_type(id, name, match, matching_algorithm)167├─ Edit storage path → update_storage_path(id, name, path, match, matching_algorithm)168├─ Edit custom field → update_custom_field(id, name, data_type, extra_data)169├─ Batch delete/perm → bulk_edit_tags / bulk_edit_correspondents /170│ bulk_edit_document_types / bulk_edit_storage_paths171└─ Del custom field → delete_custom_field(id) !! drops values from all docs !!172```173174## Critical Notes175176- **search_documents strips `content`** to save tokens. Use `get_document` for177 full OCR text.178- **post_document prefers `file_path`**: the MCP server reads the file from179 its own filesystem, so size doesn't matter. Inline base64 (`file` +180 `filename`) passes through the model: small files only. `file_path` works181 on the stdio transport only; the HTTP transport rejects it.182- **matching_algorithm** is integer `0-6` across all endpoints (tags,183 correspondents, document types): `0`=none, `1`=any, `2`=all, `3`=exact,184 `4`=regex, `5`=fuzzy, `6`=auto. See [tools.md](references/tools.md).185- **Mail rules shape FUTURE ingestion.** create/update/delete_mail_rule change186 what the next mail polls import; already-consumed documents are untouched.187 Pause with `enabled=false` instead of deleting. Mail account credentials188 never appear in responses and cannot be set via MCP (web UI only).189- **Document binaries are MCP resources**: read190 `paperless://documents/{id}/archive|original|thumbnail` via resources/read191 instead of pulling base64 through download_document; pass192 `as_resource_link=true` to download_document to get the link. Thumbnail =193 cheap preview without the full file.194- **Document delete is a soft-delete**: `bulk_edit_documents(method="delete")`195 moves documents to the trash, restorable via `restore_from_trash` until the196 retention period expires or `empty_trash` purges them. Taxonomy deletes197 (tags, correspondents, document types, storage paths, custom fields) are198 immediate and permanent.199- **download_document** returns base64 blob + filename from content-disposition.200- **list_tags**, **list_correspondents**, and **list_document_types** return201 complete paginated result sets; use IDs from `results`, not the bare `all` ID202 list alone.203- **bulk_edit_documents** accepts top-level MCP fields, but Paperless receives a204 nested `parameters` object internally. The MCP tool forwards only the fields205 relevant to the selected `method`.206- **update_document** is single-document only (title/ASN/custom fields/note).207 The backend bulk endpoint has no `set_title` method — use `update_document`208 to rename; keep tags/correspondent/type in `bulk_edit_documents`. `note`209 appends a note (notes live on a separate Paperless endpoint internally);210 remove one with `delete_document_note`.211- **Notes are an append-only log.** A document can hold multiple notes, each212 with its own timestamp and author. There is no edit operation — not in the213 API, not in the web UI; this is by design (log semantics). To correct an214 earlier note, append a new one (e.g. "correction: ..."). Reserve215 `delete_document_note` for entries that truly must go — deleting rewrites216 history.217- **post_document returns a task UUID, not a document ID.** Poll218 `get_task(task_id)` until `status="SUCCESS"`; `related_document` then219 holds the resulting document ID.220- **custom field values need IDs from list_custom_fields.** Resolve the field221 name → numeric ID there before calling `update_document.custom_fields` or222 `bulk_edit_documents.modify_custom_fields`.223- **delete_tag is deprecated** (removal in v3.0.0) — use `bulk_edit_tags` with224 `operation="delete"`, consistent with correspondents, document types, and225 storage paths.226- **delete_custom_field is single-delete only** — the backend has no bulk227 endpoint for custom fields. Deletion is permanent and drops the field's228 values from every document that uses it.229230## References231232| Task | File |233| ----------------------- | --------------------------------------------- |234| Tool parameters & types | [tools.md](references/tools.md) |235| Search query syntax | [query-syntax.md](references/query-syntax.md) |236| Multi-step workflows | [workflows.md](references/workflows.md) |