Skip to main content
Glama
omitly

omitly-mcp

Official
by omitly

omitly-mcp

A Model Context Protocol server that exposes Omitly's local, verifiable PDF redaction to AI agents (Claude Code, Claude Desktop, and any other MCP client).

Repository scope and licence — please read before opening a PR.

This repository is source-available, not open source. See LICENSE: the code is published so you can read exactly what runs on your machine before you let it touch a confidential document. It is not licensed for reuse in other projects.

It contains the MCP server and the compiled wasm detection bundle. The Omitly redaction engine, the tamper-evidence seal and the licensing implementation are not in this repository and are developed privately; this code calls the engine, it does not contain it.

Development happens in a private repository and is mirrored here on release, so pull requests cannot be merged. Issues and security reports are very welcome — see SECURITY.md.

The point of difference: an agent can redact a document without uploading it anywhere. Redaction runs on-device through the Omitly engine and returns a signed audit log proving the data was removed — the opposite of pasting a confidential file into a chat model.

Four of the eight tools (find_sensitive_regions, locate_text, check_redaction, verify_redaction) work out of the box — npm install, no Rust toolchain, no native binary, no desktop app. They run on a wasm-bindgen build of the same detector that powers the web leak-checker at omitly.app, bundled directly in this package. create_pdf, the two write tools (redact_pdf, redact_by_entity), and verify_seal still need a configured native engine — see "Build & run" below. verify_seal has no wasm fallback at all: there is no wasm seal-verification path, so it always requires the native engine.

Tools

Tool

What it does

find_sensitive_regions

Scans a PDF on-device and returns PII candidates — email/SSN/phone/card plus Australian identifiers (TFN, ABN, ACN, Medicare, Centrelink CRN, IHI, BSB; check-digit validated where a published algorithm exists) — with page + exact coordinates, so the agent selects by entity and never guesses geometry. Best-effort pattern matching, not a compliance assessment. Optional regions (generic/us/au) narrows the listed kinds.

locate_text

