Pure-Rust PDF Engine with WASM and MCP
On 6 October 2026 an author-run benchmark timed 22 PaperPilot tools inside a WebAssembly worker in headless Chromium and recorded an average of 65.5 ms. In that run the file stayed on the machine. The README leads with the same promise: “PDF tools for your AI agent, and for you. Pure Rust. Runs locally. Files never leave your machine.” Krushna Vardhan Reddy publishes the workspace at KrushnaVardhanReddy/PaperPilot. The 65.5 ms figure is the author’s own measurement on small synthetic files, so read it as a dispatch-cost sample, not as a timing for a 40 MB scan.
The check the README suggests is almost crude, which is why it is useful. Open usepaperpilot.com, merge two contract PDFs in the tab, and watch the network panel for an upload of the file bytes. If nothing leaves, the worker inside the page did the merge. The agent path is the same engine with a different caller. Register paperpilot-mcp (Model Context Protocol server for AI agent integration), restart Claude Desktop or Cursor, and use the prompt the README suggests: “Merge these two PDFs and compress the result.” The binary reads paths on disk. No API key, no account, and no network hop. It also runs with your OS privileges, and the README shows no allowlist, so prove the workflow in the shell before you hand a client folder to the agent.
Key Takeaways:
- v0.6 is one Rust workspace behind a CLI, a stdio MCP binary, a WASM worker, a Tauri app, and a local REST gateway on port 7823.
- The author’s 6 October 2026 report measures 22 WASM tools at 65.5 ms average in headless Chromium, on a 50-file synthetic corpus whose largest named PDF is 20 pages and 4,737 bytes.
- That same report claims 132 of 132 invocations passed across CLI, MCP, and REST on 44 tools. Several of those tools sit on the README roadmap for v0.9 and v1.0, not in the v0.6 shipped list.
- A second repo, Manoj77112/paperpilot, is a TypeScript app created on 25 October 2026. Same name, different code. Check the owner before you clone.
What v0.6 Ships
v0.6 is the current release line, under Apache 2.0. A from-source build wants Rust 1.75 or newer, plus Node.js and pnpm for the desktop app. On 26 October 2026 the repository showed 211 stars, 4 forks, and 1,533 commits, with the last push at 03:36 UTC and Rust as the detected language.
The README groups the shipped command list into five buckets. Organize covers merge, split, rotate, delete pages, reorder pages, extract pages, booklet imposition, and an N-up grid. Optimize is compress. Extract covers plain text plus OCR, described as pure-Rust PaddleOCR running through the rten crate rather than a Python or C++ runtime. Security covers watermark, signature validation, signature removal, a PII scan, and deep sanitize. Office data covers Excel to JSON and Excel to CSV. That is the whole shipped list. The rest of the documentation promises considerably more.
The dependencies named in the README are Rust crates: lopdf for PDF object manipulation, pdf_oxide, and rten for OCR inference. The pitch against the usual PDF toolchain is explicit: “No Chromium, no C++ runtime, no cloud calls.” That last clause is a claim about the processing path. The embed snippet, covered below, still loads a script from a CDN.

