search-excel-mcp
Local MCP server that lets any MCP client (Claude Code, Cursor, Claude Desktop, Cline, …) query complex Excel files (heavy merged cells, large size, multi-language text including CJK) via SQL and substring search — no API keys, no embeddings, no GPU.
Built with FastMCP + DuckDB + openpyxl + pyarrow.
Why this exists
Documentation-style Excel files (external design docs, report specs, requirements sheets) typically have thousands of merged cells per sheet, 20–100 MB per file, and multi-language text where most FTS tokenizers fail.
Standard RAG (embeddings + vector store) needs an LLM or embedding model that you can't always run locally. Your MCP client is the reasoning layer; this server just gives it accurate structured access to cells via DuckDB.
Install
pip install search-excel-mcp
# or run without install:
uvx search-excel-mcp
Configure your MCP client
Add to the client's MCP config file. Common locations:
| Client | Config path |
|---|---|
| Claude Code | ~/.claude/mcp.json (global) or <project>/.mcp.json (project-local) |
| Cursor | ~/.cursor/mcp.json (global) or <project>/.cursor/mcp.json (project-local) |
| Claude Desktop (macOS) | ~/Library/Application Support/Claude/claude_desktop_config.json |
| Cline / other | see your client's docs |
Config entry (same JSON shape for all):
{
"mcpServers": {
"search-excel": {
"command": "uvx",
"args": ["search-excel-mcp"],
"env": {
"SEARCH_EXCEL_DATA_DIR": "/absolute/path/to/your/excel/folder"
}
}
}
}
Only SEARCH_EXCEL_DATA_DIR is required. The DuckDB cache is placed under your OS-standard app data folder (e.g. ~/Library/Application Support/search-excel-mcp/data.duckdb on macOS) — override with SEARCH_EXCEL_DB if you want it elsewhere.
Restart your MCP client → the search-excel server appears.
Use
Drop .xlsx files into your data folder, then ask your agent:
"ingest all the files in the data folder" "find rows that mention '保存ボタン' in any file" "list all sheets in report-2024.xlsx" "show me sheet 5"
The agent routes to the right MCP tool. DuckDB is built incrementally — already-ingested files are skipped unless you re-ingest with reset=true.
CLI (optional)
The same package installs CLI tools for batch use:
# Ingest everything under $SEARCH_EXCEL_DATA_DIR
search-excel-ingest
# Ingest a single file or folder
search-excel-ingest --input /path/to/file.xlsx
search-excel-ingest --input /path/to/folder
# Filter / reset
search-excel-ingest --only "report"
search-excel-ingest --reset
# Validate ingest accuracy (samples random cells against the source xlsx)
search-excel-validate --samples 20
Environment variables
| Variable | Default | Purpose |
|---|---|---|
SEARCH_EXCEL_DATA_DIR |
./data (cwd-relative) |
Where your .xlsx files live — set this for MCP usage |
SEARCH_EXCEL_DB |
OS user data dir | DuckDB cache file |
SEARCH_EXCEL_REPORTS_DIR |
OS user data dir / reports | Ingest/validation log output |
SEARCH_EXCEL_WORKERS |
min(4, cpu_count) |
Parallel ingest worker count |
<OS user data dir> resolves per platform via platformdirs:
- macOS:
~/Library/Application Support/search-excel-mcp/ - Linux:
~/.local/share/search-excel-mcp/(or$XDG_DATA_HOME) - Windows:
%LOCALAPPDATA%\search-excel-mcp\
MCP tools
| Tool | Purpose |
|---|---|
ingest_file(path, reset?) |
Ingest a single .xlsx file |
ingest_folder(path?, reset?) |
Ingest every .xlsx under a folder (recursive) |
list_files() |
All ingested files |
list_sheets(file?) |
Sheets, optionally filtered |
search_text(keyword, file?, sheet?, limit?) |
Substring search across cells (CJK-friendly) |
search_sheets(keyword, limit?) |
Which sheets discuss a topic, ranked by hit count |
get_sheet_cells(sheet_id, row/col range, ...) |
Read a slice of a sheet |
get_sheet_text(sheet_id, max_chars?) |
Deduplicated text overview of a sheet |
query_sql(sql, limit?) |
Read-only SELECT against DuckDB |
delete_file(file_id) |
Remove one file's data |
clear_db(confirm) |
Wipe all data (preview unless confirm=true) |
db_stats() |
Counts and overall stats |
Accuracy notes
- No LLM in the pipeline → deterministic.
- Cell formatting (font color, bold, fill) is not extracted — only text values. Files that mark changes with red font lose that signal here.
- Read-only MCP for queries; ingest tools mutate DuckDB only.
search-excel-validatesamples cells from the source xlsx and checks them against the DB.search_textuses ILIKE (substring) instead of DuckDB FTS so CJK works reliably.
License
MIT
Metadata
Release files for search-excel-mcp 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | |
|---|---|---|---|---|
| search_excel_mcp-0.1.0.tar.gz | 14.7 kB | Without provenance | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| search_excel_mcp-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 33.8 kB
Release files / search_excel_mcp-0.1.0.tar.gz
| Download URL | search_excel_mcp-0.1.0.tar.gz |
|---|---|
| Size | 14.7 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
2a9f35d4b0c3a45086dd9ee8866399cb128d35892b27523e2dd2398e912f6e2d
|
|
BLAKE2b-256 checksum How to use checksums |
58f2931463a9617b09b3d0df56d386659d0fd7b9086e1cf24da0cd42a36dfaf9
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.5
|
Release files / search_excel_mcp-0.1.0-py3-none-any.whl
| Download URL | search_excel_mcp-0.1.0-py3-none-any.whl |
|---|---|
| Size | 19.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
156a74f29e9f416859e395315a155a1079d98e198b6a5cdad567c503d14bfa24
|
|
BLAKE2b-256 checksum How to use checksums |
2425d8680f331d7938e37c53c6c5202668885878daa8a8993c2e2825ce4d43db
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.5
|
Security for search-excel-mcp 0.1.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.