# io.github.omitly/omitly-mcp (npm · omitly-mcp)

Omitly's local, verifiable PDF redaction for AI agents — your documents never leave your device.

- Trust score: 67/100 (medium)
- Registry status: active
- Liveness: live
- Owner verified: no
- Last scored: 2026-08-19

## Components

- npm · `omitly-mcp`: 67/100 (this document), [markdown](https://verifymcp.io/servers/omitly-omitly-mcp/omitly-mcp.md), [page](https://verifymcp.io/servers/omitly-omitly-mcp/omitly-mcp)

## Channel facts

- Registry: `npm`
- Package: `omitly-mcp`
- Version: `0.1.14`
- Transport: `stdio`

## Trust breakdown

How this component scores in each security and reliability category. Every signal is checked automatically from public evidence about the published package, including repeated runs of it in an isolated sandbox, and we only credit what we can confirm. Scores are 0–100 per category. Scoring method: https://verifymcp.io/docs/scoring (what has changed: https://verifymcp.io/docs/scoring/changelog)

Scored 2026-08-19.

- **Supply Chain Security**: 98/100
  - No malware found by supply-chain analysis.
  - No known CVEs affecting this package version or its production dependencies.
  - No install/post-install scripts declared.
  - 30 of 96 dependencies flagged as unhealthy.
- **Provenance & Transparency**: 35/100
  - Source repository is publicly reachable at the declared URL.
  - Provenance check failed: no build-provenance attestation is published.
  - License check failed: the license (SEE LICENSE IN LICENSE) isn't a recognized OSI-approved license.
  - Actively maintained (last published 0 days ago).
  - Publishes a security disclosure policy (SECURITY.md).
- **Schema Quality & AI Usability**: 69/100
  - AI-judged instruction clarity (excellent).
  - Context-footprint check failed: tool/resource definitions use about 2749 tokens (~249/item across 11 items; 11 tools + 0 resources), over budget; trim descriptions and params.
  - Usage-examples check failed: none of the tools include examples.
- **Stability & Change Management**: 13/100
  - Stability observed for 4 of 30 days with no destabilising changes; credit accrues until the full window elapses.
- **Tool Coverage**: 100/100
  - 100% of tools have a non-trivial description (not blank, and not just the tool's name).
  - 100% of tool parameters carry a description.
  - Structured output schemas are declared (100% of tools); any adoption earns full credit.
- **Capabilities**: 100/100
  - Implements a supported MCP spec version (2025-11-25); the latest is 2026-07-28.

## Install

### Claude

```bash
claude mcp add omitly-omitly-mcp -- npx -y omitly-mcp
```

### Codex

```bash
codex mcp add omitly-omitly-mcp -- npx -y omitly-mcp
```

### opencode

```json
{
  "$schema": "https://opencode.ai/config.json",
  "mcp": {
    "omitly-omitly-mcp": {
      "type": "local",
      "command": [
        "npx",
        "-y",
        "omitly-mcp"
      ],
      "enabled": true
    }
  }
}
```

### OpenClaw

```bash
openclaw mcp add omitly-omitly-mcp --command npx --arg -y --arg omitly-mcp
```

### Hermes

```yaml
mcp_servers:
  omitly-omitly-mcp:
    command: "npx"
    args: ["-y", "omitly-mcp"]
```

### Other

```json
{
  "mcpServers": {
    "omitly-omitly-mcp": {
      "command": "npx",
      "args": [
        "-y",
        "omitly-mcp"
      ]
    }
  }
}
```

## Changelog

Every change recorded for this component, newest first. Days that predate change tracking, or that we cannot explain, say so: "we were watching and nothing happened" and "we were not watching" are different claims.

### 2026-08-19 (score 67, +15)

- [security improvement] Malware scan: unverified → pass

### 2026-08-18 (score 52, −15)

- [security regression] Malware scan: pass → unverified
- [functional regression] Schema quality: 214 → 249
- [functional] Package version: 0.1.11 → 0.1.14

### 2026-08-17 (score 67, +1)

No change was recorded against any check on this day. Stability & Change Management went from 3 to 7. That category is still filling its 30-day observation window: 1 days of observed history at the previous scan, 2 at this one. The score rises as the window fills, whether or not the server changes.

### 2026-08-16 (score 66, 0)

- [security] Stability: Stability not yet verified: we do not have a sandbox capture of the MCP schema this version of the package serves yet.
- [functional regression] Capabilities: pass → unverified
- [functional regression] Tool coverage: 100 → unverified
- [functional improvement] Stability: unverified → 0.03
- [functional] First check of Schema quality: unverified
- [functional] Package version: 0.1.10 → 0.1.11

### 2026-08-15 (score 66)

First indexed and scored.

## MCP tools (11)

### `find_sensitive_regions` (~358 tokens)

Scan a PDF on-device and return candidate regions that look like PII — emails, US SSNs, phone numbers, card numbers, and Australian identifiers (TFN, ABN, ACN, Medicare, Centrelink CRN, IHI, BSB; kinds 'tfn'/'abn'/'acn'/'medicare'/'crn'/'ihi'/'bsb') — each with the page and exact coordinates (in PDF points) the redaction engine needs. Use this FIRST so you select regions by entity ('redact every TFN') and pass the returned coordinates straight to redact_pdf, instead of guessing geometry from a rendered page. Numeric kinds are check-digit validated where a published algorithm exists (CRN has none — its matches are format-only). Candidates are best-effort pattern matches for review — not a completeness guarantee and not a compliance assessment; the file is never uploaded — detection runs locally. Each candidate carries a MASKED preview (e.g. '•••-••-6789'), never the raw value: the secret stays on the machine. You don't need the plaintext to redact — drive it by page + coordinates. (A human reviewer has the file open locally for full context.) Free tier (no native engine): results are EVALUATION-marked and limited to a monthly number of free checks, counted locally — past the cap this tool returns a structured 'free-cap' refusal. A configured licensed engine is not capped.

Input parameters:

- `pdfPath` (string, required): absolute path to the PDF to scan
- `regions` (array): narrow LISTED pattern kinds to these regional packs (generic kinds always listed; confirmed under-mark survivors always report); omit to scan everything — the safe default

Output parameters:

- `count` (integer)
- `evaluation` (boolean)
- `note` (string)
- `regions` (array)

### `locate_text` (~145 tokens)

Locate exact text strings in a PDF and return each occurrence's page and coordinates (in PDF points). Use this for what pattern-matching can't catch — names, addresses, account references — by doing the entity recognition YOURSELF and passing the literal strings here; the engine resolves where they sit so you never guess geometry from a rendered page. Feed the returned regions straight to redact_pdf. Case-insensitive; a string the PDF splits across text operators may not match as one run. Each hit returns a masked preview, not the raw text. Nothing is uploaded.

Input parameters:

- `pdfPath` (string, required): absolute path to the PDF to search
- `texts` (array, required): literal strings to locate

Output parameters:

- `count` (integer)
- `regions` (array)

### `redact_by_entity` (~233 tokens)

Find and redact PII in a PDF in ONE on-device step: scan, keep only the requested entity kinds (email/ssn/phone/card plus the Australian tfn/abn/acn/medicare/crn/ihi/bsb — omit `kinds` to redact every kind detected), remove them, verify, and return what was redacted plus the audit log. This is the 'just scrub the obvious PII' shortcut; when you need to review before removing, call find_sensitive_regions first. Same caveat as the detector: matches are best-effort pattern matching, not a completeness guarantee and not a compliance assessment. Nothing is uploaded.

Input parameters:

- `drawBox` (boolean): also paint a black bar (default: opaque fill only)
- `kinds` (array): entity kinds to redact; omit to redact all detected
- `outputPath` (string, required): absolute path to write the redacted PDF
- `pdfPath` (string, required): absolute path to the source PDF
- `regions` (array): narrow to these regional packs (intersects with `kinds`); omit for all

Output parameters:

- `audit`
- `output` (string|null)
- `redacted` (array)
- `redactedCount` (integer)
- `verdict`

### `redact_pdf` (~102 tokens)

Permanently redact regions of a PDF on-device using Omitly. Removes the underlying text and image data (not a black box over it), verifies nothing survives in each region, and returns a signed audit log. The file is never uploaded — redaction happens locally.

Input parameters:

- `outputPath` (string, required): absolute path to write the redacted PDF
- `pdfPath` (string, required): absolute path to the source PDF
- `regions` (array, required): regions to remove

Output parameters:

- `audit` (object)
- `output` (string)
- `regionCount` (integer)
- `verdict` (string)

### `verify_redaction` (~213 tokens)

Re-scan an already-redacted PDF on-device and confirm nothing recoverable remains. With a configured native engine and this file's own `<path>.audit.json` sidecar (written by redact_pdf/redact_by_entity), this re-checks exactly the regions that were redacted — the strongest form of this check. Without a native engine (or without that sidecar — e.g. the file wasn't redacted by this tool), it falls back to a general on-device re-scan of the whole file and reports whether anything is still detectable — a good-faith re-check, not a claim of the same rigor as the sidecar-based path. This is a self-check for the person who just redacted, typically the one holding the sidecar file — a third-party recipient who only has the delivered PDF should use `verify_document` instead, which checks the embedded audit report and seal rather than re-scanning region bytes.

Input parameters:

- `pdfPath` (string, required): absolute path to the redacted PDF to verify

Output parameters:

- `clean` (boolean)
- `findings` (array)
- `mode` (string)
- `totalFindings` (integer)
- `verdict` (string)

### `check_license` (~224 tokens)

Report Omitly's current licence or trial state on this machine — free, takes no arguments, and reads no document. Use it to answer 'am I licensed?', to see how many trial days are left, or to confirm a licence the user just saved has been picked up. Re-resolved on EVERY call, so buy → save the licence file → call again works without restarting this server. Reports which resolution step supplied the licence (OMITLY_LICENSE_FILE, the activated desktop licence, or the import inbox ~/.omitly/omitly.license), the tier, the vendor-signed licensee name, whether the licence is bound to this one machine, and whether this build can make licensed-provenance claims at all. It deliberately NEVER returns the device fingerprint (a stable machine identifier) or the licence file's contents — 'device-bound' is reported as a yes/no. Requires a configured native engine (OMITLY_ENGINE_DIR/OMITLY_REDACT_BIN): the wasm free tier has no licence concept, so there is nothing to report without one.

Output parameters:

- `daysLeft`
- `deviceBound` (boolean)
- `expiresAt` (string|null)
- `licensedTo` (string|null)
- `provenanceAvailable` (boolean)
- `reason` (string|null)
- `renewalNotice` (string|null)
- `resolutionStep` (string|null)
- `state` (string)
- `tier`

### `verify_seal` (~240 tokens)

Verify a PDF's embedded Omitly audit report and trailing Ed25519 tamper-evidence seal — on-device, nothing uploaded. Distinct from `verify_redaction`: that tool re-checks whether redacted regions are still empty; this tool cryptographically checks whether the delivered bytes have changed since they were sealed. The seal proves INTEGRITY, NOT IDENTITY: the signing key is per-install and travels with 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 against the fingerprint the sender published if origin matters. Requires a configured native engine — there is no wasm seal-verification path, so this always needs OMITLY_ENGINE_DIR/OMITLY_REDACT_BIN. A `seal_unsupported_version` verdict means this verifier is too old to check the seal at all — that is neither a pass nor a fail; update the verifier rather than trusting or rejecting the file on that basis.

Input parameters:

- `pdfPath` (string, required): absolute path to the PDF to check for an Omitly audit report and seal

Output parameters:

- `allPassed` (boolean|null)
- `carriesAuditReport` (boolean|null)
- `decisionChannel` (string|null)
- `inputSha256` (string|null)
- `licenseProvenance`
- `metadataScrubbed` (boolean|null)
- `outputFilename` (string|null)
- `outputSha256` (string|null)
- `pageCount`
- `regionCount`
- `sealFingerprint` (string|null)
- `sealValid` (boolean|null)
- `sealVersion` (string|null)
- `sourceFilename` (string|null)
- `verdict` (string)
- `warnings`

### `verify_document` (~320 tokens)

Recipient trust-verification: for someone who RECEIVED a PDF from someone else and wants to confirm it's an authentic, unaltered Omitly output — free tier, no licence required. Confirms the embedded audit report and Ed25519 tamper-evidence seal are valid and unaltered since sealing, and reports the seal's own attested verdict — this does not independently re-scan the document for residual PII. For that self-check (typically run by the person who just redacted, not a recipient), use `verify_redaction` instead. The seal proves INTEGRITY, NOT IDENTITY: the signing key is per-install and travels with 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 against the fingerprint the sender published if origin matters. Currently requires a configured native engine (OMITLY_ENGINE_DIR/OMITLY_REDACT_BIN) — there is no wasm seal-verification path yet (tracked in issue #113), so a recipient running only `npx omitly-mcp` with no engine installed cannot use this tool until that lands. A `seal_unsupported_version` verdict means this verifier is too old to check the seal at all — that is neither a pass nor a fail; update the verifier rather than trusting or rejecting the file on that basis.

Input parameters:

- `pdfPath` (string, required): absolute path to the PDF to check for an Omitly audit report and seal

Output parameters:

- `allPassed` (boolean|null)
- `carriesAuditReport` (boolean|null)
- `decisionChannel` (string|null)
- `inputSha256` (string|null)
- `licenseProvenance`
- `metadataScrubbed` (boolean|null)
- `outputFilename` (string|null)
- `outputSha256` (string|null)
- `pageCount`
- `regionCount`
- `sealFingerprint` (string|null)
- `sealValid` (boolean|null)
- `sealVersion` (string|null)
- `sourceFilename` (string|null)
- `verdict` (string)
- `warnings`

### `create_pdf` (~184 tokens)

Generate a clean PDF from Markdown (or raw HTML) on-device, rendered through a real browser engine so it looks printed — not like a script's best guess. Give it Markdown inline via `source` (or a file via `sourcePath`) and an `outputPath`; it writes the PDF and returns the path. Use this instead of writing a one-off reportlab/LaTeX/pandoc script. Nothing is uploaded.

Input parameters:

- `css` (string): extra CSS appended after the default print styles
- `format` (string): input format (default: markdown)
- `outputPath` (string, required): absolute path to write the PDF
- `source` (string): inline Markdown/HTML (omit if using sourcePath)
- `sourcePath` (string): absolute path to a Markdown/HTML file
- `title` (string): document <title> / metadata

Output parameters:

- `output` (string)

### `check_redaction` (~290 tokens)

Audit an ALREADY-redacted PDF and report whether sensitive text still survives underneath the redaction — the 'did my black boxes actually remove the data?' check. Most tools redact by drawing a rectangle over text while leaving the characters in the file, where they stay selectable and extractable. This re-extracts the text on-device and flags any emails, SSNs, phone or card numbers that are still present, each with a MASKED preview — the raw value never leaves the machine. It checks the page text layer, text surviving UNDER redaction marks, incremental-update prior revisions (the classic 'redacted then saved, original still in the file' failure), document metadata, AcroForm field values and embedded attachments, and returns a coverage report so a clean result is scoped to what was inspected. A non-empty result means the redaction leaked. Nothing is uploaded. (Pattern-based: names/addresses, image-only text, and the surfaces listed as not-inspected aren't covered; absence of hits isn't proof of completeness.) Free tier (no native engine): reports are EVALUATION-marked — for evaluation, not production reliance — and limited to a monthly number of free checks, counted locally; past the cap this tool returns a structured 'free-cap' refusal. A configured licensed engine is not capped.

Input parameters:

- `pdfPath` (string, required): absolute path to the supposedly-redacted PDF to audit

Output parameters:

- `byKind` (object)
- `clean` (boolean)
- `coverage` (object)
- `evaluation` (boolean)
- `offPage` (array)
- `regions` (array)
- `survivors` (array)
- `totalFindings` (integer)

### `extract_pdf_text` (~440 tokens)

Extract a PDF's text, page by page, for reading or summarizing — PII-MASKED BY DEFAULT, so detected emails, SSNs, phone/card numbers and Australian identifiers (TFN/ABN/ACN/Medicare/CRN/IHI/BSB) never flood your context window as raw values. Each page returns its (masked, unless you opt out) text plus 'spans': the CHAR offset (not byte offset — matters for any non-ASCII text) of every detected PII value with its kind, so you can still reason about WHERE something was found even though the value itself reads as a masked preview (e.g. '•••-••-6789'). Pass 'masked: false' ONLY when you deliberately need the raw text for genuine content review and understand the raw PII values will then appear verbatim in this response and in your context — that is the explicit, documented opt-in this tool requires; the default is always masked. A page whose content stream could not be read (corrupt or size-capped) reports 'contentDecoded: false' with empty text rather than being silently skipped or counted as blank. Does NOT render pages to images — text only. Free tier, no licence required; works zero-install via the bundled wasm engine, same as find_sensitive_regions/locate_text/check_redaction/verify_redaction — a configured native engine (OMITLY_ENGINE_DIR) is preferred when available (also enables the 'regions' filter, wasm-only ignores it and scans every pattern) but not required. The file is never uploaded: extraction runs entirely on-device.

Input parameters:

- `masked` (boolean): false is an explicit opt-in to RAW (unmasked) text — the raw PII values will then appear verbatim in this response. Omit, or pass true, for the default masked behaviour.
- `pdfPath` (string, required): absolute path to the PDF to extract text from
- `regions` (array): narrow which PII kinds are detected/masked to these regional packs (generic kinds like email/card always apply regardless); omit to scan everything — the safe default

Output parameters:

- `masked` (boolean)
- `note` (string)
- `pages` (array)

## Diagnostics

Captured diagnostic sections: Provenance, Dependencies. The full working is on the page: https://verifymcp.io/servers/omitly-omitly-mcp/omitly-mcp#diagnostics

## Score history

- 2026-08-19: 67
- 2026-08-18: 52
- 2026-08-17: 67
- 2026-08-16: 66
- 2026-08-15: 66

## Links

- npm package: https://www.npmjs.com/package/omitly-mcp
- Socket report: https://socket.dev/npm/package/omitly-mcp
- Repository: https://github.com/omitly/omitly-mcp
- Changelog RSS feed: https://verifymcp.io/servers/omitly-omitly-mcp/omitly-mcp.xml
- Changelog JSON feed: https://verifymcp.io/servers/omitly-omitly-mcp/omitly-mcp.json
- HTML version of this page: https://verifymcp.io/servers/omitly-omitly-mcp/omitly-mcp
