Citra (SylphxAI/pdf-reader-mcp): a local MCP server that returns citable PDF evidence
Give your AI agent eyes for PDFs — structured text, tables, OCR, visual evidence, and page-level citations via MCP. Native Rust, local-first.
At a glance
- What is it?
- Citra wraps a native Rust PDF engine behind three MCP tools and returns page-level geometry instead of flattened text. The design is evidence-first and fails closed, which is a real constraint as much as a feature.
- Who is it for?
- Adopt Citra if your agent must quote a specific page, table cell or bounding box and you want the PDF to stay on the machine. Do not adopt it if you need a platform outside the five published native targets, or if you want a pure JavaScript fallback when the binary is missing, because the project states it fails closed instead.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 3 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 15, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
The problem Citra targets: agents that invent page numbers
A language model reading a PDF through a text dump has no way to point at anything. The README frames the failure directly: page numbers get invented or dropped, tables arrive flattened, and scanned pages become noise. Citra's answer is to return what the project calls an Agent Document Twin, meaning the extracted content carries page numbers, geometry and provenance alongside the text. The README's own contrast is a claim of "$12.4M" attributed to page 14, table 3, cell (row 4, col 2), against a vague "about $12M" with no location. That distinction is the whole product. It matters most for financial reports, research papers and scanned documents, which the README lists as the flagship cases. The intended user is an agent framework or a developer building one who needs the model to cite rather than paraphrase. If your pipeline only needs plain text and nobody downstream asks where a number came from, the citation layer is overhead you are paying for.
Three tools, one binary: how the pieces fit together
The surface is deliberately small. read_pdf is the default path and returns markdown, tables, structure, OCR output and citations. search_pdf locates page and snippet matches so an agent can look before it reads. pdf_evidence handles crops, renders, inspection and focused evidence operations. A minimal read_pdf call takes a sources array of objects with a path key, as in the README example pointing at an absolute path. Underneath, the README states that production is a native Rust engine reached through a thin Node launcher. The native code is shipped as an optional platform package, and npm selects only the one matching the host: darwin-arm64, darwin-x64, linux-x64-gnu, linux-arm64-gnu, or win32-x64-msvc. That is the architecture in one line: a JavaScript entry point that exists to find and start a per-platform binary, plus an SDK exposed at @sylphx/citra/sdk with read, search and evidence methods, and a lower-level @sylphx/citra/pure-rust path described as low-level client helpers.
The fail-closed decision and what it costs you
The README is explicit that a missing native binary means fail closed, with no silent TypeScript PDF engine as a fallback. Read that as a deliberate trade. Silent fallbacks are how a system ends up quietly producing worse extractions on one machine than another, and Citra refuses to do that. The cost is that an unsupported host is not a degraded experience, it is no experience. The published platform table covers five targets. Alpine Linux with musl, FreeBSD, or an unusual architecture is not on that list, so a container built on musl will not resolve a native package. The same applies to CI images that strip optional dependencies. If your deployment depends on the binary being present, the install step is a hard prerequisite, not a suggestion. This is the single design choice most likely to decide whether Citra fits your stack, and it is worth testing before anything else.
Getting it running: npx, one config block, or a global bin
The fastest path is npx -y @sylphx/citra, which the README says spawns a stdio MCP server with no Docker, no API key and no global install. For Claude Code the documented command is claude mcp add citra -- npx -y @sylphx/citra. Other hosts take a JSON block with mcpServers.citra set to command npx and args ["-y", "@sylphx/citra"], named for Claude Desktop, Cursor, VS Code and Codex. A global install is npm i -g @sylphx/citra, after which the citra bin is on your path, and npx -y @sylphx/citra --help shows the CLI surface. The README notes that dual-era hosts sending server/discover before initialize, with Gemini Antigravity CLI given as the example, are supported on stdio, and release v4.1.2 is labelled as the server/discover pre-init dual-era fix. The SDK path is @sylphx/citra/sdk and requires the same platform native package as MCP. Note there is no API key and no cloud vision service in this flow, so OCR runs locally.
What the footprint and latency numbers actually measure
The README publishes a clean install comparison on linux-x64 between the historical TypeScript 3.0.14 line and the sole-Rust 4.1.0 lineage. Main package on disk drops from roughly 403 KB to about 77 KB, full node_modules from about 82.3 MiB to about 24.4 MiB, and installed files from 4,101 to 20. Production npm dependencies go from PDF.js plus the MCP TypeScript SDK and more, to an empty set plus one platform native. The README concedes the native binary is multi-megabyte because it is the PDF engine, and argues the total install is still cleaner. On speed, the methodology is narrower than the headline. The persistent_warm mode measures a long-lived server doing repeated identical local read_pdf calls after warm-up, and reports at least roughly 10x median latency improvement across eight fixture classes. The README states this includes a process-local cache keyed on identical local path plus options, and that the first request in a process still pays full parse cost. It also states plainly that this is not a multi-host guarantee. Treat the 10x as a warm-cache, single-host figure, not a general throughput claim.
Where Citra is the wrong tool
The fail-closed behaviour is the first disqualifier for anyone outside the five supported platforms. The second is scope. Citra is a reading and evidence layer, not a retrieval system: the README describes search_pdf as finding page and snippet matches before deep reading, which is not the same as building a persistent index across a corpus. If your workflow needs embeddings, chunk storage or cross-document ranking, those pieces are not in the three-tool surface. The third is the cache. The performance story depends on repeated identical local reads; a workload that reads each PDF once, or that varies options between calls, will not see the warm-path numbers. The fourth is OCR quality, which the README does not quantify at all. It says an OCR path exists and is linked to evidence, and that is the extent of the claim. There is no stated accuracy figure, no list of supported languages, and no guidance on handwriting or low-resolution scans. If OCR accuracy is the deciding factor for you, the material here does not let you judge it.
How it differs from a general document loader
The obvious alternative for an agent that needs to read files is a general-purpose loader in an orchestration framework, which typically returns document text plus metadata and leaves the model to describe where something came from. That approach has a different centre of gravity: breadth of formats over depth of provenance. Citra goes the other way. It handles PDFs, and it returns geometry, bounding boxes for table cells, page-linked OCR evidence, and trust signals when requested. The README also mentions visual crops through pdf_evidence, which a text-oriented loader generally does not produce. The trade is that a general loader will accept whatever file types your pipeline throws at it, while Citra is a PDF reader with a stated evidence contract and a docs/EVIDENCE_CONTRACT.md file describing it. If your corpus is mixed formats, you will be running Citra alongside something else rather than instead of it. The README also positions Citra inside a family of sibling instruments named Iris, Cue, Spine, Lookout and Locus, which suggests the intended split is one tool per media type.
Maintenance, licensing and what to verify before adopting
The licence is MIT, which permits commercial use and modification; that is a statement of the licence identifier and not legal advice, and you should read the LICENSE file in the repository rather than this summary. On maintenance, the material shows three releases in the weeks before the last push: v4.1.3 on 2026-08-03, v4.1.2 on 2026-07-28 described as the server/discover pre-init dual-era fix, and v4.1.1 on 2026-07-24 described as an npm README sync. The README's live version line reads 5.0.0 while the newest listed release is v4.1.3, so the README and the release list are not aligned, and that gap is worth resolving against npm before you pin a version. The upgrade cost you should expect is platform-package churn: the native binary is versioned separately per target, so an upgrade means new optional packages rather than a pure JavaScript bump. Verify three things first. Run npx -y @sylphx/citra --help on your actual host, confirm the matching @sylphx/citra-<platform> package installs, and open docs/EVIDENCE_CONTRACT.md to see whether the citation shape matches what your agent needs to emit.
Editorial conclusion
Adopt Citra if your agent must quote a specific page, table cell or bounding box and you want the PDF to stay on the machine. Do not adopt it if you need a platform outside the five published native targets, or if you want a pure JavaScript fallback when the binary is missing, because the project states it fails closed instead. Before wiring it in, run npx -y @sylphx/citra --help on the exact host, confirm the matching @sylphx/citra-<platform> package resolves, and check that your own PDFs produce page numbers you can verify by hand.
Community notes