Docs menu

MCP server setup

Install @fenfill/mcp in Claude Code, Claude Desktop, Cursor or any client that launches a stdio server.

View this page as Markdown

Before you start

  • Node.js 22 or newer. npx comes with it.
  • A fenfill API key (ff_live_…): fenfill → Settings → API keys. The API is included on Pro, Team and Business: see pricing.

Add the server to your client

Run this in a terminal.

Terminal
claude mcp add fenfill --scope user -e FENFILL_API_KEY=ff_live_… -- npx -y @fenfill/mcp

Client notes

  • Claude Desktop reads claude_desktop_config.json from ~/Library/Application Support/Claude/ on macOS and %APPDATA%\Claude\ on Windows. Restart Claude Desktop after editing it.
  • Native Windows: if the client can't find npx, use "command": "cmd" with "args": ["/c", "npx", "-y", "@fenfill/mcp"].
  • The installed command is fenfill-mcp.

This page describes version 0.2.6. To update, restart your client. If it still runs an older version, use @fenfill/mcp@latest in the command. See the changelog for what changed.

Configuration

The server reads these environment variables, set in the client's config next to the command.

VariableDefaultWhat it does
FENFILL_API_KEY(none)Your workspace API key (ff_live_…), from fenfill → Settings → API keys. The tools that call fenfill need it; fill_form works without it once a form has been analyzed.
FENFILL_API_URLhttps://api.fenfill.comThe API origin. https only (http is allowed for localhost).
FENFILL_CACHE_DIRthe OS cache folderWhere the server keeps form schemas and blank forms. Never answers.
FENFILL_ANALYZE_WAIT_SECONDS50How many seconds analyze_form and reanalyze_template wait for a result before they answer "running". Calling again with the same arguments picks up the same run.

The local cache

The cache (FENFILL_CACHE_DIR) is private to your user. By default it is ~/Library/Caches/fenfill-mcp on macOS, ~/.cache/fenfill-mcp on Linux and %LOCALAPPDATA%\fenfill-mcp\Cache on Windows.

  • It holds form schemas, blank template PDFs, the workspace logo, sha256 hashes of the PDFs the server produced and edit_template's working copies, never the answers you fill in.
  • At startup, and at most once a day, it deletes blank PDFs and the logo after 1 hour, analyses and working copies unused for 90 days, stale job records after 48 hours, and output hashes after a year.
  • fonts/ holds the Japanese font (Noto Sans JP, about 5.8 MB), downloaded the first time a value needs it and never aged out.
  • Filled PDFs are written only where you ask, readable by your user only (mode 0600).
  • Logs go to stderr and contain tool names, timings and error codes, never field values.

To work offline with Japanese values, copy NotoSansJP-Regular.ttf (from https://fenfill.com/fonts/NotoSansJP-Regular.ttf) into <cache>/fonts/ (FENFILL_CACHE_DIR if you set it). It is used if its sha256 matches the pinned value.

Troubleshooting

Errors come back as a code with a message. The common ones:

ErrorWhat to do
missing_api_key / invalid_api_keySet FENFILL_API_KEY in the client's config and restart the client.
plan_requiredYour plan doesn't include API access: see pricing.
insufficient_scansNot enough page scans left. Analyze fewer pages, or check get_account.
prefilled_form / filled_outputOnly 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. When the refusal names annotations or XFA values that belong to the blank form, pass confirm_blank: true.
pdf_password_requiredRemove the open password first. PDFs with only an owner password work as they are.
pdf_fill_forbiddenThe PDF's author forbids form filling, so fenfill won't fill it. Use a copy that allows filling.
unsupported_scriptA value needs Japanese characters and the font could not be loaded. ids lists the fields and details.reason says why (network, http_status, hash_mismatch, timeout, too_large). Connect once and retry, or pre-seed the font (see the local cache).
not_analyzedRun analyze_form on the same file (and pages) before fill_form.
output_existsPick a new output_path, or pass overwrite: true.
edit_conflictAnother fenfill-mcp process changed the form's local edits during the call, so nothing was applied. Call edit_template again with the same ops.
rate_limited / queue_fullanalyze_form already waited about a minute (waited_s). Try again later.
too_many_active_jobsOther analyses in the workspace (native-field ones too) are still running. Try again in a minute, or analyze fewer at once.
template_conflictThe template changed in fenfill since your edits began. Your local edits are kept: call edit_template with discard: true, re-apply the ops and save again.
invalid_schemafenfill (or the local check before it) refused the edited layout. details lists each item and reason; fix them with edit_template.
check_copy_failedpreview_page could not build its outlined copy; stage and id say where. Fix or remove that field or group with edit_template, then preview again. overlay: "none" still shows the page meanwhile.
request_too_largeThe edited template is too large to save in one request.
answer_in_templateEdited wording matches an answer from this session, so nothing was sent; matched lists the ids and properties. If it is an answer, put the form's own wording back with edit_template. If it is the form's own wording, call save_template again with confirm_wording: true.
confirm_wording_neededThe working copy has wording edited in an earlier session. Review the ids and properties in changed, then call save_template with confirm_wording: true.
local_edits_pendingreanalyze_template won't run over unsaved edits: save them with save_template first, or pass discard: true.
kind_requiredThe pages already have fields: pass kind (find, relabel, label_missing, or scratch to replace them).
job_in_progressA job is already running on the template. Wait and retry (call reanalyze_template again with the same arguments if you started it).
upload_outcome_unknownAn earlier upload was interrupted. So you aren't charged twice, the same file isn't uploaded again for about 10 minutes; check get_account meanwhile.

Verify the package

  • Releases are built and published by GitHub Actions from github.com/fenfill/mcp with npm provenance: the npm page links each version to the exact commit and workflow run that built it.
  • The bundle (dist/index.js) is not minified, so what runs on your machine can be read. dist/pdfium.wasm is the unmodified PDFium build from @embedpdf/pdfium (see THIRD_PARTY_NOTICES), loaded only by preview_page.

In a project that installs @fenfill/mcp, this checks the registry signature and the provenance attestation:

Terminal
npm audit signatures

Report vulnerabilities to security@fenfill.com, or through GitHub private vulnerability reporting on the repository, not in public issues.