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 +34 -0
- package/README.md +235 -0
- package/THIRD-PARTY-NOTICES.md +2214 -0
- package/dist/engine-config.js +29 -0
- package/dist/engine-config.js.map +1 -0
- package/dist/index.js +612 -0
- package/dist/index.js.map +1 -0
- package/dist/paths.js +97 -0
- package/dist/paths.js.map +1 -0
- package/package.json +54 -4
- package/skill/SKILL.md +63 -0
- package/wasm/leakcheck_wasm.d.ts +26 -0
- package/wasm/leakcheck_wasm.js +232 -0
- package/wasm/leakcheck_wasm_bg.wasm +0 -0
- package/wasm/leakcheck_wasm_bg.wasm.d.ts +11 -0
- package/wasm/package.json +12 -0
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.
|