How to search documents with AI agents using MCP

Run the GroupDocs.Search MCP server locally in Docker, ask your agent to index a folder, and it can answer which documents say X and what exactly they say — three tool calls, no upload:

docker run --rm -i -v $(pwd)/documents:/data \
  ghcr.io/groupdocs-search/search-net-mcp:latest

Index the contracts folder, then tell me which contracts mention a termination penalty and quote the clause.

Note
The commands and config snippets on this page are for the .NET build of the server, which ships as a Docker image only. Installation and client setup: MCP server for .NET. Other platforms will expose the same tools with their own launch command; everything else on this page applies unchanged.

Prerequisites

  • Docker, and the server registered in your AI client — quick start.
  • The folder mounted at /data. On Linux, add --user "$(id -u):$(id -g)".

The pattern

user              agent                         Search MCP server
 |  "Which contracts mention a termination penalty?"           |
 |---------------->|                                           |
 |                 |-- add_to_index ------------------------->|  reads the
 |                 |   {"documentsPath":"contracts",           |  files once,
 |                 |    "indexName":"contracts"}               |  stores text
 |                 |<- "5 document(s) added, 5 in the index" --|
 |                 |-- search ------------------------------->|
 |                 |   {"query":"termination AND penalty"}     |
 |                 |<- {"documentsFound":3, "documents":[ ... |  which files
 |                 |     "contracts/acme-...-agreement.pdf",   |
 |                 |     "contracts/globex-...-agreement.docx",|
 |                 |     "contracts/initech-nda.docx" ]}       |
 |                 |-- get_text_fragments ------------------->|
 |                 |   {"query":"\"termination penalty\""}     |
 |                 |<- === contracts/acme-...-agreement.pdf ===|  the passages
 |                 |   ...a termination penalty of three       |
 |                 |   monthly fees applies...                 |
 |<- "Two contracts carry one: Acme (3 monthly fees, 12.3),    |
 |    Globex (50% of the remaining fees). Initech excludes it."|
  1. Index once — add_to_index reads the files and stores their text in a named index.
  2. Find the files — search returns the matching documents as JSON.
  3. Quote the passages — get_text_fragments returns each match with words of context.

What the agent sees

Captured from server 26.10.1 against five synthetic contracts (evaluation note trimmed):

-> add_to_index {"documentsPath":"contracts","indexName":"contracts"}
<- Indexed 'contracts' into index 'contracts': 5 document(s) added, 5 in
   the index.

-> search {"query":"termination AND penalty","indexName":"contracts"}
<- { "documentsFound": 3, "totalOccurrences": 9, "documents": [
     { "filePath": "contracts/acme-master-services-agreement.pdf", ... },
     { "filePath": "contracts/globex-consulting-agreement.docx", ... },
     { "filePath": "contracts/initech-nda.docx", ... } ] }

-> get_text_fragments {"query":"\"termination penalty\"",
                       "indexName":"contracts"}
<- === contracts/acme-master-services-agreement.pdf (1 occurrence(s)) ===
     [content] …terminates before the end of the Term, a termination
   penalty of three monthly fees applies, payable within 30…
   === contracts/globex-consulting-agreement.docx (1 occurrence(s)) ===
     [content] …Early termination penalty: the Client pays 50 percent of
   the fees…

The agent’s answer: two contracts carry a termination penalty — Acme (three monthly fees, clause 12.3) and Globex (50% of the remaining fees); the Initech NDA mentions both words but excludes a penalty. That last part came from reading the passages, which is why the third call matters.

Expected result

File names with the quoted passage for each, in seconds after the first indexing. The index stays in /data/.groupdocs-search-index/contracts, so a follow-up question costs two calls, not a re-read.

The two query rules worth memorising

  • Quote phrases. termination penalty without quotes finds nothing; the server returns a hint saying so. Use "termination penalty" or termination AND penalty.
  • content: before a date range. A bare daterange(…) also matches the file dates the engine indexes. More: find documents by date and amount.

The full language: search.

Troubleshooting

SymptomCauseFix
"documentsFound": 0 with a hintan unquoted multi-word queryquote the phrase, or join the words with AND
“Path ‘x’ not found in storage” with a file lista host path instead of a storage-relative onepass contracts, not /home/me/contracts
“The index folder … is not writable”Linux, container user does not own the folderadd --user "$(id -u):$(id -g)"

FAQ

Do I need a vector database or an embedding model? No. The index is a local full-text index; nothing calls a model or a network service.

How big can the folder be? In evaluation mode, 100 documents per index and 10 per result. Licensed, the limits come from disk and memory; very large corpora index once and update incrementally.

Can the agent search several indexes? Yes — one call per index. Name indexes by project or corpus (contracts, mail, reports).

Add to your CLAUDE.md or AGENTS.md

Agents follow project instructions about when to use a tool. Paste this into the instruction file your agent reads (CLAUDE.md, AGENTS.md, .github/copilot-instructions.md, .cursorrules):

Before reading documents in ./documents, use the groupdocs-search MCP server:
search (quote multi-word phrases) to find the files, then get_text_fragments
to quote the passages. Cite file and passage. Never read whole files to search.

Honest limits

  • Evaluation mode: an index holds at most 100 documents and a search returns at most 10 — the response says so in its evaluation field. Licensing.
  • Full-text, not semantic: it matches words, not meaning. Ask the agent to try variants (OR, fuzzy: true).
  • No OCR: scans without a text layer are indexed by their file properties only.
  • Docker only: there is no dnx channel for this product (why).

Read more