sery-mcp
The local-files MCP server. Pure Rust. Free your Claude Desktop / Cursor / Zed / Continue from the upload-to-cloud dance.
Status: v0.2.0 — five tools shipped (
list_folder,search_files,get_schema,sample_rows,read_document).query_sqllands in v0.3.0.
sery-mcp is a Model Context Protocol
server that exposes the data-heavy files on your machine — CSVs,
Parquet, Excel, DOCX, PDF, HTML — to any MCP-aware LLM client. Files
stay where they live; only what your AI explicitly asks about ever
crosses the stdio pipe.
Why this exists
Every MCP server in the official registry today is TypeScript or
Python. Both are fine for a single-user demo, neither is what you
want sitting in your mcp.json quietly indexing 50 GB of CSVs and
documents while you work.
sery-mcp is the canonical pure-Rust local-files MCP server,
extracted from Sery Link's production scanner. It
composes three open-source crates we already publish:
scankit— walk + watch + filter directory treestabkit— tabular files → schema + sample rows + row countmdkit— documents → markdown (PDF, DOCX, PPTX, HTML, IPYNB)
Plus ~500 lines of MCP glue on top of rmcp, the official Anthropic
Rust SDK.
Quick start
Then point your MCP client at it. Example for Claude Desktop's mcp.json:
{
"mcpServers": {
"sery": {
"command": "sery-mcp",
"args": ["--root", "/Users/me/Documents"]
}
}
}
Restart your MCP client and the tools below show up in its tool palette.
Tool surface
Shipped in v0.2.0
| Tool | What it does | Backed by |
|---|---|---|
list_folder |
Enumerate files under --root (or a sub-path) with size + mtime + extension |
scankit |
search_files |
Case-insensitive filename search with ranking (exact 1.0 → path-substring 0.2). Optional extension filter. | scankit + scoring |
get_schema |
Column names + inferred types + row count for any tabular file (CSV / TSV / Parquet / XLSX / XLS / XLSB / XLSM / ODS) | tabkit |
sample_rows |
First N rows of a tabular file as header-keyed JSON objects (default 5, capped at 100) | tabkit |
read_document |
DOCX / PDF / PPTX / HTML / IPYNB / EPUB / RTF / ODT → markdown. 50 MB cap. | mdkit (libpdfium / pandoc / html2md) |
Coming in v0.3.0
| Tool | What it does | Backed by |
|---|---|---|
query_sql |
Read-only SQL queries against a single tabular file | Pure-Rust SQL engine (DataFusion) |
Tools are read-only by design. There is no write_file, no
execute_command, no delete. The privacy story is that a bug in
the LLM (or in your prompt) cannot lose your data.
What sery-mcp deliberately doesn't do
- No cloud. Stdio transport only in v0.1. The cloud-routed variant
(
mcp.sery.ai) is a separate product that wraps the existing Sery Link tunnel; this binary is local-only. - No watching. Tools are pull-based — the LLM asks, we answer. If
you need continuous indexing, run Sery Link and
let
sery-mcpquery its scan cache instead of re-walking each call. - No write tools. Read-only. Forever.
- No auth. Single-user, single-machine, stdio-spawned. If your MCP client is malicious you have bigger problems.
Architecture
┌──────────────────────────────────────────────────┐
│ LLM client (Claude Desktop / Cursor / Zed / …) │
└────────────────────┬─────────────────────────────┘
│ stdio (MCP / JSON-RPC 2.0)
▼
┌──────────────────────────────────────────────────┐
│ sery-mcp (this binary) │
│ │
│ ┌─────────────────────────────────────────┐ │
│ │ rmcp (protocol + dispatch) │ │
│ └────────────────────┬────────────────────┘ │
│ │ tool calls │
│ ▼ │
│ ┌─────────────────────────────────────────┐ │
│ │ Tools (v0.2.0) │ │
│ │ ├─ list_folder → scankit │ │
│ │ ├─ search_files → scankit │ │
│ │ ├─ get_schema → tabkit │ │
│ │ ├─ sample_rows → tabkit │ │
│ │ └─ read_document → mdkit │ │
│ │ │ │
│ │ v0.3.0: │ │
│ │ query_sql → DataFusion │ │
│ └─────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘
│ filesystem reads
▼
Your local files
Privacy
sery-mcp is pure stdio. It opens no sockets. It makes no outbound
network calls. The only things that cross the stdio pipe are:
- The MCP handshake (capabilities, server info)
- Tool calls coming in (e.g.
{ "tool": "get_schema", "args": { "path": "..." } }) - Tool results going out (e.g.
[{"name":"customer_id","type":"INTEGER"}, ...])
Whatever your LLM client does with the results — that's between you and your LLM client. We don't see prompts or completions.
The source of truth is the code: read src/ for what the tools do,
read Cargo.toml for what we depend on. No FFI, no Python, no
network — by design.
Family
| Crate | Role |
|---|---|
sery-mcp |
This — local-files MCP server |
scankit |
Walk + watch + filter directory trees |
tabkit |
Tabular files → schema + samples + count |
mdkit |
Documents → markdown |
sery-link |
Full desktop app — GUI, file watcher, multi-machine network |
License
Dual-licensed under MIT OR Apache 2.0
at your option. SPDX: MIT OR Apache-2.0. Same convention as the
rest of the Sery kit family.
Contributing
Bug reports, format-coverage PRs, MCP spec-compliance fixes, and downstream-production stories all welcome. Drop a star if you find this useful — it helps other developers find it.
Issues + PRs: https://github.com/seryai/sery-mcp/issues