Skip to main content
Glama
chrisguidry

paperless-mcp

by chrisguidry

Search documents

search_documents
Read-only

Search and filter Paperless documents by full text, tags, correspondents, dates, document types, and custom fields to find specific records, or locate documents similar to a given one.

Instructions

Search and filter documents in the archive.

All parameters combine as AND conditions, except that query and more_like_document_id cannot be used together. query is full-text search over document contents using tantivy syntax: plain terms ("electric bill"), boolean operators ("chase AND (mortgage OR escrow)"), field prefixes ("correspondent:university", "type:invoice", "tag:unpaid", "created:[2020 to 2023]"), and wildcards ("electr*"). Notes and custom fields are structured fields with dotted paths: "notes.note:reimbursed", "custom_fields.value:overdue", "custom_fields.name:warranty". Plain terms do NOT match them, only titles and content. Full-text results include a search_hit with highlights.

more_like_document_id finds documents whose text is similar to one document's, ranked by similarity in search_hit.rank. The results leave out that document itself, and the other filters narrow them. Leave ordering unset to keep the ranking.

To find unfiled documents, use is_in_inbox=true, or has_tags, has_correspondent, has_document_type, or has_storage_path set to false.

custom_field_query compares custom field values, like "Amount over 100" or "Warranty Expires before 2027-01-01". Every field type supports exact, in, exists, and isnull. Date, integer, float, and monetary fields add gt, gte, lt, lte, and range. String, URL, long text, and monetary fields add icontains, istartswith, and iendswith. Document link fields add contains. Paperless refuses an operator that the field's type does not support.

Each result carries a uri, which you can read as an MCP resource for the document's full text, and a web_url that links to the document in the Paperless web UI. Read paperless://documents/{id}/notes for a document's notes, or call get_document for its notes and custom field values.

Input Schema

NameRequiredDescriptionDefault
pageNoPage number, starting at 1 (default: 1)
queryNoFull-text query in tantivy syntax, described above (default: none)
tag_idsNoMatch documents that have ALL of these tags (default: none)
has_tagsNotrue matches documents with at least one tag, and false matches documents with no tags (default: none)
orderingNoField to sort by. Prefix it with "-" for descending order, like "-created". Without it, full-text results are ranked by relevance (default: none)
page_sizeNoNumber of documents per page (default: 25)
added_afterNoMatch documents added to the archive at or after this ISO 8601 date and time (default: none)
any_tag_idsNoMatch documents that have at least one of these tags (default: none)
is_in_inboxNotrue matches documents with at least one inbox tag, and false matches documents with none (default: none)
added_beforeNoMatch documents added to the archive at or before this ISO 8601 date and time (default: none)
created_afterNoMatch documents dated on or after this date, as YYYY-MM-DD (default: none)
created_beforeNoMatch documents dated on or before this date, as YYYY-MM-DD (default: none)
title_containsNoCase-insensitive substring of the title (default: none)
storage_path_idNoMatch documents filed under this storage path (default: none)
content_containsNoCase-insensitive substring of the text content (default: none)
correspondent_idNoMatch documents from or to this correspondent (default: none)
document_type_idNoMatch documents of this type (default: none)
excluded_tag_idsNoMatch documents that have NONE of these tags (default: none)
has_storage_pathNotrue matches documents with a storage path, and false matches documents without one (default: none)
has_correspondentNotrue matches documents with a correspondent, and false matches documents without one (default: none)
has_document_typeNotrue matches documents with a document type, and false matches documents without one (default: none)
custom_field_queryNoConditions on custom field values, described above. Name each field by its ID or exact name from list_custom_fields (default: none)
more_like_document_idNoMatch documents similar to the document with this ID. Cannot be combined with query (default: none)

Output Schema

NameRequiredDescriptionDefault
documentsYes
paginationYesThe position of one page of results in the full result set.

Schema Changelog

Changes observed during successful MCP inspections.

  1. First observedv0.1.0

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations only declare read-only and closed-world; the description adds much more: all filters combine as AND, `query` and `more_like_document_id` are mutually exclusive, similarity results exclude the seed document and are ranked in search_hit.rank unless `ordering` is set, and 'Paperless refuses an operator that the field's type does not support'. These are non-obvious behavioral constraints an agent could not infer from the annotations.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and the AND/mutual-exclusion rules, then organized into paragraphs per parameter family, which is appropriate for a 23-parameter tool. It loses a point because the custom_field_query paragraph restates operator-by-type rules the schema already enumerates at length, and the final paragraph about uri/web_url borders on return-value explanation that the output schema covers.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 23-parameter search tool with an output schema, the description covers the semantics that actually determine correct invocation: filter combination logic, query syntax, the query/more_like_document_id exclusion, ranking behavior, and the unfiled-document shortcut. Nothing an agent needs in order to construct a correct call is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters5/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline would be 3, but the description adds meaning the schema cannot express: concrete tantivy syntax with worked examples, the field prefixes available (correspondent, type, tag, created), the crucial caveat that 'Plain terms do NOT match' notes and custom fields, and dotted-path syntax for structured fields. That is well beyond what the JSON Schema conveys.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opening sentence states a specific verb and resource with scope ('Search and filter documents in the archive'), immediately telling the agent this is a query tool over the whole archive rather than a per-document fetch. It also names the sibling it is not ('call get_document for its notes and custom field values'), so it is distinguishable from get_document without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives real routing guidance: 'To find unfiled documents, use is_in_inbox=true, or has_tags, has_correspondent... set to false', and 'Leave `ordering` unset to keep the ranking'. It also redirects to get_document / the notes resource when the agent wants notes or custom field values. What is missing is an explicit statement of when to prefer this over a direct get_document lookup by ID, so it stops just short of full when/when-not coverage.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.