Every new chat starts with an agent that has forgotten your documents. It can re-read them, at the cost of time and context, or it can consult something that remembers. GroupDocs.Search.Mcp keeps a named full-text index on disk, locally, that survives between sessions and container restarts, so Claude Desktop, Cursor or Copilot starts each session with the project’s documents already searchable and refreshes them with one call when files change:

I edited some contracts. Refresh the contracts index, then tell me which contracts mention a penalty now.

The step-by-step version with config and troubleshooting is in the documentation: How to keep a document index current as files change.

What does “memory” mean for an agent?

In practice, two things: state that persists outside the conversation, and a cheap way to keep that state true. Chat history fails both: it ends with the session, and nothing updates it when a document changes. A search index is a better fit for documents. It lives on disk next to them, it answers “which files say X” without loading them, and it can be refreshed incrementally.

session 1    add_to_index --> index "contracts" --+
                                                 |  kept on disk in
session 2    search, get_text_fragments <--------+  /data/.groupdocs-search-
             (nothing is re-read)                    index/contracts
files edit   update_index --> re-reads changed, added, deleted files only
new project  create_index {"indexName":"legal-2026"} --> a separate index

How does refreshing work?

update_index compares the index with the files on disk and re-reads only what changed. Here is what the server returned in our test, after one contract had a penalty clause added between two calls:

-> get_index_info {"indexName":"contracts"}
<- { "documentCount": 5, "indexedPaths": [ "contracts" ],
     "documentsWithErrors": [], "status": "Ready" }

-> update_index {"indexName":"contracts"}
<- Index 'contracts' updated: 0 added, 1 updated, 0 removed;
   5 document(s) in the index.

-> search {"query":"penalty","indexName":"contracts"}
<- documentsFound 3, including the edited initech-nda.docx

The counts tell you what happened: one file re-read, nothing else touched. Deleted files drop out on the same call.

Why one index per project?

Because separate corpora deserve separate answers. A question about this year’s contracts should not surface last year’s drafts, and a client’s documents should not mix with another client’s. Index names are cheap:

-> create_index {"indexName":"legal-2026"}
<- Index 'legal-2026' created. Add documents with add_to_index
   (indexName: 'legal-2026').

Each index is a folder under /data/.groupdocs-search-index, and get_index_info without a name lists them all. You rarely need create_index explicitly, because add_to_index creates an index on first use, but naming them deliberately is what turns “an index” into “this project’s memory”.

The one rule about removal

The engine removes paths that were added, not individual files inside them. The server says so plainly when you try:

-> remove_from_index {"documentPath":"contracts/hooli-supply-terms.txt",...}
<- Removal failed for 'contracts/hooli-supply-terms.txt':
   'contracts/hooli-supply-terms.txt' is inside the indexed folder
   'contracts'. GroupDocs.Search removes whole indexed paths only: ...

So design for it: if you expect to drop part of a corpus later, such as a year, a client or the drafts, index those parts as separate paths (contracts/2025, contracts/2026) and each can be removed on its own. Deleting a file on disk and running update_index also removes it.

Keeping it current without asking

create_index (optional)
      |
      v
add_to_index ---> search ---> get_text_fragments
      ^              ^
      |              |  get_index_info: counts, paths, status
update_index  (files changed on disk)
      |
remove_from_index  (only a path that was given to add_to_index)

Three practical ways to make refreshing automatic:

  1. In the agent’s instructions. A line in CLAUDE.md or AGENTS.md, “call update_index for this project’s index before answering if files may have changed”, makes the agent do it at the start of a session.
  2. On a schedule. Any MCP-capable automation can call update_index nightly; when little has changed, the call is quick.
  3. After a bulk copy. One call picks up every added file.

Indexes also survive upgrades: indexes built by GroupDocs.Search 22.7 to 26.8 are converted on first use, with a backup kept next to them.

What the agent decides, and what the index does

The agent decides The index does
which index a question belongs to keeps each named index in its own folder
when files may have changed re-reads only changed, added and deleted files
which words to search, and variants to try matches words, phrases, ranges; reports the terms it found
how much context to quote returns passages with the requested number of words around them
what to tell you nothing: it returns counts, paths and text, never conclusions

The split is deliberate. Judgement stays with the model, and the facts it reasons from come from a tool whose output you can inspect.

Honest limits

  • In evaluation mode an index holds at most 100 documents and a search returns at most 10. Call get_license_status before relying on an index as the source of truth.
  • The index persists only if /data (or the index volume) is a mounted host folder; otherwise it disappears with the container.
  • The index contains the documents’ text: protect and dispose of it like the documents.
  • Docker only; on Linux add --user "$(id -u):$(id -g)" so the container can write the index.

FAQ

Does the agent remember my documents between sessions? With a persistent index, yes: the index stays on disk and the next session searches it without re-reading anything.

Do I need to rebuild the index when files change? No. update_index re-reads only changed, added and deleted files.

Can I keep the index separate from read-only documents? Yes. Mount the documents read-only, mount a writable folder at /index, and set GROUPDOCS_MCP_INDEX_PATH=/index.

Go deeper