A PDF can stay on your computer while information from it travels somewhere else. No contradiction required. The local tool and the agent using it occupy different parts of the system. đź“„
PaperPilot is getting attention for a Rust document engine exposed through a CLI, browser interface, desktop app, local HTTP service and MCP server. The appealing part is straightforward: common document operations do not have to begin with uploading a PDF to a conversion website. [1]
But when I connect a local tool to an assistant, I want to trace the return path, too. Where do the filenames, search queries, extracted text and error messages go after the tool finishes?
Original source-traced architecture diagram. The provider arrow is conditional on the client's configuration; it is not a captured PaperPilot network trace.
Follow a concrete operation through the source 🔎
At the pinned PaperPilot revision linked below, pdf_extract_text loads the input file, runs the extraction operation, joins the extracted pages and writes the result to the requested output path. Its successful operation result contains a success message and that output path. Its data field is empty. [2]
That detail matters. It would be inaccurate to say this operation always sends the complete extracted document back in its MCP reply. In this branch, it writes the text to a file and reports where it went.
Now add an agent. If the client subsequently reads that output file to summarize it, the extracted text may enter the client's model request. That is a separate action with a separate data flow. Whether it reaches a hosted provider depends on the client, model and surrounding configuration.
The original PDF need never be uploaded for its contents to become part of a prompt. Equally, using MCP does not mean contents must be uploaded. A local model and local tool can keep that part of the path local. đź’ˇ
A tool result is information, too
PaperPilot's pdf_search branch illustrates a different return shape. It searches a document and builds a message reporting matching page indices, or that no matches were found. The general response wrapper serializes the operation result into MCP text content. [2]
That is much less than returning the whole document. It can still disclose a fact about it: whether a particular query matched, and where. A file path can also reveal a client name or a project label before anyone reads a page.
I think of this as a set of envelopes rather than a single “local/cloud” switch:
- The input envelope: file bytes and paths made available to the process.
- The result envelope: messages, metadata, paths or content returned to the client.
- The model envelope: whatever that client actually places in a subsequent model request.
The envelopes can overlap. Inspecting one does not tell you everything about the others.
Choose the surface for the job
For a deterministic merge or rotation, a local CLI can avoid involving a model at all. That removes the model-request envelope from that particular workflow. For interactive document work, a browser or desktop surface may be more convenient. For language-driven orchestration, MCP gives the agent a tool interface.
None of those choices alone establishes the complete privacy story. A browser-delivered application still needs its own review; a local service needs an appropriate binding and access policy; an agent needs a decision about what it may read and send. These are different questions, even when the underlying PDF operation is shared.
⚠️ A common mistake is to treat “stdio” as a confidentiality certificate. It describes how processes exchange messages. It does not describe what a client does with those messages afterward.
MCP roots provide a way for clients to describe intended filesystem boundaries, and the specification asks servers to validate paths against them. A declared root is not, by itself, proof that an operating system prevents a process from reading anything else. [3]
The inspection I would actually perform
I would start with a synthetic document containing a distinctive harmless phrase. Inspect the tool request, tool response and any subsequent file read separately. Then inspect what the configured client sends to its model. Keep logs themselves inside the intended boundary.
That sequence gives specific answers: did a path leave, did content leave, and which component sent it? It is more informative than watching the document tool alone and declaring the entire agent session offline. âś…
This article is a source-based architecture explanation. I have not run PaperPilot's PDF engine, captured its network traffic or audited every operation or dependency. The conditional flows above are an interpretation of the inspected branches and the client/tool boundary, not a security certification or an allegation of observed leakage.
Local document processing is a useful capability. I just want the word “local” attached to the component it actually describes.
References
[1] PaperPilot, project overview.
[2] PaperPilot, MCP operation handlers at revision ba6c05d, especially pdf_extract_text, pdf_search and the operation-result wrapper. The setup guide distinguishes the server from each agent's model authentication.
[3] Model Context Protocol, roots and path-validation guidance.
Original architecture diagram created for this article. No third-party project imagery reused.
AI disclosure
AI was used to draft the article.

Top comments (0)