Resolves literal strings the model supplies (names, addresses — anything regex can't catch) to their page + coordinates. The model does the recognition; the engine does the geometry.

redact_by_entity

One-shot: find + filter by kind (email/ssn/phone/card/tfn/abn/acn/medicare/crn/ihi/bsb) and/or regions + redact + verify. The "just scrub the obvious PII" shortcut.

redact_pdf

Removes the underlying data from given regions of a PDF, verifies nothing survives, writes the redacted file, and returns the audit log.

verify_redaction

Re-scans an already-redacted PDF and returns the verification verdict — the redaction-completeness check.

verify_seal

Cryptographically checks a PDF's embedded Omitly audit report and trailing Ed25519 tamper-evidence seal — the tamper-evidence check, distinct from verify_redaction. Integrity, not identity: the signing key is per-install and rides inside the file, so a valid seal means "unchanged since sealed by the holder of this key", never "produced by Omitly" — compare sealFingerprint out-of-band for origin. Requires a native engine; no wasm fallback exists.

create_pdf

Generates a clean PDF from Markdown/HTML on-device, rendered through a real browser engine so it looks printed — instead of writing a throwaway reportlab/LaTeX script.

Related MCP server: PDF Redaction MCP Server

PDF generation (create_pdf)

create_pdf is served by a separate binary, omitly-pdf (in crates/omitly-pdf), kept apart from the redaction engine because generation is a different trust model from verifiable redaction. It renders Markdown (or raw HTML) through a headless Chromium-family browser (Chrome/Chromium/Edge/Brave; override with OMITLY_BROWSER_BIN) — the same engine family the Omitly app's webview uses, so output looks printed rather than script-generated. omitly-pdf ships with the Omitly desktop application; its source is not in this repository. Point OMITLY_PDF_BIN at the binary to enable this tool.

// stdin
{ "command": "create", "outputPath": "/abs/out.pdf",
  "source": "# Hello\n\nBody **markdown**", "format": "markdown", "title": "Hello" }
// stdout
{ "ok": true, "output": "/abs/out.pdf" }

Typical agent flows:

  • Quick: redact_by_entity (find + redact + verify in one call).

  • Careful: find_sensitive_regions / locate_text → review → redact_pdfverify_redaction. Coordinates from find/locate drop straight into redact as its regions argument.

See DEMO.md for a full Claude Code walkthrough.

Status

The MCP surface (eight tools, schemas, transport), the native engine binary (crates/omitly-cli, built as omitly-redact), and the bundled wasm engine (crates/leakcheck-wasm, covering the four free tools without a native binary) are all implemented and pass end-to-end tests. find_sensitive_regions is a first-pass detector (ASCII patterns, per-show-operator matching): treat its hits as candidates for review, not a completeness guarantee. An LLM can always supply additional regions directly.

Privacy of findings. Detection results are returned with a masked preview (e.g. •••-••-6789), never the raw value. The file isn't uploaded and the secret detected inside it isn't sent back through the model — redaction is driven entirely by page + coordinates, so the plaintext stays on the machine.

Engine contract (implemented in crates/omitly-cli)

The server spawns OMITLY_REDACT_BIN, writes a JSON request to stdin, and reads a JSON response from stdout. Any failure returns { "ok": false, "error": "..." } (the process still exits 0, so the caller reads ok rather than the exit code).

// stdin
{ "command": "find", "pdfPath": "..." }
// stdout
{ "ok": true, "count": 2, "regions": [
  { "page": 0, "x": 250.4, "y": 610.4, "width": 79.2, "height": 14.4, "kind": "ssn", "preview": "•••-••-6789" } ] }
// `preview` is masked — the raw value never leaves the process; redaction is driven by coordinates.
// stdin
{ "command": "redact", "pdfPath": "...", "outputPath": "...",
  "regions": [{ "page": 0, "x": 72, "y": 700, "width": 200, "height": 14, "reason": "PII.SSN" }] }
// stdout — also writes "<outputPath>.audit.json" beside the file
{ "ok": true, "output": "...", "audit": { "verdict": "pass", "regions": [ ... ], "warnings": [], "metadataScrubbed": true } }
// stdin — recovers the redacted regions from "<pdfPath>.audit.json"
{ "command": "verify", "pdfPath": "..." }
// stdout — hiddenContent re-checks thumbnails / document actions / embedded
// files on the delivered bytes (omitly#171); any fail flips the verdict
{ "ok": true, "verdict": "pass", "regions": [ ... ], "metadataScrubbed": true,
  "hiddenContent": [ { "class": "thumbnails", "verification": { "result": "pass" } }, ... ] }
// stdin — checks the embedded audit report + trailing Ed25519 seal, not
// redaction completeness (that's "verify" above)
{ "command": "verify_seal", "pdfPath": "..." }
// stdout — verdict is one of: no_report | seal_invalid |
// seal_unsupported_version | incomplete | verified. seal_unsupported_version
// means this verifier is too old to check the seal at all — sealValid is
// `null` (checked nothing), never true or false; carriesAuditReport flags
// whether the file also carries an Omitly audit report (escalation signal).
{ "ok": true, "verdict": "verified", "sealValid": true, "sealFingerprint": "...",
  "allPassed": true, "metadataScrubbed": true, "regionCount": 2, "pageCount": 4,
  "warnings": [], "licenseProvenance": null,
  "inputSha256": "...", "outputSha256": "...",
  "sourceFilename": "...", "outputFilename": "..." }

Build & run

Free tools only (find_sensitive_regions, locate_text, check_redaction, verify_redaction) — no native engine needed:

cd omitly-mcp
npm install    # published releases ship the wasm build already bundled
npm run build  # plain tsc; the wasm bundle ships prebuilt in wasm/
node dist/index.js

npm install omitly-mcp from the registry gets a package with wasm/ already built — a published install never needs Rust.

This repository also ships the compiled wasm bundle in wasm/, alongside wasm/leakcheck_wasm_bg.wasm.sha256 so you can verify the byte-for-byte artifact you received. It is the same bundle published in the npm package. That means npm install && npm run build && npm test works here with no Rust toolchain: npm run build is plain tsc. The wasm is compiled from the Omitly detection engine, whose Rust source is not part of this repository (see "Repository scope" below).

Everything, including create_pdf, verify_seal, and the two write tools (redact_pdf, redact_by_entity): verify_seal has no wasm fallback — unlike the four free tools above, it always needs the native engine configured, even though it carries no licence requirement (see "Licensing" below).

# Build and start the MCP server (no Rust toolchain needed)
npm install
npm run build
node dist/index.js

# To enable the native-engine tools as well, point at a directory containing
# the Omitly engine binaries (omitly-redact, omitly-pdf). These ship with the
# Omitly desktop application; their source is not in this repository.
OMITLY_ENGINE_DIR=/abs/path/to/engine node dist/index.js

One env var covers both binaries: OMITLY_ENGINE_DIR is the directory holding omitly-redact and omitly-pdf. Per-binary overrides (OMITLY_REDACT_BIN, OMITLY_PDF_BIN) win over the directory when set. When OMITLY_ENGINE_DIR (or OMITLY_REDACT_BIN) isn't set, find_sensitive_regions, locate_text, and check_redaction transparently use the bundled wasm engine instead — same detector, no native binary. verify_redaction does too, but with a narrower check: without a native engine there's no <path>.audit.json sidecar to verify specific regions against, so it falls back to a general re-scan of the whole file (still useful — a non-empty result still means the file isn't clean — just not the same rigor as the sidecar-based check).

find/redact need qpdf for the redaction pipeline (QPDF_BIN overrides the PATH lookup). find alone (native or wasm) is read-only and works without it.

Access control

Every path in a tool call comes from the model, so the server confines all reads and writes to one allowed directory:

  • OMITLY_ALLOWED_DIR — set it in the MCP config (recommended). Without it, the directory the server was started in is used.

  • Symlinks are resolved before the check, so a link inside the root pointing outside it is refused.

  • Outputs never overwrite an existing file (or its .audit.json sidecar); the agent is asked to pick a fresh name instead.

  • OMITLY_ENGINE_TIMEOUT_MS (default 120000) — a wedged engine process is killed at the deadline instead of hanging the agent's tool call.

These are guardrails against confused-deputy mistakes, not a sandbox against a hostile local user — see docs/THREAT-MODEL.md.

Licensing

redact_pdf/redact_by_entity are the write surface, enforced inside the engine binary (not in this server, and not bypassable by the bundled wasm fallback — wasm never touches these two tools): a Pro or Personal licence (OMITLY_LICENSE_FILE, or the Omitly desktop app's activated licence on the same machine) runs unmarked; otherwise the shared 14-day trial applies and the audit output is permanently marked as evaluation output. The redaction itself is never degraded, and licence checks never touch the network. find_sensitive_regions, locate_text, check_redaction, verify_redaction, and verify_seal are free — and verify_redaction/verify_seal are free forever with no cap and no marking (recipient-side verification everywhere is the point). The two free detection tools (find_sensitive_regions, check_redaction) on the wasm tier — i.e. with no native engine configured — are metered (omitly#226): results carry an evaluation: true flag plus an EVALUATION banner, and after a monthly number of free checks (default 10, OMITLY_FREE_CAP to tune) the tool returns a structured { blocked: true, reason: "free-cap" } refusal until the month rolls over. The count lives in ~/.omitly/usage.json (override the directory with OMITLY_STATE_DIR; written 0600) and is local-only — nothing ever phones home; deleting the file resets the free count, which is accepted (the no-network doctrine makes it unavoidable), and the counter is deliberately never consulted by any paid write path. Calls served by a configured native engine are not metered here — the licence rules above apply on that path instead. verify_seal (native-only) stays free by the same design in the engine (no Pro/Personal licence check on that command path either).

Register with Claude Code

claude mcp add omitly -- env \
  OMITLY_ENGINE_DIR=/path/to/engine-dir \
  OMITLY_ALLOWED_DIR=/path/agents/may/touch \
  node /abs/path/to/omitly-mcp/dist/index.js

Or in Claude Desktop's claude_desktop_config.json:

{
  "mcpServers": {
    "omitly": {
      "command": "node",
      "args": ["/abs/path/to/omitly-mcp/dist/index.js"],
      "env": {
        "OMITLY_ENGINE_DIR": "/path/to/engine-dir",
        "OMITLY_ALLOWED_DIR": "/path/agents/may/touch"
      }
    }
  }
}

One-click install for Claude Desktop (MCPB, free tier only)

mcpb/ packages the four free/diagnosis tools (check_redaction, find_sensitive_regions, locate_text, verify_redaction) — never the write tools — as a self-contained MCPB .mcpb extension: no Node/npm/Rust toolchain on the end user's machine, just "Install Extension…" in Claude Desktop. This is a deliberately smaller, separate server (mcpb/server/index.js) from dist/index.js above, so the bundle can never expose redact_pdf/redact_by_entity/create_pdf even by accident.

Download: releases.omitly.app/mcp/omitly-leak-check.mcpb — always the current version (published by publish-npm.yml on every real omitly-mcp release; a versioned copy + checksum also live at mcp/latest.json). Drag the downloaded file into Claude Desktop, or use "Install Extension…".

Or build it yourself from source:

npm run mcpb:pack   # copy wasm/ into mcpb/wasm + npm install + mcpb pack
                     # → dist-mcpb/omitly-leak-check.mcpb

mcpb:pack needs no Rust toolchain — it reuses the prebuilt wasm/ in this repository (builds the shared wasm detector once, then copies it into mcpb/ — see mcpb/scripts/copy-wasm.mjs). The packed .mcpb itself needs nothing but Node, already bundled inside Claude Desktop.

Not signed (mcpb sign needs a code-signing cert we don't have yet — same gate as desktop app signing). mcpb info on the packed file confirms WARNING: Not signed. Whether Claude Desktop's "Install Extension…" flow blocks or just warns on an unsigned .mcpb has NOT been confirmed against the real Desktop app in this change (no Desktop GUI in this environment) — that check is still open, tracked in omitly#225.

Install Server
A
license - permissive license
A
quality
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Related MCP Servers

  • F
    license
    -
    quality
    D
    maintenance
    A local MCP server that extracts text-layer content from PDF files, enabling AI agents to inspect, extract text, outlines, and page content.
  • A
    license
    A
    quality
    D
    maintenance
    A Model Context Protocol (MCP) server that provides comprehensive PDF redaction capabilities, including text and image redaction, search, and session-based in-memory operations using FastMCP and pymupdf.
    11
    MIT
  • A
    license
    A
    quality
    B
    maintenance
    A local-first MCP server that ingests PDFs, extracts structure, and provides semantic search and sequential navigation tools for AI clients to query and learn from documents.
    10
    MIT

View all related MCP servers

Related MCP Connectors

  • Remote MCP for C2PA intake verifier MCP, structured receipts, audit logs, and reviewer-ready evidenc

  • Generate PDFs from templates via AI chat. Works with Claude, ChatGPT, Cursor, and any MCP client.

  • Remote MCP for C2PA disclosure policy MCP, structured receipts, audit logs, and reviewer-ready evide

View all MCP Connectors

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/omitly/omitly-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server