@fenfill/mcp 0.0.1 → 0.2.0
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 +26 -0
- package/README.md +346 -4
- package/THIRD_PARTY_NOTICES +1172 -0
- package/dist/fonts/DejaVuSans.ttf +0 -0
- package/dist/fonts/Inter-Regular.ttf +0 -0
- package/dist/index.js +143688 -0
- package/dist/pdfium.wasm +0 -0
- package/licenses/DejaVu-LICENSE.txt +187 -0
- package/licenses/Inter-OFL.txt +92 -0
- package/licenses/PDFium-LICENSE.txt +196 -0
- package/licenses/PDFium-third-party.txt +591 -0
- package/package.json +52 -5
package/LICENSE
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Stanisław Ursatjew
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
The bundled third-party software keeps its own licenses: see
|
|
26
|
+
THIRD_PARTY_NOTICES and the licenses/ folder.
|
package/README.md
CHANGED
|
@@ -1,9 +1,351 @@
|
|
|
1
|
-
# @fenfill/mcp
|
|
1
|
+
# @fenfill/mcp
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
An [MCP](https://modelcontextprotocol.io) server that lets an AI agent turn a blank PDF form into a
|
|
4
|
+
filled one with [fenfill](https://fenfill.com).
|
|
4
5
|
|
|
6
|
+
**Fills happen on your machine; only blank forms and templates go to fenfill.** The agent's answers
|
|
7
|
+
are stamped into the PDF locally and are never sent to fenfill or anywhere else.
|
|
8
|
+
|
|
9
|
+
## How it works
|
|
10
|
+
|
|
11
|
+
1. **`analyze_form`** uploads the **blank** PDF to fenfill once. fenfill finds the fillable
|
|
12
|
+
fields (text boxes, checkboxes, dates, character boxes, tables, signatures) and returns them
|
|
13
|
+
with ids, types and labels. The result is cached on your machine, so asking again is free.
|
|
14
|
+
2. **`fill_form`** takes the agent's answers (`field id → value`), checks them against the
|
|
15
|
+
fields, and stamps them into a new, flattened PDF. This step runs entirely on your machine,
|
|
16
|
+
with no network at all.
|
|
17
|
+
3. Saved fenfill templates work the same way: `list_templates` → `get_template` → `fill_template`.
|
|
18
|
+
4. **`preview_page`** shows a page as an image with every field box outlined and tagged, rendered
|
|
19
|
+
on your machine. If a box is misplaced, missing or mislabeled, **`edit_template`** fixes it in a
|
|
20
|
+
local working copy that filling uses at once, and **`save_template`** keeps the fix in a saved
|
|
21
|
+
template.
|
|
22
|
+
5. **`reanalyze_template`** re-runs fenfill on some pages of a saved template (a page that was
|
|
23
|
+
never analyzed, or one that came out badly), from the blank PDF already stored with it.
|
|
24
|
+
|
|
25
|
+
### What is sent where
|
|
26
|
+
|
|
27
|
+
| Data | Sent to fenfill? |
|
|
28
|
+
| -------------------------------------------------- | ---------------------------------------------------------------------------- |
|
|
29
|
+
| The blank PDF you analyze | Yes, once (then cached locally) |
|
|
30
|
+
| Your API key | Yes, as `Authorization: Bearer` |
|
|
31
|
+
| The agent's answers, signatures and the filled PDF | **No, never** |
|
|
32
|
+
| Saved templates (blank PDF, fields, your logo) | Downloaded from fenfill to fill locally |
|
|
33
|
+
| Page previews (`preview_page`) | **No**: rendered on your machine |
|
|
34
|
+
| Layout corrections (`edit_template`) | Only on `save_template`, and then only the layout and the form's own wording |
|
|
35
|
+
| Re-analysis (`reanalyze_template`) | Only the template id, pages, kind and version: nothing is uploaded |
|
|
36
|
+
|
|
37
|
+
`analyze_form` refuses PDFs whose form fields already hold answers, and PDFs this server wrote
|
|
38
|
+
itself, so a filled-in form isn't uploaded by mistake.
|
|
39
|
+
|
|
40
|
+
On fenfill's side, uploads are encrypted on arrival. Unless you save the form as a template, the
|
|
41
|
+
blank PDF is deleted when the analysis finishes. The analysis result is kept for at most 24 hours
|
|
42
|
+
after it completes, or 1 hour after it is first fetched, whichever comes first.
|
|
43
|
+
|
|
44
|
+
## Requirements
|
|
45
|
+
|
|
46
|
+
- Node.js 22 or newer (`npx` comes with it).
|
|
47
|
+
- A fenfill API key (`ff_live_…`): fenfill → Settings → API keys. The API is available on paid
|
|
48
|
+
plans (Pro and up).
|
|
49
|
+
- Analyzing a form uses one page scan per analyzed page from your plan. Forms that already have
|
|
50
|
+
native PDF form fields are read directly, with no AI, and use none. Repeat analyses of the same
|
|
51
|
+
file come from the local cache. Filling never uses scans. `get_account` shows what's left.
|
|
52
|
+
|
|
53
|
+
## Setup
|
|
54
|
+
|
|
55
|
+
### Claude Code
|
|
56
|
+
|
|
57
|
+
```sh
|
|
58
|
+
claude mcp add fenfill --scope user -e FENFILL_API_KEY=ff_live_… -- npx -y @fenfill/mcp
|
|
5
59
|
```
|
|
6
|
-
|
|
60
|
+
|
|
61
|
+
### Claude Desktop
|
|
62
|
+
|
|
63
|
+
Edit `claude_desktop_config.json` (macOS:
|
|
64
|
+
`~/Library/Application Support/Claude/claude_desktop_config.json`, Windows:
|
|
65
|
+
`%APPDATA%\Claude\claude_desktop_config.json`), then restart Claude Desktop:
|
|
66
|
+
|
|
67
|
+
```json
|
|
68
|
+
{
|
|
69
|
+
"mcpServers": {
|
|
70
|
+
"fenfill": {
|
|
71
|
+
"command": "npx",
|
|
72
|
+
"args": ["-y", "@fenfill/mcp"],
|
|
73
|
+
"env": { "FENFILL_API_KEY": "ff_live_…" }
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
7
77
|
```
|
|
8
78
|
|
|
9
|
-
|
|
79
|
+
### Cursor
|
|
80
|
+
|
|
81
|
+
Add the same `mcpServers` block to `~/.cursor/mcp.json` (all projects) or `.cursor/mcp.json` (one
|
|
82
|
+
project).
|
|
83
|
+
|
|
84
|
+
### Other MCP clients
|
|
85
|
+
|
|
86
|
+
Any client that can launch a stdio server works: run `npx -y @fenfill/mcp` with
|
|
87
|
+
`FENFILL_API_KEY` in its environment. The installed command is `fenfill-mcp`.
|
|
88
|
+
|
|
89
|
+
On native Windows, if the client can't find `npx`, use `"command": "cmd"` with
|
|
90
|
+
`"args": ["/c", "npx", "-y", "@fenfill/mcp"]`.
|
|
91
|
+
|
|
92
|
+
## Tools
|
|
93
|
+
|
|
94
|
+
| Tool | What it does |
|
|
95
|
+
| ----------------------- | ------------------------------------------------------------------------------- |
|
|
96
|
+
| `analyze_form` | Uploads a **blank** PDF once and returns its fields. Cached locally afterwards. |
|
|
97
|
+
| `fill_form` | Fills an analyzed PDF locally, offline, and writes a new flattened PDF. |
|
|
98
|
+
| `fill_template` | Fills a saved fenfill template locally. |
|
|
99
|
+
| `list_templates` | Lists the workspace's saved templates, newest first. |
|
|
100
|
+
| `get_template` | Shows a template's fields (use `pages` to narrow a large form). |
|
|
101
|
+
| `create_recipient_link` | Creates a personal fill link for one recipient of a restricted template. |
|
|
102
|
+
| `get_recipient_status` | Shows those links' status: `pending`, `opened` or `completed`. |
|
|
103
|
+
| `get_account` | Shows the plan, page scans left and limits. |
|
|
104
|
+
| `preview_page` | Renders one page (PNG) with every field box outlined and tagged, locally. |
|
|
105
|
+
| `edit_template` | Moves, resizes, relabels, retypes, adds, deletes or regroups fields, locally. |
|
|
106
|
+
| `save_template` | Saves `edit_template`'s working copy to a saved template. |
|
|
107
|
+
| `reanalyze_template` | Re-analyzes some pages of a saved template, with no upload, and shows the diff. |
|
|
108
|
+
|
|
109
|
+
`analyze_form` options: `pages` (e.g. `"1-3,5"`; long PDFs can be analyzed in chunks, and
|
|
110
|
+
`fill_form` merges them), `save_as_template` (also keep it as a fenfill template), `access`
|
|
111
|
+
(with `save_as_template`: `"public"`, the default, or `"restricted"`, which recipient links
|
|
112
|
+
need), `estimate` (price the request first: counts the pages and spots native form fields on
|
|
113
|
+
your machine, uploads nothing, and returns `page_count`, `likely_mode`, `estimated_scans` and
|
|
114
|
+
`scans_remaining`), `detect_extra_blanks` (for PDFs with native form fields: also find blanks
|
|
115
|
+
that have no native field, such as a signature or date line, at 1 page scan per analyzed page;
|
|
116
|
+
a free analysis answers `extra_blanks_available: true` when that is likely worth it), and `force`
|
|
117
|
+
(analyze again even if cached; uses scans again). If it answers `"running"`, call it again with
|
|
118
|
+
the same arguments. To correct the layout and keep the corrections, analyze with
|
|
119
|
+
`save_as_template: true` (edits on an unsaved analysis can be used for filling and previews but
|
|
120
|
+
can't be saved); a result without a template says so in `save_note`.
|
|
121
|
+
|
|
122
|
+
When fenfill refuses an upload for capacity (`rate_limited`, `too_many_active_jobs`,
|
|
123
|
+
`queue_full`), `analyze_form` waits the server's `retry_after` (plus a little jitter) and
|
|
124
|
+
uploads again by itself, up to about 60 s of waiting per call, then reports the error with
|
|
125
|
+
`waited_s`. These refusals happen before fenfill creates a job, so the retry never pays twice;
|
|
126
|
+
cancelling the call ends the wait. `too_many_active_jobs` counts every running analysis of the
|
|
127
|
+
workspace, free native-field (AcroForm) ones included.
|
|
128
|
+
|
|
129
|
+
`fill_form` and `fill_template` take `values`, `output_path` (a new `.pdf`) and optional
|
|
130
|
+
`overwrite`. They never overwrite the input PDF.
|
|
131
|
+
|
|
132
|
+
### Previews and corrections
|
|
133
|
+
|
|
134
|
+
`preview_page` takes `path` (an analyzed PDF) or `template_id`, a 1-based `page`, optional
|
|
135
|
+
`values` (to see them stamped; the same shapes as `fill_form`, e.g. `table_rows` =
|
|
136
|
+
`[{columnId: value}, …]`, `multiselect` = an array of option ids or labels) and `dpi` (default
|
|
137
|
+
110, max 200). It returns a PNG image plus a legend: each box's tag, id, type, label and `box`;
|
|
138
|
+
a text/date field's stored `format` and `font_pt` (the size its value starts at; `font_auto`
|
|
139
|
+
when that follows the box height); a choice's options with their own boxes; a table's cells by
|
|
140
|
+
`(row, col)`, its `orientation` and headers (also printed on the image inside, or beside, the
|
|
141
|
+
first cell of each line as `R: …` / `C: …`); a `table_rows` table's columns and printed cells
|
|
142
|
+
with their boxes (fill values still go by column id). `warnings` and `placement_warnings` are
|
|
143
|
+
always present (`[]` = checked and clean): placement covers every box shown, so a plain preview
|
|
144
|
+
is a read-only placement audit (see the checks under `edit_template`). `crop`
|
|
145
|
+
(`{x, y, w, h}`, fractions) with `zoom` (default 2, max 8) renders just a region, magnified, and
|
|
146
|
+
lists only what it shows; `legend: "changed"` returns only the rows that changed since your last
|
|
147
|
+
preview of that page (the first time: since fenfill's version), each with only its changed
|
|
148
|
+
options/cells/columns (`members_changed` counts them, so a header edit doesn't list the whole
|
|
149
|
+
grid), plus `removed` ids and `moved_into` (ids that now sit inside a table or group), and
|
|
150
|
+
`legend: "none"` omits the legend. It renders the local working copy (`edit_template`) when there is one, otherwise the saved
|
|
151
|
+
template or analyzed version; `edited: true` / `false` in the result says which. The page is rendered on your machine by
|
|
152
|
+
PDFium (WebAssembly, shipped in the package; nothing native is installed), nothing is written to
|
|
153
|
+
disk, and the image goes only to the calling client.
|
|
154
|
+
|
|
155
|
+
`edit_template` takes `path` or `template_id` and up to 200 `ops`:
|
|
156
|
+
|
|
157
|
+
- fields: `set_box` (absolute `{id, x, y, w, h}` in one step), `move`, `resize`, `relabel`,
|
|
158
|
+
`retype`, `add`, `delete`, `set_format` (`date_format` is one of `DD/MM/YYYY`, `MM/DD/YYYY`,
|
|
159
|
+
`YYYY-MM-DD`, `DD.MM.YYYY`, `DD-MM-YYYY`), `set_required`, `set_description`,
|
|
160
|
+
`set_placeholder`, `set_autofill` (a browser autofill token such as `name` or `postal-code`,
|
|
161
|
+
or `null` to clear it);
|
|
162
|
+
- choices and combs: `group` (`kind: "choice" | "comb"`), `ungroup`, `set_options`, and
|
|
163
|
+
`add_option` / `remove_option`, which keep the group's id;
|
|
164
|
+
- tables: `group` with `kind: "table"` (a `cells` grid of field ids, rows × columns with `null`
|
|
165
|
+
for a gap, or `ids` laid out from their boxes; `header_cols`, `header_rows`, `orientation`,
|
|
166
|
+
`format`), `table_insert` / `table_delete` (a row or column; a new line's geometry is
|
|
167
|
+
interpolated from its neighbours unless you pass it), `table_add_cell` (fill an empty slot),
|
|
168
|
+
`table_adopt` (move a loose field into an empty slot), `set_column_type`, `set_orientation`
|
|
169
|
+
and `set_header` / `set_headers` (`{id, axis, texts: [...], start?}`, several in one op). Every cell of one column (or row, for `orientation: "row"`) has one type,
|
|
170
|
+
as in the web editor; `set_format` on a table cell applies to its whole column or row;
|
|
171
|
+
- order: `reorder {page, ids}` moves those top-level entries together, in that order, to where
|
|
172
|
+
the first of them sat, and stamps an explicit `order` on every entry of the page (the web
|
|
173
|
+
editor's layer-panel convention), so a later sub-pixel move no longer reshuffles questions.
|
|
174
|
+
|
|
175
|
+
Any id can be shortened to an unambiguous prefix of 6+ characters (the length of the preview
|
|
176
|
+
tags); an ambiguous prefix is rejected with the candidates. `add`, `move` and `set_box` take an
|
|
177
|
+
optional `snap`: `"underline"` fits the box onto the printed rule under it, `"cell"` into the
|
|
178
|
+
ruled box around it, `"answer"` into that cell's blank part (below a caption printed at its top,
|
|
179
|
+
or after one at its left), read from the page render on your machine; when nothing fits near the
|
|
180
|
+
box, the box is kept and a warning says so. Snap finds printed rules with its own simple line
|
|
181
|
+
finder (one ink threshold per page, not the web editor's wand): a very faint rule on a tinted
|
|
182
|
+
scan can be missed, and an underline box is one line of handwriting tall (as tall as the clear
|
|
183
|
+
space above the rule, within about 11–16 pt). `diff_summary.ops` lists every applied op with
|
|
184
|
+
`snapped: true/false` (when it asked for a snap) and `noop: true` when it changed nothing. After
|
|
185
|
+
each edit, the boxes you touched are checked for three placement problems: a value that would
|
|
186
|
+
print much larger than the page's other fields (an Auto box's text size follows its height), a
|
|
187
|
+
box over printed text (text layer only, so not on scans), and a box that runs a little past the
|
|
188
|
+
ruled cell it sits in (from the page render, so scans too). `set_format` merges into the stored
|
|
189
|
+
format (a date field keeps its date format when you only set `font_size`).
|
|
190
|
+
Coordinates are fractions of the page (0–1) with a top-left origin, the same as the legend's
|
|
191
|
+
`box`. Each op is checked against the rules fenfill applies when saving and is rejected with a
|
|
192
|
+
reason if it breaks them; ops apply in order, all-or-nothing each, except that a box only has to
|
|
193
|
+
lie on the page after the whole batch (so `move` then `resize` works even if the moved box
|
|
194
|
+
overhangs the page in between). `discard: true` drops the working copy. Labels, descriptions,
|
|
195
|
+
placeholders, options, date formats and checkbox symbols are the form's wording, never answers:
|
|
196
|
+
an op whose new wording matches an answer given to `fill_form`, `fill_template` or
|
|
197
|
+
`preview_page` in the same session is rejected before the working copy is written (wording that
|
|
198
|
+
contains an answer of 6+ characters, or equals one of 4–5; equal to a shorter one only warns).
|
|
199
|
+
Once a PDF is saved as a template, `fill_form` and `preview_page` on it use only that template's
|
|
200
|
+
working copy; an older copy of its unsaved analysis is dropped.
|
|
201
|
+
|
|
202
|
+
`save_template` sends the working copy of a saved template, together with the version it started
|
|
203
|
+
from: if the template changed in fenfill meanwhile, it answers `template_conflict` and keeps your
|
|
204
|
+
local edits. Before anything is sent, it refuses wording that matches an answer given to
|
|
205
|
+
`fill_form`, `fill_template` or `preview_page` in the same session (that list lives only in
|
|
206
|
+
memory). A working copy edited in an earlier session can't be checked against that session's
|
|
207
|
+
answers: `save_template` then answers `confirm_wording_needed` with the changed ids and
|
|
208
|
+
properties (never their text); review them and call again with `confirm_wording: true`. An
|
|
209
|
+
unsaved analysis can be edited for filling but not saved: to keep corrections,
|
|
210
|
+
analyze with `save_as_template: true` and edit that template. With nothing to save, it succeeds
|
|
211
|
+
with `saved: false, nothing_to_save: true`. `get_template` says `has_local_edits` (its fields
|
|
212
|
+
are fenfill's saved version; `preview_page` shows the working copy) and gives `field_count`
|
|
213
|
+
(entries listed) and `field_count_total` (the whole form); `save_template`'s `field_count` is
|
|
214
|
+
the whole saved template.
|
|
215
|
+
|
|
216
|
+
### Re-analyzing pages of a saved template
|
|
217
|
+
|
|
218
|
+
A template saved from only some pages (`analyze_form` with `pages` and `save_as_template`) has
|
|
219
|
+
pages fenfill never looked at: `get_template` lists them as `unanalyzed_pages`, and
|
|
220
|
+
`list_templates` shows `analyzed_pages` next to `page_count`. `reanalyze_template` takes
|
|
221
|
+
`template_id`, `pages` and a `kind`:
|
|
222
|
+
|
|
223
|
+
| `kind` | Use it to |
|
|
224
|
+
| --------------- | --------------------------------------------------------------------------------- |
|
|
225
|
+
| `scratch` | analyze a never-analyzed page, or replace a badly analyzed page's fields entirely |
|
|
226
|
+
| `find` | add blanks the first pass missed, keeping everything already there |
|
|
227
|
+
| `relabel` | re-derive labels, types, groups and sections, keeping the boxes |
|
|
228
|
+
| `label_missing` | fill in only the labels that are missing |
|
|
229
|
+
|
|
230
|
+
`kind` can be left out only when the pages have no fields (it then means `scratch`). Each page
|
|
231
|
+
costs one page scan; `label_missing` is free within the workspace's monthly free-label
|
|
232
|
+
allowance. `estimate: true` prices the run and starts nothing. `relabel` may reset table column
|
|
233
|
+
types and orientation, so check the template with `get_template` afterwards.
|
|
234
|
+
|
|
235
|
+
It uses the PDF already stored with the template, so nothing is uploaded. It refuses while the
|
|
236
|
+
template has unsaved `edit_template` edits (`local_edits_pending`): save them with
|
|
237
|
+
`save_template` first, or pass `discard: true` to drop them when the run finishes. The result
|
|
238
|
+
lists, per changed page, the fields `added`, `removed` and `changed` (label, type, box, or a
|
|
239
|
+
group's cells), then the new fields of those pages; review them with `preview_page` and correct
|
|
240
|
+
them with `edit_template` + `save_template`. Like `analyze_form`, it waits out capacity
|
|
241
|
+
refusals, and if it answers `"running"`, calling it again with the same arguments follows the
|
|
242
|
+
same run at no extra charge.
|
|
243
|
+
|
|
244
|
+
### Value shapes
|
|
245
|
+
|
|
246
|
+
| Field type | Value |
|
|
247
|
+
| ------------------- | --------------------------------------------------------------------------- |
|
|
248
|
+
| `text`, `multiline` | string, stamped exactly as given |
|
|
249
|
+
| `comb` | string, one character per cell |
|
|
250
|
+
| `date` | `"YYYY-MM-DD"`, printed in the field's `date_format` (e.g. `DD/MM/YYYY`) |
|
|
251
|
+
| `checkbox` | `true` / `false` |
|
|
252
|
+
| `radio` | option id, option label, or the bare option text (`"No"` for `"Smoke? No"`) |
|
|
253
|
+
| `multiselect` | array of those |
|
|
254
|
+
| `table` | `{ "<cellId>": value, … }` |
|
|
255
|
+
| `table_rows` | `[{ "<columnId>": value, … }, …]` |
|
|
256
|
+
| `signature` | `{ "image_path": "/abs/path/signature.png" }` (PNG or JPG) |
|
|
257
|
+
|
|
258
|
+
A date the form asks for in a plain `text` field is not reformatted: write it the way the field's
|
|
259
|
+
label or placeholder asks (for example `10042026` for "mmddyyyy"). A `signature` whose
|
|
260
|
+
`signing_requirement` is `"external"` is signed outside fenfill (on paper, or with an e-signature
|
|
261
|
+
service), so it is left blank.
|
|
262
|
+
|
|
263
|
+
Unknown field ids (with did-you-mean suggestions), invalid options, comb values that don't fit
|
|
264
|
+
and malformed dates are reported back, so the agent can correct itself. Required fields left empty are listed as
|
|
265
|
+
warnings.
|
|
266
|
+
|
|
267
|
+
### Branding
|
|
268
|
+
|
|
269
|
+
`fill_form` output is never branded. `fill_template` applies the same branding as a fill in the
|
|
270
|
+
fenfill web app for that workspace (for example, your logo if you have set one up).
|
|
271
|
+
|
|
272
|
+
## Configuration
|
|
273
|
+
|
|
274
|
+
| Variable | Default | Notes |
|
|
275
|
+
| ------------------------------ | ------------------------- | ---------------------------------------------------------------------------- |
|
|
276
|
+
| `FENFILL_API_KEY` | (none) | `ff_live_…` from fenfill → Settings → API keys. |
|
|
277
|
+
| `FENFILL_API_URL` | `https://api.fenfill.com` | https only (http allowed for localhost). |
|
|
278
|
+
| `FENFILL_CACHE_DIR` | the OS cache folder | Holds schemas and blank forms only, never answers. |
|
|
279
|
+
| `FENFILL_ANALYZE_WAIT_SECONDS` | `50` | How long `analyze_form` / `reanalyze_template` wait before saying "running". |
|
|
280
|
+
|
|
281
|
+
`fill_form` works without an API key once a form has been analyzed.
|
|
282
|
+
|
|
283
|
+
## Files and privacy
|
|
284
|
+
|
|
285
|
+
- **The cache** (`FENFILL_CACHE_DIR`, by default `~/Library/Caches/fenfill-mcp` on macOS,
|
|
286
|
+
`~/.cache/fenfill-mcp` on Linux, `%LOCALAPPDATA%\fenfill-mcp\Cache` on Windows; private to
|
|
287
|
+
your user) holds form schemas, blank template PDFs, the workspace logo, sha256 hashes of the
|
|
288
|
+
PDFs it produced and `edit_template`'s working copies, **never the answers you fill in**. A
|
|
289
|
+
working copy holds the layout plus the wording the agent wrote with `edit_template`; the echo
|
|
290
|
+
guard refuses wording that repeats an answer seen in the same session before it is written.
|
|
291
|
+
- **Cache cleanup:** at startup and at most once a day it deletes blank PDFs and the logo after
|
|
292
|
+
1 hour, analyses and working copies unused for 90 days, stale job records after 48 hours, and
|
|
293
|
+
output hashes after a year.
|
|
294
|
+
- **Filled PDFs** are written only where you ask, readable by your user only (mode 0600).
|
|
295
|
+
- **`overwrite: true`** replaces the target file with a new one: the old file's permissions and
|
|
296
|
+
ACL are not kept, and other hard links to it keep the old content.
|
|
297
|
+
- **Recipient links** from `create_recipient_link` are working access links to the form: treat
|
|
298
|
+
them as secrets and share them only with that recipient.
|
|
299
|
+
- **Logs** go to stderr and contain tool names, timings and error codes, never field values.
|
|
300
|
+
|
|
301
|
+
## Troubleshooting
|
|
302
|
+
|
|
303
|
+
| Error | What to do |
|
|
304
|
+
| ------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
305
|
+
| `missing_api_key` / `invalid_api_key` | Set `FENFILL_API_KEY` in the client's config and restart the client. |
|
|
306
|
+
| `plan_required` | The workspace needs a paid plan (Pro and up). |
|
|
307
|
+
| `insufficient_scans` | Not enough page scans left; analyze fewer `pages` or check `get_account`. |
|
|
308
|
+
| `prefilled_form` / `filled_output` | Only blank forms can be analyzed; use the original, empty PDF. If it is the blank form (some ship with default text in their fields), use the fenfill web app. |
|
|
309
|
+
| `pdf_password_required` | Remove the open password first; owner-password PDFs work as they are. |
|
|
310
|
+
| `pdf_fill_forbidden` | The PDF's author forbids form filling; fenfill won't fill it. Use a copy that allows filling. |
|
|
311
|
+
| `not_analyzed` | Run `analyze_form` on the same file (and pages) before `fill_form`. |
|
|
312
|
+
| `output_exists` | Pick a new `output_path` or pass `overwrite: true`. |
|
|
313
|
+
| `rate_limited` / `queue_full` | `analyze_form` already waited about a minute (`waited_s`); try again later. |
|
|
314
|
+
| `too_many_active_jobs` | Other analyses in the workspace (free native-field ones too) are still running; try again in a minute, or analyze fewer at once. |
|
|
315
|
+
| `template_conflict` | The template changed in fenfill since your edits began. Your local edits are kept: `edit_template` with `discard: true`, re-apply the ops, save again. |
|
|
316
|
+
| `invalid_schema` | fenfill (or the local check before it) refused the edited layout; `details` lists each item and reason. Fix them with `edit_template`. |
|
|
317
|
+
| `request_too_large` | The edited template is too large to save in one request. |
|
|
318
|
+
| `answer_in_template` | Edited wording matches an answer from this session, so nothing was sent. Put the form's own wording back with `edit_template`. |
|
|
319
|
+
| `confirm_wording_needed` | The working copy has wording edited in an earlier session. Review the ids and properties in `changed`, then `save_template` with `confirm_wording: true`. |
|
|
320
|
+
| `local_edits_pending` | `reanalyze_template` won't run over unsaved edits: `save_template` them first, or pass `discard: true`. |
|
|
321
|
+
| `kind_required` | The pages already have fields: pass `kind` (`find`, `relabel`, `label_missing`, or `scratch` to replace them). |
|
|
322
|
+
| `job_in_progress` | A job is already running on the template; wait and retry (call `reanalyze_template` again with the same arguments if you started it). |
|
|
323
|
+
| `upload_outcome_unknown` | An earlier upload was interrupted. To avoid charging twice, the same file isn't re-uploaded for about 10 minutes; check `get_account` meanwhile. |
|
|
324
|
+
|
|
325
|
+
## API
|
|
326
|
+
|
|
327
|
+
The server wraps fenfill's REST API: reference at
|
|
328
|
+
[api.fenfill.com/v1/docs](https://api.fenfill.com/v1/docs), OpenAPI spec at
|
|
329
|
+
[api.fenfill.com/v1/openapi.json](https://api.fenfill.com/v1/openapi.json). Fill values are never
|
|
330
|
+
sent to any endpoint; the API has no field for them.
|
|
331
|
+
|
|
332
|
+
## Verify this package
|
|
333
|
+
|
|
334
|
+
- Releases are built and published by GitHub Actions from
|
|
335
|
+
[github.com/fenfill/mcp](https://github.com/fenfill/mcp) with
|
|
336
|
+
[npm provenance](https://docs.npmjs.com/generating-provenance-statements): the npm page links
|
|
337
|
+
each version to the exact commit and workflow run that built it.
|
|
338
|
+
- `npm audit signatures` in a project that installs `@fenfill/mcp` checks the registry signature
|
|
339
|
+
and the provenance attestation.
|
|
340
|
+
- The bundle (`dist/index.js`) is not minified, so what runs on your machine can be read.
|
|
341
|
+
`dist/pdfium.wasm` is the unmodified PDFium build from `@embedpdf/pdfium` (see
|
|
342
|
+
`THIRD_PARTY_NOTICES`), loaded only by `preview_page`.
|
|
343
|
+
|
|
344
|
+
## Security
|
|
345
|
+
|
|
346
|
+
Report vulnerabilities to [security@fenfill.com](mailto:security@fenfill.com) (or through GitHub
|
|
347
|
+
private vulnerability reporting on the repository), not in public issues.
|
|
348
|
+
|
|
349
|
+
## License
|
|
350
|
+
|
|
351
|
+
MIT: see `LICENSE`. Bundled third-party software: see `THIRD_PARTY_NOTICES` and `licenses/`.
|