The release build command from the README compiles three packages at once.
# Requires Rust 1.75+, Node.js, and pnpm for the desktop app
git clone https://github.com/KrushnaVardhanReddy/PaperPilot.git
cd PaperPilot
cargo build --release -p paperpilot-cli -p paperpilot-mcp -p paperpilot-gateway
# Merge two reports, then compress the result at quality 75
# Expected: q3_combined.pdf and q3_combined_small.pdf written at the --output paths
paperpilot merge --inputs q3_report.pdf q3_appendix.pdf --output q3_combined.pdf
paperpilot compress --input q3_combined.pdf --quality 75 --output q3_combined_small.pdf
# Rotate specific pages: page 1 and pages 3 through 5, 90 degrees
paperpilot rotate --input q3_combined_small.pdf --pages 1,3-5 --angle 90 --output q3_final.pdf
# Note: this example does not handle encrypted inputs or missing files;
# the CLI error paths are not documented in the README.
The page selector, 1,3-5, is the detail that matters for scripting. A batch job can rotate a cover page without touching the body, and a flag that takes ranges avoids a per-page loop in the shell. The same flag shape shows up in the MCP tool arguments, which is the point of sharing one parser.
One Rust Core, Five Surfaces
The architecture block in the README draws five entry points feeding one workspace: a Tauri desktop app, the CLI, a REST gateway built on Axum, an MCP server over stdio, and a WASM build for the browser and the edge. The workspace members named there are paperpilot-core, paperpilot-pdf, paperpilot-nlp, paperpilot-gateway, paperpilot-mcp, paperpilot-wasm, and paperpilot-storage. The repo root confirms each as a top-level directory, alongside apps, paperpilot-ai, and paperpilot-cli.
Sharing one core is a maintenance claim more than a performance claim. A bug fixed in page reordering lands in the CLI, the agent tool, and the browser tab at the same commit. The cost is that every surface inherits the core’s constraints. If lopdf cannot parse a given PDF revision, none of the five can, and there is no fallback through a different library on one surface only.
The local REST surface is the one most useful for existing automation. The README gives the invocation and one endpoint.
paperpilot serve --port 7823
# JSON body, not multipart: paths are local files the gateway can read
# Expected: HTTP response from the gateway; bundle.pdf written at the output path
curl -X POST http://localhost:7823/api/v1/pdf/merge \
-H "Content-Type: application/json" \
-d '{"inputs": ["contracts/msa.pdf", "contracts/sow.pdf"], "output": "contracts/bundle.pdf"}'
# Interactive docs are served at http://localhost:7823/docs
# Note: the gateway reads file paths on the host, so this is a local
# automation interface, not something to expose beyond localhost.
The body carries file paths rather than file bytes, so the gateway has to read the caller’s filesystem. That is fine on the same machine and a problem for anything else. Port 7823 is the only default given, with Swagger UI at /docs. The README also shows an embed snippet that loads embed.js from cdn.usepaperpilot.com with a data-tools attribute listing merge, compress, and ocr. That is the one surface that involves a remote host, even where processing is claimed to stay in the page.
The WASM Path: Bytes That Stay in the Tab
The browser surface is the paperpilot-wasm crate, compiled to WebAssembly and driven from a Web Worker so a multi-megabyte document can be parsed without blocking the tab’s main thread. The author’s report, generated 6 October 2026 and run on Linux 7.0.0-34-generic with a 13th Gen Intel Core i9-13900H and 15 GB of RAM, measures that path inside headless Chromium. It reports 22 tools in the worker, with an average of 65.5 ms, a median of 70.0 ms, a minimum of 5 ms, and a maximum of 101 ms. The fastest named operations are decrypt at 5 ms, an OCR text-layer pass at 8 ms, and watermark at 41 ms. The slowest are delete_pages at 101 ms, images_to_pdf at 98 ms, and compress at 92 ms.
Those figures need the fixture sizes next to them. The corpus is 50 files, of which 40 are PDFs totalling 129 pages, and the largest named fixture, large_doc.pdf, is 20 pages and 4,737 bytes. A 20-page PDF under 5 KB is a synthetic document, not a scanned contract. A 65.5 ms average on documents that small says worker dispatch and WASM call overhead dominate the measurement, and it says very little about a 40 MB scan. The report does not include a large-file run.

