Skip to main content
Glama
GroupDocs.Search MCP Server

GroupDocs.Search MCP Server

Official
README.md
# GroupDocs.Search MCP Server

MCP server that exposes [GroupDocs.Search](https://products.groupdocs.com/search) as AI-callable tools
for Claude, Cursor, GitHub Copilot, and other MCP agents. It indexes folders of PDF, Office, email,
archive and 70+ other document formats **locally**, then answers full-text, boolean, phrase, fuzzy and
date-range queries over them — documents never leave your machine.

[![GHCR](https://img.shields.io/badge/GHCR-search--net--mcp-2496ED?logo=docker&logoColor=white)](https://github.com/orgs/groupdocs-search/packages/container/package/search-net-mcp)
[![MCP Registry](https://img.shields.io/badge/MCP_Registry-listed_(OCI)-6f42c1)](https://registry.modelcontextprotocol.io/v0/servers?search=io.github.groupdocs-search/groupdocs-search-mcp)
[![Integration tests](https://github.com/groupdocs-search/GroupDocs.Search.Mcp.Tests/actions/workflows/integration.yml/badge.svg)](https://github.com/groupdocs-search/GroupDocs.Search.Mcp.Tests/actions/workflows/integration.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)

<!-- TODO(manual): record 30s demo per improvement-plan M1 -->
<!-- ![Demo](assets/demo.gif) -->

## Installation

<!-- install-buttons:start - generated by install/generate-install-links.ps1; do not edit by hand -->
[![Install in VS Code](https://img.shields.io/badge/VS_Code-Install-0098FF)](https://vscode.dev/redirect/mcp/install?name=groupdocs-search&config=%7B%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22--rm%22%2C%22-i%22%2C%22-v%22%2C%22%2Fpath%2Fto%2Fdocuments%3A%2Fdata%22%2C%22-e%22%2C%22GROUPDOCS_MCP_STORAGE_PATH%3D%2Fdata%22%2C%22-e%22%2C%22GROUPDOCS_MCP_OUTPUT_PATH%3D%2Fdata%22%2C%22-e%22%2C%22GROUPDOCS_LICENSE_PATH%3D%22%2C%22ghcr.io%2Fgroupdocs-search%2Fsearch-net-mcp%3Alatest%22%5D%7D) [![Install in VS Code Insiders](https://img.shields.io/badge/VS_Code_Insiders-Install-24bfa5)](https://insiders.vscode.dev/redirect/mcp/install?name=groupdocs-search&config=%7B%22command%22%3A%22docker%22%2C%22args%22%3A%5B%22run%22%2C%22--rm%22%2C%22-i%22%2C%22-v%22%2C%22%2Fpath%2Fto%2Fdocuments%3A%2Fdata%22%2C%22-e%22%2C%22GROUPDOCS_MCP_STORAGE_PATH%3D%2Fdata%22%2C%22-e%22%2C%22GROUPDOCS_MCP_OUTPUT_PATH%3D%2Fdata%22%2C%22-e%22%2C%22GROUPDOCS_LICENSE_PATH%3D%22%2C%22ghcr.io%2Fgroupdocs-search%2Fsearch-net-mcp%3Alatest%22%5D%7D&quality=insiders) [![Add to Cursor](https://img.shields.io/badge/Cursor-Add_MCP-111111)](https://cursor.com/en/install-mcp?name=groupdocs-search&config=eyJjb21tYW5kIjoiZG9ja2VyIiwiYXJncyI6WyJydW4iLCItLXJtIiwiLWkiLCItdiIsIi9wYXRoL3RvL2RvY3VtZW50czovZGF0YSIsIi1lIiwiR1JPVVBET0NTX01DUF9TVE9SQUdFX1BBVEg9L2RhdGEiLCItZSIsIkdST1VQRE9DU19NQ1BfT1VUUFVUX1BBVEg9L2RhdGEiLCItZSIsIkdST1VQRE9DU19MSUNFTlNFX1BBVEg9IiwiZ2hjci5pby9ncm91cGRvY3Mtc2VhcmNoL3NlYXJjaC1uZXQtbWNwOmxhdGVzdCJdfQ%3D%3D) [![Codex CLI setup](https://img.shields.io/badge/Codex_CLI-Setup-e5541b)](install/generated/codex.md) [![Windsurf setup](https://img.shields.io/badge/Windsurf-Setup-0e8a7d)](install/generated/windsurf.md)

> One-click installs pre-fill every supported setting: edit the placeholder host path in
> the volume mount after install; an empty GROUPDOCS_LICENSE_PATH runs in evaluation mode.
>
> **More clients** - ready-made configs for Claude Code, Codex CLI, Visual Studio 2022,
> Cursor, Windsurf, Cline, and JetBrains Rider live in [`install/generated/`](install/generated/).
<!-- install-buttons:end -->

**This product ships via Docker (GHCR) only.** The GroupDocs.Search engine DLL is about 200 MiB and
ships ONNX Runtime natives, so the packed tool (~281 MiB) exceeds NuGet.org's 250 MB limit — `dnx` and
`dotnet tool install` are **not available** for it. When a slimmer engine packs under the limit, the
standard NuGet flow returns (see the revert notes in `.github/workflows/publish_prod.yml`).

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

Images are multi-arch (`linux/amd64` + `linux/arm64`), tagged `latest` plus an immutable version tag
per release (e.g. `:26.10.1`). To pin, replace `:latest` with the version tag — recommended for shared
configs and CI.

### Linux: run the container as your user

The image runs as a non-root user (uid 1654). On Linux a mounted folder keeps its host owner, so a folder
you own is **read-only** inside the container and indexing fails with *"The index folder … is not
writable"*. Add `--user` so the container writes as you:

```bash
docker run --rm -i --user "$(id -u):$(id -g)" \
  -v $(pwd)/documents:/data \
  ghcr.io/groupdocs-search/search-net-mcp:latest
```

MCP client configs (JSON) do not run a shell, so put the numbers in directly — `id -u` and `id -g`
print them, typically `1000`: `"args": ["run", "--rm", "-i", "--user", "1000:1000", "-v", …]`. Docker
Desktop on Windows and macOS does not need this.

### Where the index lives

Search is the one **stateful** server in the GroupDocs MCP family: an index is a persistent, searchable
copy of your documents' text that survives restarts. By default it is kept in a
`.groupdocs-search-index` folder **inside the documents folder** (`/data/.groupdocs-search-index` in the
container), so the one volume mount above is all you need and the index is never indexed itself.

If the documents folder is read-only, keep the index in its own folder:

```bash
docker run --rm -i \
  -v /path/to/documents:/data:ro \
  -v /path/to/index:/index -e GROUPDOCS_MCP_INDEX_PATH=/index \
  ghcr.io/groupdocs-search/search-net-mcp:latest
```

## Available MCP Tools

| Tool | Description |
|---|---|
| `add_to_index` | Indexes a file, a folder (recursively), or the whole storage folder. Creates the index on demand. |
| `search` | Finds the documents that match a query, ranked by relevance, with occurrence counts — returned as JSON |
| `get_text_fragments` | Returns the matching passages with surrounding words, so the agent can quote or answer from them |
| `update_index` | Re-reads changed files, adds new files in indexed folders, drops deleted ones |
| `remove_from_index` | Removes an indexed path (a folder or file passed to `add_to_index`) from the index; files on disk are untouched |
| `create_index` | Creates or opens a named index (`contracts`, `hr/2026`), or recreates it empty |
| `get_index_info` | Reports whether an index exists, its document count, indexed paths, version, and the other indexes — as JSON |
| `get_license_status` | Reports the active licensing mode (evaluation / licensed / metered), the engine version, and — under metered — the consumed quantity and credit. Processes no document. |

Paths are always **relative to the documents folder** (`contracts`, `reports/2026/q3.pdf`), and indexes
are referred to by **name**, never by filesystem path. Several named indexes can live side by side.

**Query syntax** (GroupDocs.Search DSL): single words (`invoice`); phrases **in double quotes**
(`"force majeure"` — unquoted multi-word input does not match); `AND`, `OR`, `NOT` and parentheses;
`?` character wildcards (`?ffect`, `princip?(2~4)`); `daterange(2026-01-01 ~~ 2026-06-30)`; number
ranges (`100 ~~ 500`); field prefixes (`filename: lease`); regular expressions starting with `^`; and
fuzzy matching via the `fuzzy` argument.

Indexable formats include PDF, DOC/DOCX, XLS/XLSX, PPT/PPTX, ODT/ODS/ODP, RTF, TXT, HTML, EPUB, FB2,
EML/EMLX/MSG, PST/OST, ONE and ZIP — including documents inside archives and email attachments.
`get_index_info` with `includeSupportedFormats: true` lists the engine's full set.

## Example prompts for AI agents

Copy any of these into Claude Desktop, Cursor, or GitHub Copilot Chat after the server is connected.

1. **Make a folder searchable**: *"Index everything in my contracts folder."*
2. **Find the right documents**: *"Which contracts mention a termination penalty?"*
3. **Read the evidence, not the file list**: *"Show me the paragraphs that talk about \"force majeure\", with the file each one comes from."*
4. **Keep it current**: *"I edited some files in reports — refresh the index and search for the Q3 forecast again."*
5. **Separate collections**: *"Create an index called hr for the HR folder, then search it for parental leave."*

## Licensing

**The MCP server itself is MIT; the underlying GroupDocs.Search engine requires a license for
production use.** Without one the server runs in **evaluation mode**, and the limits are counts, not
watermarks — results look complete and are not:

- **An index holds at most 100 documents** (across all indexes of a repository); indexing stops there.
- **A search returns at most 10 documents.**
- Every tool response carries an `evaluation` note while this applies.
- Full list: [evaluation limitations](https://docs.groupdocs.com/search/net/evaluation-limitations-and-licensing/).

There are two ways to license the server.

**License file** — mount your `GroupDocs.Search.lic` (or `GroupDocs.Total.lic`) into the container and
point `GROUPDOCS_LICENSE_PATH` at it. Works offline.

**Metered (pay-per-use)** — set both `GROUPDOCS_METERED_PUBLIC_KEY` and
`GROUPDOCS_METERED_PRIVATE_KEY`. You are billed for what you actually process, which suits AI agents
well because their usage is bursty and hard to predict up front. If both a metered key pair and a
license file are configured, **metered wins** and the file is ignored.

> **Metered mode needs outbound connectivity.** Usage is reported to GroupDocs servers, so air-gapped
> or firewalled deployments must allow that egress — or use a license file instead.

Call the **`get_license_status`** tool at any time to see which mode is active, and — under metered —
the consumed quantity and remaining credit. It processes no document and changes nothing.

### Keeping the private key out of your config

The metered private key is a secret. MCP client configs are plain files on disk, and a project-scoped
`.mcp.json` is committed by convention, so prefer, in order:

1. **Set the variables in your OS environment and leave them out of the config entirely.** An stdio MCP
   server inherits its client's environment, so this works in every client. On macOS note that an app
   launched from Finder does not inherit shell exports — use `launchctl setenv`, or launch the client
   from a terminal.
2. **Reference them indirectly** if your client supports it (Claude Code expands `${VAR}`; VS Code uses
   `${env:VAR}` and `${input:...}`).
3. **A literal value in a user-scoped config** (for example `~/.claude.json`) is acceptable for a single
   developer.
4. **Never** commit a literal key in a project-scoped `.mcp.json`.

For Docker, forward the values without writing them into any file — the names alone, so the keys never
appear in the command line:

```bash
docker run --rm -i \
  -e GROUPDOCS_METERED_PUBLIC_KEY -e GROUPDOCS_METERED_PRIVATE_KEY \
  -v /path/to/documents:/data \
  ghcr.io/groupdocs-search/search-net-mcp:latest
```

- [Get a free 30-day temporary license](https://purchase.groupdocs.com/temporary-license/)
- [Purchase a license](https://purchase.groupdocs.com/pricing/search/net) | [Product page](https://products.groupdocs.com/search/net/)

## Configuration

| Variable | Description | Default |
|---|---|---|
| `GROUPDOCS_MCP_STORAGE_PATH` | Folder with the documents to index; tool paths are relative to it | `./Files` (`/data` in the image) |
| `GROUPDOCS_MCP_OUTPUT_PATH` | *(Optional)* writable folder; indexes go under it when `GROUPDOCS_MCP_INDEX_PATH` is not set | `GROUPDOCS_MCP_STORAGE_PATH` |
| `GROUPDOCS_MCP_INDEX_PATH` | *(Optional)* folder that holds the indexes, one sub-folder per index name | `<output or storage>/.groupdocs-search-index` |
| `GROUPDOCS_LICENSE_PATH` | Path to a GroupDocs license file, as seen inside the container. Ignored when metered keys are set | (evaluation mode) |
| `GROUPDOCS_METERED_PUBLIC_KEY` | Metered (pay-per-use) public key. Needs the private key too; takes precedence over `GROUPDOCS_LICENSE_PATH` | (unset) |
| `GROUPDOCS_METERED_PRIVATE_KEY` | Metered private key. **Secret** — pass it from the environment, never from a committed config | (unset) |

Indexes written by GroupDocs.Search 22.7–26.8 are converted to the 26.10 format the first time they are
opened; the original is kept next to it as `<name>.pre-26.10-backup`.

## Usage with Claude Desktop

```json
{
  "mcpServers": {
    "groupdocs-search": {
      "command": "docker",
      "args": ["run", "--rm", "-i", "-v", "/path/to/documents:/data", "ghcr.io/groupdocs-search/search-net-mcp:latest"]
    }
  }
}
```

> To use a license, add `"-v", "/path/to/license-folder:/license", "-e",
> "GROUPDOCS_LICENSE_PATH=/license/GroupDocs.Total.lic"` before the image name.
> To pin a version, replace `:latest` with the release tag.

## Usage with VS Code / GitHub Copilot

Use the **Install in VS Code** button above, or add to `.vscode/mcp.json`
(also in [`install/generated/vscode-mcp.json`](install/generated/vscode-mcp.json)):

```json
{
  "inputs": [
    {
      "type": "promptString",
      "id": "storage_path",
      "description": "Folder with the documents to index.",
      "password": false
    }
  ],
  "servers": {
    "groupdocs-search": {
      "command": "docker",
      "args": ["run", "--rm", "-i", "-v", "${input:storage_path}:/data", "ghcr.io/groupdocs-search/search-net-mcp:latest"]
    }
  }
}
```

## Usage with Docker Compose

```bash
cd docker
docker compose up
```

Edit `docker/docker-compose.yml` to point volumes at your local documents folder.

## Documentation & guides

Step-by-step deployment guides and a published-image integration test suite live in the companion
repo [**GroupDocs.Search.Mcp.Tests**](https://github.com/groupdocs-search/GroupDocs.Search.Mcp.Tests):

- [Run via Docker](https://github.com/groupdocs-search/GroupDocs.Search.Mcp.Tests/blob/master/how-to/02-run-via-docker.md)
- [Verify on the MCP registry](https://github.com/groupdocs-search/GroupDocs.Search.Mcp.Tests/blob/master/how-to/03-verify-mcp-registry.md)
- [Use with Claude Desktop](https://github.com/groupdocs-search/GroupDocs.Search.Mcp.Tests/blob/master/how-to/04-use-with-claude-desktop.md)
- [Use with VS Code / GitHub Copilot](https://github.com/groupdocs-search/GroupDocs.Search.Mcp.Tests/blob/master/how-to/05-use-with-vscode-copilot.md)
- [Run the integration tests](https://github.com/groupdocs-search/GroupDocs.Search.Mcp.Tests/blob/master/how-to/06-run-integration-tests.md)

## License

MIT — see [LICENSE](LICENSE)

<!-- mcp-name: io.github.groupdocs-search/groupdocs-search-mcp -->