omitly-mcp 0.0.0 → 0.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,34 @@
1
+ Omitly MCP server — Proprietary License
2
+ Copyright (c) 2026 Innisfallen Pty Ltd. All rights reserved.
3
+
4
+ This software is provided to let AI agents and MCP clients use Omitly's
5
+ local, on-device PDF tools: free functionality (detection, leak checking,
6
+ verification, document generation) at no charge, and paid functionality
7
+ (verifiable redaction and any other features gated by an Omitly licence)
8
+ subject to a valid, current Omitly licence.
9
+
10
+ Permission is granted to install and use this package to:
11
+ (a) use the free functionality for any lawful purpose; and
12
+ (b) use the paid functionality only while you hold a valid Omitly licence
13
+ issued by Innisfallen and in accordance with the Omitly Terms of
14
+ Service at https://omitly.app.
15
+
16
+ You may NOT, except to the extent permitted by applicable law that cannot be
17
+ excluded by agreement:
18
+ - copy, modify, or create derivative works of this software;
19
+ - reverse engineer, decompile, or disassemble it, or attempt to derive the
20
+ source of the closed components or engine;
21
+ - redistribute, sublicense, sell, rent, or lease it;
22
+ - circumvent, disable, or interfere with the licence gating or any
23
+ usage metering; or
24
+ - remove or alter any proprietary notices.
25
+
26
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
27
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
28
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
29
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
30
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
31
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
32
+ SOFTWARE.
33
+
34
+ For commercial licensing terms, contact hello@omitly.app.
package/README.md ADDED
@@ -0,0 +1,235 @@
1
+ # omitly-mcp
2
+
3
+ A [Model Context Protocol](https://modelcontextprotocol.io) server that exposes
4
+ Omitly's **local, verifiable PDF redaction** to AI agents (Claude Code, Claude
5
+ Desktop, and any other MCP client).
6
+
7
+ The point of difference: an agent can redact a document **without uploading it
8
+ anywhere**. Redaction runs on-device through the Omitly engine and returns a
9
+ signed audit log proving the data was removed — the opposite of pasting a
10
+ confidential file into a chat model.
11
+
12
+ **Four of the seven tools (`find_sensitive_regions`, `locate_text`,
13
+ `check_redaction`, `verify_redaction`) work out of the box — `npm install`,
14
+ no Rust toolchain, no native binary, no desktop app.** They run on a
15
+ wasm-bindgen build of the same detector that powers the web leak-checker at
16
+ omitly.app, bundled directly in this package. `create_pdf` and the two
17
+ write tools (`redact_pdf`, `redact_by_entity`) still need a configured
18
+ native engine — see "Build & run" below.
19
+
20
+ ## Tools
21
+
22
+ | Tool | What it does |
23
+ |------|--------------|
24
+ | `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. |
25
+ | `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. |
26
+ | `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. |
27
+ | `redact_pdf` | Removes the underlying data from given regions of a PDF, verifies nothing survives, writes the redacted file, and returns the audit log. |
28
+ | `verify_redaction` | Re-scans an already-redacted PDF and returns the verification verdict. |
29
+ | `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. |
30
+
31
+ ## PDF generation (`create_pdf`)
32
+
33
+ `create_pdf` is served by a **separate** binary, `omitly-pdf` (in
34
+ `crates/omitly-pdf`), kept apart from the redaction engine because generation is
35
+ a different trust model from verifiable redaction. It renders Markdown (or raw
36
+ HTML) through a headless Chromium-family browser (Chrome/Chromium/Edge/Brave;
37
+ override with `OMITLY_BROWSER_BIN`) — the same engine family the Omitly app's
38
+ webview uses, so output looks printed rather than script-generated. Build it and
39
+ point `OMITLY_PDF_BIN` at the binary:
40
+
41
+ ```bash
42
+ cargo build -p omitly-pdf --release # → target/release/omitly-pdf
43
+ ```
44
+
45
+ ```jsonc
46
+ // stdin
47
+ { "command": "create", "outputPath": "/abs/out.pdf",
48
+ "source": "# Hello\n\nBody **markdown**", "format": "markdown", "title": "Hello" }
49
+ // stdout
50
+ { "ok": true, "output": "/abs/out.pdf" }
51
+ ```
52
+
53
+ Typical agent flows:
54
+ - Quick: **`redact_by_entity`** (find + redact + verify in one call).
55
+ - Careful: **`find_sensitive_regions` / `locate_text` → review → `redact_pdf` → `verify_redaction`**.
56
+ Coordinates from `find`/`locate` drop straight into `redact` as its `regions` argument.
57
+
58
+ See [DEMO.md](./DEMO.md) for a full Claude Code walkthrough.
59
+
60
+ ## Status
61
+
62
+ The MCP surface (seven tools, schemas, transport), the native engine binary
63
+ (`crates/omitly-cli`, built as `omitly-redact`), and the bundled wasm engine
64
+ (`crates/leakcheck-wasm`, covering the four free tools without a native
65
+ binary) are all implemented and pass end-to-end tests. `find_sensitive_regions`
66
+ is a first-pass detector (ASCII patterns, per-show-operator matching): treat
67
+ its hits as *candidates for review*, not a completeness guarantee. An LLM can
68
+ always supply additional regions directly.
69
+
70
+ **Privacy of findings.** Detection results are returned with a **masked**
71
+ preview (e.g. `•••-••-6789`), never the raw value. The file isn't uploaded *and*
72
+ the secret detected inside it isn't sent back through the model — redaction is
73
+ driven entirely by page + coordinates, so the plaintext stays on the machine.
74
+
75
+ ### Engine contract (implemented in `crates/omitly-cli`)
76
+
77
+ The server spawns `OMITLY_REDACT_BIN`, writes a JSON request to stdin, and reads
78
+ a JSON response from stdout. Any failure returns `{ "ok": false, "error": "..." }`
79
+ (the process still exits 0, so the caller reads `ok` rather than the exit code).
80
+
81
+ ```jsonc
82
+ // stdin
83
+ { "command": "find", "pdfPath": "..." }
84
+ // stdout
85
+ { "ok": true, "count": 2, "regions": [
86
+ { "page": 0, "x": 250.4, "y": 610.4, "width": 79.2, "height": 14.4, "kind": "ssn", "preview": "•••-••-6789" } ] }
87
+ // `preview` is masked — the raw value never leaves the process; redaction is driven by coordinates.
88
+ ```
89
+
90
+ ```jsonc
91
+ // stdin
92
+ { "command": "redact", "pdfPath": "...", "outputPath": "...",
93
+ "regions": [{ "page": 0, "x": 72, "y": 700, "width": 200, "height": 14, "reason": "PII.SSN" }] }
94
+ // stdout — also writes "<outputPath>.audit.json" beside the file
95
+ { "ok": true, "output": "...", "audit": { "verdict": "pass", "regions": [ ... ], "warnings": [], "metadataScrubbed": true } }
96
+ ```
97
+
98
+ ```jsonc
99
+ // stdin — recovers the redacted regions from "<pdfPath>.audit.json"
100
+ { "command": "verify", "pdfPath": "..." }
101
+ // stdout — hiddenContent re-checks thumbnails / document actions / embedded
102
+ // files on the delivered bytes (omitly#171); any fail flips the verdict
103
+ { "ok": true, "verdict": "pass", "regions": [ ... ], "metadataScrubbed": true,
104
+ "hiddenContent": [ { "class": "thumbnails", "verification": { "result": "pass" } }, ... ] }
105
+ ```
106
+
107
+ ## Build & run
108
+
109
+ **Free tools only (find_sensitive_regions, locate_text, check_redaction,
110
+ verify_redaction) — no native engine needed:**
111
+
112
+ ```bash
113
+ cd omitly-mcp
114
+ npm install # published releases ship the wasm build already bundled
115
+ npm run build # local/dev only: also runs wasm-pack (needs Rust + wasm-pack)
116
+ node dist/index.js
117
+ ```
118
+
119
+ `npm install omitly-mcp` from the registry gets a package with `wasm/`
120
+ already built — a published install never needs Rust. Building **from
121
+ source** (this repo) does need `wasm-pack` (`cargo install wasm-pack`) and
122
+ the `wasm32-unknown-unknown` target, since `npm run build` regenerates the
123
+ wasm bundle from `../crates/leakcheck-wasm` via `npm run build:wasm`.
124
+
125
+ **Everything, including `create_pdf` and the two write tools
126
+ (`redact_pdf`, `redact_by_entity`):**
127
+
128
+ ```bash
129
+ # 1. Build the local engine binaries (from the repo root)
130
+ cargo build -p omitly-cli -p omitly-pdf --release # → target/release/{omitly-redact,omitly-pdf}
131
+
132
+ # 2. Build and start the MCP server
133
+ cd omitly-mcp
134
+ npm install
135
+ npm run build
136
+ OMITLY_ENGINE_DIR=/abs/path/to/target/release node dist/index.js
137
+ ```
138
+
139
+ One env var covers both binaries: `OMITLY_ENGINE_DIR` is the directory holding
140
+ `omitly-redact` and `omitly-pdf`. Per-binary overrides (`OMITLY_REDACT_BIN`,
141
+ `OMITLY_PDF_BIN`) win over the directory when set. When `OMITLY_ENGINE_DIR`
142
+ (or `OMITLY_REDACT_BIN`) isn't set, `find_sensitive_regions`, `locate_text`,
143
+ and `check_redaction` transparently use the bundled wasm engine instead —
144
+ same detector, no native binary. `verify_redaction` does too, but with a
145
+ narrower check: without a native engine there's no `<path>.audit.json`
146
+ sidecar to verify specific regions against, so it falls back to a general
147
+ re-scan of the whole file (still useful — a non-empty result still means the
148
+ file isn't clean — just not the same rigor as the sidecar-based check).
149
+
150
+ `find`/`redact` need `qpdf` for the redaction pipeline (`QPDF_BIN` overrides the
151
+ PATH lookup). `find` alone (native or wasm) is read-only and works without it.
152
+
153
+ ## Access control
154
+
155
+ Every path in a tool call comes from the model, so the server confines all
156
+ reads and writes to one allowed directory:
157
+
158
+ - **`OMITLY_ALLOWED_DIR`** — set it in the MCP config (recommended). Without
159
+ it, the directory the server was started in is used.
160
+ - Symlinks are resolved before the check, so a link inside the root pointing
161
+ outside it is refused.
162
+ - Outputs **never overwrite an existing file** (or its `.audit.json` sidecar);
163
+ the agent is asked to pick a fresh name instead.
164
+ - **`OMITLY_ENGINE_TIMEOUT_MS`** (default 120000) — a wedged engine process is
165
+ killed at the deadline instead of hanging the agent's tool call.
166
+
167
+ These are guardrails against confused-deputy mistakes, not a sandbox against a
168
+ hostile local user — see `docs/THREAT-MODEL.md`.
169
+
170
+ ## Licensing
171
+
172
+ `redact_pdf`/`redact_by_entity` are the write surface, enforced **inside the
173
+ engine binary** (not in this server, and not bypassable by the bundled wasm
174
+ fallback — wasm never touches these two tools): a Pro or Personal licence
175
+ (`OMITLY_LICENSE_FILE`, or the Omitly desktop app's activated licence on the
176
+ same machine) runs unmarked; otherwise the shared 14-day trial applies and
177
+ the audit output is permanently marked as evaluation output. The redaction
178
+ itself is never degraded, and licence checks never touch the network.
179
+ `find_sensitive_regions`, `locate_text`, `check_redaction`, and
180
+ `verify_redaction` are free forever — the wasm build backing them has no
181
+ licence logic at all, because there's nothing to gate.
182
+
183
+ ## Register with Claude Code
184
+
185
+ ```bash
186
+ claude mcp add omitly -- env \
187
+ OMITLY_ENGINE_DIR=/path/to/engine-dir \
188
+ OMITLY_ALLOWED_DIR=/path/agents/may/touch \
189
+ node /abs/path/to/omitly-mcp/dist/index.js
190
+ ```
191
+
192
+ Or in Claude Desktop's `claude_desktop_config.json`:
193
+
194
+ ```jsonc
195
+ {
196
+ "mcpServers": {
197
+ "omitly": {
198
+ "command": "node",
199
+ "args": ["/abs/path/to/omitly-mcp/dist/index.js"],
200
+ "env": {
201
+ "OMITLY_ENGINE_DIR": "/path/to/engine-dir",
202
+ "OMITLY_ALLOWED_DIR": "/path/agents/may/touch"
203
+ }
204
+ }
205
+ }
206
+ }
207
+ ```
208
+
209
+ ## One-click install for Claude Desktop (MCPB, free tier only)
210
+
211
+ `mcpb/` packages the four free/diagnosis tools (`check_redaction`,
212
+ `find_sensitive_regions`, `locate_text`, `verify_redaction`) — never the write
213
+ tools — as a self-contained [MCPB](https://github.com/anthropics/mcpb) `.mcpb`
214
+ extension: no Node/npm/Rust toolchain on the end user's machine, just
215
+ "Install Extension…" in Claude Desktop. This is a deliberately smaller,
216
+ separate server (`mcpb/server/index.js`) from `dist/index.js` above, so the
217
+ bundle can never expose `redact_pdf`/`redact_by_entity`/`create_pdf` even by
218
+ accident.
219
+
220
+ ```bash
221
+ npm run mcpb:pack # build:wasm + copy into mcpb/wasm + npm install + mcpb pack
222
+ # → dist-mcpb/omitly-leak-check.mcpb
223
+ ```
224
+
225
+ `mcpb:pack` needs the same Rust + wasm-pack toolchain as `npm run build`
226
+ (builds the shared wasm detector once, then copies it into `mcpb/` — see
227
+ `mcpb/scripts/copy-wasm.mjs`). The packed `.mcpb` itself needs nothing but
228
+ Node, already bundled inside Claude Desktop.
229
+
230
+ **Not signed** (`mcpb sign` needs a code-signing cert we don't have yet — same
231
+ gate as desktop app signing). `mcpb info` on the packed file confirms
232
+ `WARNING: Not signed`. Whether Claude Desktop's "Install Extension…" flow
233
+ blocks or just warns on an unsigned `.mcpb` has NOT been confirmed against the
234
+ real Desktop app in this change (no Desktop GUI in this environment) — that
235
+ check is still open, tracked in omitly#225.