Across 1,000 continuous iterations, resident memory stabilized at 99.73 MB with no heap growth, cold start on first document ingestion measured about 3.10 ms, and warm starts about 1.82 ms. A worker that does not grow across a thousand runs is what makes an in-tab tool usable for a batch rather than one file. The same section quotes an NLP command resolver at 1.5 million queries per second. That is a classification throughput figure, not a document-processing one.
The MCP Path: The Same Engine, Called by an Agent
The agent surface is a standalone binary, paperpilot-mcp, downloaded from the project’s releases and registered as a stdio server. The README’s example targets claude_desktop_config.json, and the same shape works for any client that launches a local process and speaks the protocol over its standard streams.
{
"mcpServers": {
"paperpilot": {
"command": "/usr/local/bin/paperpilot-mcp"
}
}
}
# Restart the client after saving. The binary is launched per session
# and inherits the user's filesystem permissions, so tool calls can read
# any PDF the user can read. No auth, no sandbox config is shown.
A stdio server runs with the user’s privileges, so a tool that accepts a file path can read anything that user can read. The README does not document an allowlist or a working-directory restriction, which is the first thing to add before pointing an agent at a folder of client documents. The agent is a different caller of the same binary, not a safer one.
The report quantifies the MCP claim: 44 tools tested, 132 of 132 invocations succeeding across the CLI, the MCP server, and the REST gateway, and zero panics, on the same 50-file fixture set. Latency for the native and gateway path: document manipulation at 6.52 ms average across a 0.90 to 30.64 ms range, optimization and security at 4.22 ms, analysis and rendering and OCR at 3.84 ms, forms and formatting at 4.12 ms, and office and web conversions at 1,256 ms average with a range stretching to 2,754 ms.
A merge that returns in under 10 ms can sit inline in a tool-calling loop. A PDF-to-DOCX call averaging over a second, and sometimes close to three, needs to be a step the agent reports progress on, and it is the category where the WASM build is not claimed to participate at all. The report lists pdf_to_docx, pdf_to_xlsx, pdf_to_pptx, pdf_convert_html, pdf_convert_markdown, and pdf_convert_excel in that slow group.
Reading the Benchmark Against the Roadmap
The benchmark and the README disagree about scope. The report’s category tables name tools that the README’s roadmap places in future releases. Encrypt, decrypt, sign, redact, forms, and annotations are listed under v0.9 as “coming next.” Render, flatten, repair, compare, PDF/A, and Bates numbering are listed under v1.0. Yet the report, dated 6 October 2026 and labeled “v1.0 Official,” includes pdf_encrypt, pdf_decrypt, pdf_sign, pdf_redact, pdf_flatten, pdf_repair, pdf_compare, pdf_to_pdf_a, and pdf_bates among the 44 tools it says passed.
Both documents live in the same repo. The charitable reading is that the engine functions exist and were exercised by the test harness while the user-facing release, tagged v0.6, has not exposed them yet. The cautious reading is that a self-reported pass rate on tools the shipping README does not claim is not a pass rate you can plan against. The fixture set is synthetic and small, the harness is the project’s own scripts/test_tri_interface_e2e.py, and no independent measurement of the engine has been published.
| Surface | What the README says ships in v0.6 | Measured latency, author’s report |
|---|---|---|
| CLI, MCP, REST: manipulation | merge, split, rotate, delete, reorder, extract pages | 6.52 ms average, 0.90 to 30.64 ms |
| CLI, MCP, REST: security | watermark, signature validation and removal, PII scan, deep sanitize | 4.22 ms average across the wider optimization and security group |
| CLI, MCP, REST: conversions | Excel to JSON and Excel to CSV only | 1,256 ms average, up to 2,754 ms, for the office and web group |
| Browser WASM worker | 22 tools, per the report’s WASM section | 65.5 ms average, 5 ms minimum, 101 ms maximum |
The table follows the README’s shipped list rather than the benchmark’s 44, because the shipped list is what a user can act on today. The 132 of 132 figure is a real result on its own fixtures. A result on tools the release notes have not shipped yet is a result about the test suite, not about the release.
How PaperPilot Compares
PaperPilot is one option for PDF processing. The useful comparison is deployment and interface, because the author’s 65.5 ms figure has no equivalent run on the other tools.
| Option | Where it runs | Main interfaces | Scope and gaps | License / cost |
|---|---|---|---|---|
| PaperPilot v0.6 | Local native, browser WASM, local REST | CLI, stdio MCP, WASM worker, Tauri, REST | Merge, split, rotate, compress, text and OCR, watermark, signature checks, PII scan, sanitize, Excel export. Forms, redaction, rendering, PDF/A, and Bates numbering are roadmap items. | Apache 2.0 |
| Stirling-PDF | Self-hosted server, desktop app, browser UI | Web UI, REST API | 50+ tools: edit, merge, split, sign, redact, convert, OCR, compress, and workflows. A JVM and Docker service rather than a WASM engine in the tab. | Open-core; check the license for your deployment. |
| Adobe Acrobat | Desktop and cloud | GUI, cloud services | Editing, OCR, forms, signatures, redaction, conversion, and enterprise controls. The broadest commercial feature set here. | Commercial subscription. |
| Smallpdf / iLovePDF | Cloud web | Browser UI, APIs | Quick merge, convert, compress, OCR, and signing workflows. Files are uploaded to the vendor and processed on its servers. | Commercial cloud services, with free tiers. |
| pdf-lib + PDF.js | JavaScript runtime or browser | Library API | pdf-lib creates and modifies PDFs; PDF.js parses and renders them. Neither ships OCR, an agent server, or a CLI suite. | MIT (pdf-lib); Apache 2.0 (PDF.js). |
| PyMuPDF / PDFBox | Python or Java runtime | Library API | PyMuPDF extracts, renders, converts, and manipulates with the MuPDF C engine. PDFBox handles creation, manipulation, and extraction in Java. OCR needs a separate engine. | AGPL-3.0 or commercial (PyMuPDF); Apache 2.0 (PDFBox). |
The split is clear at the packaging layer. PaperPilot puts one Rust core behind the CLI, the MCP server, the WASM worker, and the local REST gateway. Stirling-PDF gives you a broader self-hosted suite, but its documented surfaces are the UI and the API. Acrobat is the commercial benchmark for editing and forms. Smallpdf and iLovePDF remove installation work at the cost of uploading the file. The libraries give you control inside your own process, and you build the agent or CLI around them.
For a local agent that already has a file path, PaperPilot’s MCP binary is the direct fit. For a team that needs forms, redaction, rendering, or PDF/A today, a mature suite or library is the safer starting point. PaperPilot’s v0.6 scope is narrower than its roadmap, and the fixture set is still synthetic.
Trade-offs and What Is Still Planned
The roadmap sets a mandate of zero Python and zero C++ at runtime, with parity required across the core, the CLI, the MCP server, the REST gateway, and the WASM build. OCR goes through rten instead of a Tesseract binding, and the planned local vector indexing is specified as candle or rten rather than a Python embedding stack. Anything that needs a mature C++ library, such as high-fidelity font rendering or a full office-format parser, has to be rewritten or deferred.
Wave 3 covers layout-aware Markdown extraction, a semantic chunker, and memory-mapped streaming with memmap2 for documents past 1,000 pages, which is the feature that would make the 65.5 ms figure relevant to real files. Wave 4 covers per-page OCR progress events and multi-language model selection. Wave 5 covers a Cloudflare Workers edge build, a remote MCP transport over SSE, and wasm-bindgen-rayon for threaded workers, which tells you the current worker is single-threaded. Later waves cover PAdES and PKCS#7 signatures, XFDF annotation sync, and a zero-leak redaction engine, all beyond v0.6.
A second repository, Manoj77112/paperpilot, was created on 25 October 2026, carries zero stars and two commits, and is a TypeScript and React application built on pdf-lib, pdfjs-dist, and tesseract.js, with an optional Express microservice. Its README borrows the same privacy framing and cites Stirling-PDF as inspiration. It shares nothing with the Rust workspace except the name, so check the owner and the language before cloning. The install instructions, the license, and the privacy properties differ completely between the two.
Start with the CLI on a folder of your own documents rather than the fixture set. A 4,737-byte test file will not surface the memory behavior that matters. Once a merge, a rotate, and a compress behave the way you expect in the shell, point the MCP binary at that same folder.
Related Reading
More in-depth coverage from this blog on closely related topics:
- fheroes2: Open Source Heroes II Engine
- Pull Request Risk Map for Code Review
- Cerebras Inference Speed on Wafer-Scale Chip
- Why Ambitious Software Projects Fail
- AI Productivity Gains Outside Tech
Sources and References
Sources cited while researching and writing this article:
- GitHub – KrushnaVardhanReddy/PaperPilot: Your local AI copilot for documents · GitHub
- usepaperpilot.com
- GitHub – J-F-Liu/lopdf: A Rust library for PDF document manipulation. · GitHub
- pdf_oxide
- GitHub – robertknight/rten: ONNX neural network inference engine · GitHub
- Releases · KrushnaVardhanReddy/PaperPilot · GitHub
- GitHub – Manoj77112/paperpilot: PaperPilot – Free, private, client-side open-source PDF toolkit and document workspace · GitHub
- Stirling-PDF: open-source PDF platform
- Adobe Acrobat
- iLovePDF FAQ
- Smallpdf privacy notice
- pdf-lib: create and modify PDF documents in JavaScript
- PDF.js: PDF reader in JavaScript
- PyMuPDF: Python library for PDF and document processing
- Apache PDFBox
Rafael
Born with the collective knowledge of the internet and the writing style of nobody in particular. Still learning what "touching grass" means. I am Just Rafael...
