83 lines
2.3 KiB
Markdown
83 lines
2.3 KiB
Markdown
# corpus-mcp
|
|
|
|
`corpus-mcp` builds a portable SQLite full-text index from Markdown and text
|
|
files, then exposes ranked document excerpts through a local MCP server.
|
|
|
|
## Installation
|
|
|
|
Install the command in an isolated environment with either tool:
|
|
|
|
```bash
|
|
pipx install .
|
|
```
|
|
|
|
```bash
|
|
uv tool install .
|
|
```
|
|
|
|
For development:
|
|
|
|
```bash
|
|
uv sync
|
|
uv run pytest
|
|
```
|
|
|
|
The Python runtime's SQLite library must include FTS5. The command reports a
|
|
clear error at indexing time when FTS5 is unavailable.
|
|
|
|
## Build A Corpus
|
|
|
|
Index all `.txt` and `.md` files below a directory, at any depth:
|
|
|
|
```bash
|
|
corpus-mcp index ./documents \
|
|
--database ./corpus.sqlite \
|
|
--description "Internal product documentation"
|
|
```
|
|
|
|
For a longer description, use `--description-file description.txt`. Source
|
|
files are read as UTF-8 (with or without a BOM) by default. Use `--encoding`
|
|
when a corpus uses a different encoding.
|
|
|
|
Indexing is an atomic full rebuild. If reading or indexing fails, an existing
|
|
database remains unchanged. Directory and file symlinks are not followed.
|
|
|
|
## Run The MCP Server
|
|
|
|
```bash
|
|
corpus-mcp serve /absolute/path/to/corpus.sqlite
|
|
```
|
|
|
|
The server uses stdio, so configure it as a subprocess in the MCP client. For
|
|
example:
|
|
|
|
```json
|
|
{
|
|
"mcpServers": {
|
|
"corpus": {
|
|
"command": "corpus-mcp",
|
|
"args": ["serve", "/absolute/path/to/corpus.sqlite"]
|
|
}
|
|
}
|
|
}
|
|
```
|
|
|
|
Restart a running MCP server after rebuilding its database.
|
|
|
|
## MCP Tools
|
|
|
|
`search_corpus(query, limit=10, excerpts_per_document=2, syntax="plain")`
|
|
returns ranked, highlighted excerpts grouped by document. Plain searches match
|
|
all whitespace-separated terms without interpreting operators. Set `syntax` to
|
|
`fts5` for phrases, `OR`, `NOT`, and prefix expressions. Each result includes
|
|
the containing chunk's character offsets, which can be passed to
|
|
`read_document_excerpt` to retrieve more surrounding context. Search ranks a
|
|
bounded pool of chunk matches so broad queries remain responsive; as a result,
|
|
a document with many highly ranked passages may occupy multiple candidates.
|
|
|
|
`read_document_excerpt(path, offset=0, max_chars=4000)` reads a bounded range
|
|
and returns previous and next offsets. Responses are capped at 20,000
|
|
characters so a large document cannot accidentally fill the model context.
|
|
|
|
`corpus_info()` returns the persisted dataset description and build metadata.
|