officegrep
README.md
# officegrep
[](https://github.com/Asgoresmilelong/officegrep/actions/workflows/ci.yml)
[](LICENSE)
[](pyproject.toml)
[](https://modelcontextprotocol.io)
**Full-text search inside Word, PowerPoint, Excel and PDF — for agents.**
`grep` cannot see a single character inside a `.docx`. `officegrep` extracts the text, indexes it into one SQLite file, and hands it to any agent over MCP.
```
$ officegrep search "bending moment"
Found 3 hits:
F:\reports\pole-design.docx [table p 89]
design bending moment (load point 0.25 m from tip); deflection limit; test moment = 2× …
F:\notes\composites.md [line 32]
… utilization 81%. **test bending moment = 2× the standard test moment** …
```
中文说明:[README.zh-CN.md](README.zh-CN.md)
## Why
- `grep` / `ripgrep` only read plain text. `.docx` is a zip of XML, `.xlsx` keeps strings in a shared table, `.pdf` is a compressed stream.
- Generic RAG needs an embedding service, a vector store, and a network round-trip.
- This needs one SQLite file: offline, incremental, milliseconds.
## Install
```bash
# one command, no clone, no uv
pip install https://github.com/Asgoresmilelong/officegrep/releases/download/v0.1.1/officegrep-0.1.1-py3-none-any.whl
# or from source
pip install git+https://github.com/Asgoresmilelong/officegrep
```
Runtime deps: `lxml`, `openpyxl`; PDF support adds optional `pypdf`.
Listed in the official [MCP Registry](https://registry.modelcontextprotocol.io) as `io.github.Asgoresmilelong/officegrep`; there is also an `.mcpb` bundle on the [releases page](https://github.com/Asgoresmilelong/officegrep/releases) for MCP hosts that install bundles (needs `uv`).
## CLI
```bash
officegrep index ~/Documents ~/Downloads # build / update (incremental)
officegrep search "island reef" --limit 5
officegrep search "wind load" --under ~/Documents
officegrep stats
```
The index lives in `~/.officegrep/index.db`; override with `--db` or `OFFICEGREP_DB`.
## First run
Nothing to do. If the index is empty when `officegrep mcp` starts, it scans `~/Documents`, `~/Downloads` and `~/Desktop` in the background (25 MB per-file cap) while the agent keeps talking; a `search_docs` call made in the meantime answers with a "still building" note instead of a misleading "no results".
- opt out: `OFFICEGREP_AUTOINDEX=0`
- scan other folders: `OFFICEGREP_ROOTS="~/work;~/papers"`
## Stay in sync
```bash
officegrep watch ~/Documents # re-index on change: 2s poll, no extra dependency
officegrep watch ~/Documents --once # single sync pass (cron / CI friendly)
```
Or let the MCP server watch in the background:
```bash
OFFICEGREP_WATCH="~/Documents;~/Downloads" officegrep mcp
```
The index runs in WAL mode, so a `watch` process and an MCP server can share one database file concurrently — something that fails with `database is locked` on a default rollback journal.
## MCP server
```bash
officegrep mcp
```
Client config (Claude Desktop / Cursor / Codex / any MCP host):
```json
{
"mcpServers": {
"officegrep": {
"command": "officegrep",
"args": ["mcp", "--db", "/Users/me/.officegrep/index.db"]
}
}
}
```
| Tool | What it does |
|---|---|
| `search_docs` | Full-text search → file path, locator (`p 42`, `slide 3`, `Sheet1!12`, `page 7`), highlighted snippet |
| `list_docs` | Indexed files with block counts |
| `index_folder` | Build / refresh the index (incremental) |
The protocol is a hand-written JSON-RPC over stdio — no MCP SDK dependency.
## How it works
```
docx / pptx → zipfile + lxml, read the XML directly
xlsx → openpyxl (read_only)
pdf → pypdf (optional)
txt / md → line chunks, line numbers kept
```
- Every block carries a **human-readable locator**, because the first question an agent asks is "where?".
- The index uses SQLite **FTS5 with the `trigram` tokenizer**: substring matching for both CJK and Latin text, no word segmenter required, ranked by `bm25()`.
- Queries of 1–2 characters cannot match trigrams, so they fall back to a scan ranked by hit count (CJK queries are frequently two characters).
- Incremental: compare `(size, mtime)` first, hash with SHA-1 only when they differ.
Benchmark on a real engineering corpus:
| Metric | Value |
|---|---|
| Files | 43 (docx / pptx / xlsx / md, incl. an 8.6 MB deck) |
| Text blocks | 2,260 |
| First index | 2.16 s |
| Database | 1.9 MiB |
## Limits
- No OCR: scanned PDFs yield nothing.
- Literal search, not semantic — "tower" will not find "pole" unless both appear.
- 1–2 character queries scan the table; slow past a few hundred thousand blocks.
- Indexes body text only: no comments, tracked changes, headers or footers.
## License
MIT
This server cannot be deployed
Maintenance
ActivityNo data
ResponsivenessSyncing