Skip to main content
Glama
formfeed-dev

formfeed

Official

Formfeed packages

Client libraries, command line tools and integrations for Formfeed, the API for generating PDFs and images from templates. Documentation lives at docs.formfeed.dev.

Package

Registry

What it is

@formfeed/sdk

npm

TypeScript client: renders, batches, templates, webhooks. No dependencies, Web APIs only

formfeed

PyPI

Python client, sync and async

formfeed

npm

CLI: templates as files, offline preview and validation, renders through the API

@formfeed/engine

npm

The template engine (Jinja2, Liquid, Handlebars) the API and the editor use

@formfeed/devkit

npm

Template folders, project config and local rendering

@formfeed/testing

npm

Vitest and Jest matchers for templates

@formfeed/mcp

npm

Model Context Protocol server for AI agents formfeed MCP server – quality and maintenance score on Glama

n8n-nodes-formfeed

npm

n8n community node

Every npm package is built and published from this repository by GitHub Actions with provenance, and the Python package with trusted publishing, so each release can be traced to the commit and workflow run it came from.

Development

Node 22 or newer and pnpm (the version in package.json, corepack enable picks it up):

pnpm install
pnpm nx run-many -t lint test --exclude sdk-python   # TypeScript packages
pnpm nx run-many -t bundle smoke                     # build, pack and try every npm package
cd packages/sdk-python && pip install pytest httpx pydantic && python -m pytest -q

This repository is generated from Formfeed's main repository, where the packages are developed together with the API they talk to. See CONTRIBUTING.md for how issues and pull requests are handled.

Related MCP server: docjet-mcp

Licence

MIT, see LICENSE. Bundled third-party code keeps its own licence; the CLI and MCP packages list it in THIRD_PARTY_LICENSES.md.

Available Tools

10 tools
check_invoiceCheck an e-invoiceA
Read-only

Checks the _invoice block of an e-invoice offline, as the API does before it renders one: the fields EN 16931 asks for, the totals to the cent, VAT categories and code lists, and France's rules for an invoice between two French businesses. Free, no units, nothing sent. Returns ok and problems, each with the field, the rule (BR-…) where one applies and a message. Nothing is computed for you: change the values a problem names, check again, then call render with einvoice and the block as data._invoice. The validator that runs during the render holds the file to the full rule set and to PDF/A-3b as well.

NameRequiredDescriptionDefault
invoiceYesThe _invoice block as it goes into data._invoice: number, issue_date, currency, seller, buyer, lines, tax.breakdown, totals and payment, as https://docs.formfeed.dev/templates/e-invoices#invoice-block describes
profileNoThe profile the render will ask for; en16931 when left out. basic cannot carry a rounding amount and is refused between two French businesses

Output Schema

NameRequiredDescription
okYes
problemsYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well past readOnlyHint/destructiveHint by disclosing cost ('free, no units'), that nothing is transmitted ('nothing sent'), that nothing is auto-fixed ('nothing is computed for you'), the return shape (ok plus problems carrying field, BR-… rule and message), and the stricter validation that awaits at render. These are exactly the traits an agent needs to plan a retry loop.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads what it validates, then the cost/offline guarantees, then the problem-then-render workflow, then the caveat about the render validator. Dense but every clause carries information an agent would otherwise have to infer.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a two-parameter validator with an output schema, the description covers purpose, cost, iteration loop, and the boundary against render-time validation. Nothing an agent needs in order to call it correctly and interpret the result is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the param details (block contents, profile enum, en16931 default, basic restrictions) are already carried by the schema. The description adds the tie that matters: the same block is what gets passed to render as data._invoice, which clarifies identity and reuse rather than restating the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource (checks the _invoice block) plus the scope: offline, mirroring the API's pre-render validation, covering EN 16931 fields, totals, VAT categories, code lists and French domestic rules. It is clearly separable from the render sibling, which it names and contrasts with the stricter full rule set plus PDF/A-3b.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicitly positions the tool before render in a workflow: validate, change the values a problem names, check again, then call render with einvoice. It also names the condition that distinguishes its checks from the render-time validator, so the agent knows when this suffices and when it does not.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

convert_to_pdfConvert an office document to PDFA

Converts an existing Word, Excel, PowerPoint, OpenDocument, RTF or HTML document (up to 20 MB) to a PDF as it is, without filling in data, and returns the render with status and download_url. To make a document from a template and data, use render instead. Pass exactly one source: render_id, the render of a Word or PowerPoint template (output docx or pptx); path, a file on this machine; or file_base64 with file_name. Every call is a new render that counts units like a PDF; the Free plan cannot convert (Starter and above). The document is converted and not kept.

NameRequiredDescriptionDefault
pathNoAbsolute path of the document on this machine
filenameNoName of the PDF behind download_url, e.g. report.pdf
file_nameNoName of the document, e.g. report.xlsx; the type is read from the content
landscapeNoLandscape for spreadsheets and documents without their own page setup
render_idNornd_ id of a render whose output is docx or pptx, to get that document as a PDF
file_base64NoThe document to convert, base64 encoded; needs file_name
page_rangesNoPages to convert, e.g. 1-3,5; all pages when left out
single_page_sheetsNoEach spreadsheet sheet on one page

Output Schema

NameRequiredDescription
idYesrnd_ id of the render
pdfaNoThe PDF/A verdict (PDF/A-2b or PDF/A-3b), when the template declares it
errorYesWhy a failed render failed
unitsYesUnits the render counted
statusYes
einvoiceNoThe e-invoice report, when the render made one
templateYesThe template and version rendered; null for html and conversions
expires_atYesWhen download_url stops working; get_render issues a fresh one
page_countYes
environmentYes
download_urlYesSigned link to the file; null until the render succeeded
accessibilityNoThe PDF/UA-1 verdict, when the template declares it

TDQS

A4.6/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond annotations: discloses unit consumption ('Every call is a new render that counts units like a PDF'), plan gating, the fact that the source is not retained, the 20 MB cap, and that the response carries status/download_url. Annotations only say readOnly=false, idempotent=false, destructive=false; the description adds the material cost and retention behavior. Minor gap: no mention of failure/error behavior or how long download_url stays valid.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loads what it does, then the alternative, then the input rule, then the cost/limits. Dense and nearly every clause carries information, though the second and third sentences are long run-ons that could be split for scanning.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For an 8-parameter, zero-required conversion tool, the description covers inputs, exclusivity rule, size limit, plan eligibility, cost model, retention, and the sibling alternative; return values are covered by the existing output schema. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so baseline is 3, but the description adds meaning the schema lacks: the exactly-one-source constraint (required list is empty and there is no oneOf), and clarification that render_id must be a docx/pptx render. It does not explain landscape, page_ranges, single_page_sheets or filename beyond the schema, but those are already well documented.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb (converts) and enumerates the exact resource types accepted (Word, Excel, PowerPoint, OpenDocument, RTF, HTML) plus size limit, and explicitly contrasts with the sibling 'render' for the template+data case. An agent can distinguish this from render without opening any schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Names the alternative tool and the condition that selects it ('To make a document from a template and data, use render instead'), and gives an explicit rule for mutually exclusive inputs ('Pass exactly one source') with the three valid variants. It also flags a hard eligibility constraint (Free plan cannot convert).

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_renderGet a renderA
Read-only

Returns the current state of a render: status (queued, rendering, succeeded or failed), download_url with expires_at, page_count, units and error, and the picture of a finished image render up to 2 MB. Use it to follow a render started with wait false, or to get a fresh link once the old one has expired; render and convert_to_pdf already return this for the render they just made. Read-only and free; an unknown id returns an error.

NameRequiredDescriptionDefault
idYesrnd_ id of the render, as render or convert_to_pdf returned it

Output Schema

NameRequiredDescription
idYesrnd_ id of the render
pdfaNoThe PDF/A verdict (PDF/A-2b or PDF/A-3b), when the template declares it
errorYesWhy a failed render failed
unitsYesUnits the render counted
statusYes
einvoiceNoThe e-invoice report, when the render made one
templateYesThe template and version rendered; null for html and conversions
expires_atYesWhen download_url stops working; get_render issues a fresh one
page_countYes
environmentYes
download_urlYesSigned link to the file; null until the render succeeded
accessibilityNoThe PDF/UA-1 verdict, when the template declares it

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Goes well beyond the readOnly/openWorld annotations: it discloses cost ('free'), the failure mode for an unknown id ('returns an error'), the 2 MB cap on image payloads, and the fact that download_url is time-limited via expires_at. That is exactly the operational context an agent needs before polling.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Two dense sentences with no waste: what comes back first, then when to call it, then the cost/error caveats. Every clause (2 MB cap, expires_at, wait false) maps to a real agent decision.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, yet the description still flags the practically important pieces — the status enum and the expiring link — and adds polling guidance and error behavior. For a one-parameter read tool, an agent has everything needed to call it correctly on the first try.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the single id parameter is fully documented in the schema, including the rnd_ prefix convention, so the description adds little. The 'unknown id returns an error' clause is the only extra semantic value. Baseline 3 applies when the schema carries the parameter burden.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ('Returns the current state of a render') and enumerates the concrete fields returned (status values, download_url/expires_at, page_count, units, error, image preview cap). It also explicitly distinguishes itself from the siblings render and convert_to_pdf, which already return this payload for their own renders.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives two explicit when-to-use triggers ('follow a render started with wait false' and 'get a fresh link once the old one has expired') and an explicit when-not-to-use case ('render and convert_to_pdf already return this'). Nothing about tool selection is left to inference.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_template_schemaGet the data schema of a templateA
Read-only

Returns the JSON Schema of the data object a template expects and the sample data it was designed with, from its published version, else its latest draft. Call it after list_templates and before render or validate_template, to build data that fits; ad-hoc html has no stored schema to read. When the template stores no schema, one is inferred from the sample data: treat that as a guide, not a contract. Read-only and free; an unknown slug returns an error.

NameRequiredDescriptionDefault
templateYesSlug (e.g. invoice) or tpl_ id, as list_templates returns them

Output Schema

NameRequiredDescription
schemaYesJSON Schema of data; inferred from sample_data when none is stored
statusYespublished, or draft when nothing is published yet
versionYesThe version the schema comes from
templateYes
sample_dataYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnly annotations it discloses the published-vs-draft fallback, that an inferred schema from sample data is a guide rather than a contract, that the call is free, and that an unknown slug errors. These are behaviors an agent cannot get from the structured fields.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Three tight sentences: what is returned, when to call it, and the edge-case caveat. The return value is front-loaded and no sentence is filler.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return shapes need not be spelled out, and the description covers the remaining ambiguities: version resolution, inference fallback quality, and error behavior. Nothing needed to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the sole `template` parameter already documents slug-or-tpl_ id format. The description adds no parameter-level detail beyond naming the slug context implicitly, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource: returns the JSON Schema of a template's `data` object plus its sample data. It also pins the resolution rule (published version, else latest draft), which no sibling tool does.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit sequencing ('after list_templates and before render or validate_template') and a clear exclusion ('ad-hoc html has no stored schema to read'). The failure case for an unknown slug is also named.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_template_sourceRead the source of a templateA
Read-only

Returns what a template version is made of: the body markup (html), css, head, settings (paper, margins, header, footer, fonts), sample data, data sets, data schema, translations and partials, with the version's checksum. Call it before save_template to change a template the user named, and save what you edited with that checksum as base_checksum. Reads the latest version by default, the newest draft a change builds on; published reads what renders use. Word and PowerPoint templates are documents: for them it returns the settings and data, not the document. Read-only and free.

NameRequiredDescriptionDefault
versionNolatest (default), published, a version number or a channel name
templateYesSlug (e.g. invoice) or tpl_ id, as list_templates returns them

Output Schema

NameRequiredDescription
cssYes
headYes
htmlYes
i18nYes
versionYes
partialsYes
settingsYes
templateYes
data_setsYes
data_schemaYes
sample_dataYes

TDQS

A4.7/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the readOnlyHint, destructiveHint, and openWorldHint annotations, it discloses important behavior: the full set of returned components, checksum usage for subsequent saves, version resolution semantics, and the Word/PowerPoint limitation. It also notes that the operation is read-only and free.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but well-structured and front-loaded with what is returned. Every sentence contributes operational information: return contents, save workflow, version semantics, and the document-format caveat.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the presence of an output schema, full schema description coverage, and clear read-only annotations, the description is complete enough for an agent to invoke the tool correctly. It covers return scope, version behavior, downstream save workflow, and an important edge case for Word and PowerPoint templates.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The schema fully documents both parameters, so the baseline is 3, but the description adds meaningful semantics for the version parameter: what latest means, what published means, and how draft/build versions are selected. It does not further explain the template slug or tpl_ id beyond the schema, but the added version behavior is valuable.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific resource and verb: it returns the source composition of a template version, enumerating body markup, css, head, settings, data, translations, partials, and checksum. This is specific enough to distinguish it from siblings like get_template_schema and list_templates.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives clear workflow guidance: call before save_template when editing a user-named template and pass the returned checksum as base_checksum. It also explains version selection behavior for latest, published, version numbers, and channels, though it does not explicitly name alternative read tools such as get_template_schema.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

get_workspaceWhich workspace this server works inA
Read-only

Returns the workspace and organisation this server acts in, the plan, the environment (live or test) and the units of the current period: included, used and the balance of prepaid units. Call it when the user asks where a document will land or how many renders are left, or when list_templates returns nothing you expected. A signed-in agent works in the workspace chosen when it was connected, which the person changes in Formfeed under Account → Connected agents; an API key works in the workspace it was made for. Read-only and free.

NameRequiredDescriptionDefault

No parameters

Output Schema

NameRequiredDescription
planYes
unitsYes
periodYesThe current billing period
workspaceYes
environmentNolive renders count units; test renders are free
organizationYes

TDQS

A4.4/5.0
Behavior4/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint and destructiveHint=false, so 'Read-only and free' is partly redundant, but 'free' is new. The genuinely additive content is the scoping model: a signed-in agent sees the workspace chosen at connect time (changeable under Account → Connected agents) while an API key is pinned to the workspace it was created for. That explains why the answer might differ from user expectation, which annotations never convey.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The payload is front-loaded in the first sentence (what is returned), then triggers, then the scoping caveat. Four sentences with little waste, though 'Read-only and free' partly restates the annotations and could be trimmed.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

An output schema exists, so return values need no elaboration, yet the description still summarizes the fields an agent would reason about. With zero parameters and full annotation coverage, nothing an agent needs in order to call this correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

The tool takes no parameters, so the baseline of 4 applies. The description correctly offers no parameter guidance and instead spends its words on what the fixed result contains.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description names a concrete resource and enumerates exactly what comes back: workspace, organisation, plan, environment, and unit totals (included, used, prepaid balance). That is specific enough that an agent can distinguish it from every sibling in the list, none of which report account or workspace state.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives concrete triggers ('where a document will land', 'how many renders are left') and a diagnostic case tied to a named sibling: when list_templates returns unexpected results. It stops short of stating when not to call it or naming alternatives for the diagnostic case, so it is clear context without exclusions.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

list_templatesList templatesA
Read-only

Lists the templates of the workspace this server works in (the one chosen at sign-in, or the API key's), most recently changed first: id, slug, name, kind (pdf, image, docx for Word, pptx for PowerPoint), engine, tags and published_version. Call it first to find the slug that get_template_schema, validate_template and render take; skip it when the user already named the template. Returns every match in one answer, without archived templates, and an empty list when nothing matches. A template whose published_version is null has never been published, so render cannot use it yet. Read-only and free.

NameRequiredDescriptionDefault
qNoText to find in the name or slug, case-insensitive (e.g. invoice)
tagNoOnly templates with this tag; exact match, tags are lowercase with dashes (e.g. billing)
kindNoOnly templates that produce this kind of document
engineNoOnly templates written in this template language

Output Schema

NameRequiredDescription
templatesYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already declare readOnlyHint/destructiveHint, but the description adds real behavioral facts: results are most-recently-changed first, archived templates are excluded, all matches come back in one answer (no pagination), an empty list signals no match, and a null published_version means render cannot use it. It also notes the call is free, which matters for an agent deciding whether to probe.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with purpose and scope, and every clause carries information an agent would otherwise have to guess. The single dense block runs long and chains several ideas, but there is no filler sentence to cut.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

With an output schema present the description needn't enumerate return values, yet it still calls out ordering, archived exclusion, and the published_version null edge case that gates render. Combined with 100% schema coverage and clear annotations, an agent has everything needed to call this correctly or decide not to.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is 100%, so q, tag, kind and engine are already fully documented, including case-insensitivity, exact-match tag format, and the kind/engine enums. The description's brief gloss of kind values repeats the enum rather than adding filtering semantics, so the baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Specific verb (Lists) plus resource (templates) plus scope (the workspace this server works in, chosen at sign-in or the API key's), ordering rule, and the returned field set. It also names the siblings that consume the slug (get_template_schema, validate_template, render), so an agent can place it precisely in the workflow.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Explicit when: "Call it first to find the slug that get_template_schema, validate_template and render take." Explicit when-not: "skip it when the user already named the template." Both the trigger and the exclusion are stated, not implied.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

renderRender a documentA

Creates a document by filling a stored template, or ad-hoc html, with data: a PDF or image, or DOCX, PPTX or PDF from Word and PowerPoint templates. Returns the render with status and download_url; for an image (png, jpg or webp) up to 2 MB the result also carries the picture itself, so look at what you made before handing it on (a PDF comes as its link). Use it to make a document from data; to turn an existing office file into a PDF, use convert_to_pdf. Stored templates render their published version, so one whose published_version is null fails with template_not_found. Every call is a new render: a live key or a signed-in agent consumes units, a test key is free (watermarked on the Free plan). A render that fails returns status failed and an error with code and message; validate_template finds most causes beforehand. With einvoice the PDF becomes a ZUGFeRD / Factur-X e-invoice built from data._invoice (check the block with check_invoice first): the render then carries einvoice, the validator's report, and a refused invoice names the fields and rules to fix. The link expires at expires_at; get_render issues a fresh one.

NameRequiredDescriptionDefault
dataNoValues for the template, shaped as get_template_schema describes; leave out when it needs none
htmlNoA complete HTML document to render instead of a stored template, up to 5 MB
waitNoMost renders are finished when the call returns; true also waits for one that continues in the background, false returns it as it is (queued or rendering) to check later with get_render
engineNoTemplate language of html, when it contains expressions to fill from data
localeNoBCP 47 tag for helpers and translations, e.g. de-DE
outputNoLeft out, the template decides: PDF for PDF templates and html, its image format for image templates, its default output for Word and PowerPoint templates. Word templates render docx or pdf, PowerPoint templates pptx or pdf
einvoiceNoMakes the PDF a ZUGFeRD / Factur-X e-invoice whose XML is built from data._invoice: true for the defaults, an object to choose, false to switch off what the template declares. PDF only; live renders from the Starter plan, test keys on Free make 20 marked ones a day
filenameNoName of the file behind download_url, e.g. invoice-2026-0042.pdf
templateNoSlug or tpl_ id of a stored template; pass this or html

Output Schema

NameRequiredDescription
idYesrnd_ id of the render
pdfaNoThe PDF/A verdict (PDF/A-2b or PDF/A-3b), when the template declares it
errorYesWhy a failed render failed
unitsYesUnits the render counted
statusYes
einvoiceNoThe e-invoice report, when the render made one
templateYesThe template and version rendered; null for html and conversions
expires_atYesWhen download_url stops working; get_render issues a fresh one
page_countYes
environmentYes
download_urlYesSigned link to the file; null until the render succeeded
accessibilityNoThe PDF/UA-1 verdict, when the template declares it

TDQS

A4.2/5.0
Behavior3/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Annotations already cover the safety profile (readOnly=false, destructive=false), and the description adds real behavioral context: every call is a new render consuming units, test keys are free but watermarked, templates render their published version and fail with template_not_found when null. Failures return status failed with a code/message, and links expire at expires_at. Good additions, but the einvoice and return-shape details are partly duplicated by the output schema, so it sits at a solid 3.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Front-loaded with the core action, then progressively less common concerns (units, einvoice, expiry). It is long, and the einvoice sentence packs several ideas together, but nearly every sentence carries operational information and could not be cut without loss.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

For a 9-parameter, nested-object, mutation tool with an output schema, the description covers source choice, output defaults, failure mode, cost, expiry and the einvoice branch. Nothing an agent needs to call it correctly is missing.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters3/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100% and the schema already documents each parameter with enums and nested einvoice fields. The description adds a few non-obvious constraints — data shaped per get_template_schema, data._invoice for einvoice, published-version template selection — but most of its parameter talk restates the schema. Baseline 3 applies.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

Opens with a concrete verb+resource+output matrix: filling a stored template or ad-hoc html with data, yielding PDF/image/DOCX/PPTX. It explicitly names the sibling it is not (convert_to_pdf) in the same breath, so an agent can route without opening either schema.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

States the positive case ("Use it to make a document from data") and the exclusion with an alternative ("to turn an existing office file into a PDF, use convert_to_pdf"). It also points to validate_template and check_invoice as preflight steps, giving concrete ordering guidance rather than vague hints.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

save_templateSave a template as a draftA

Saves a template as a draft, never published: renders keep using the published version until a person publishes the draft in Formfeed. With template and base_checksum it saves a new version of that template: read it with get_template_source first, change what the user asked for, and pass only the parts you changed (the others are kept from the version you read). With new_template and html it creates a template whose version 1 is the draft. change_note says what changed; the person reads it before publishing. Returns the saved version, the check of the draft with its sample data (fix every error and save again) and review_url, the page where the person reviews and publishes it: hand that to the user. Needs an API key with template:write, or, for a signed-in agent, the person's permission under Account → Connected agents in Formfeed. Word and PowerPoint templates cannot be saved here. Free; a new template counts towards the plan's template limit.

NameRequiredDescriptionDefault
cssNoThe stylesheet; up to 1 MB
headNoExtra markup for <head>, such as font links
htmlNoThe body markup in the template language, without <html>, <head> or <body>; up to 2 MB
i18nNoTranslations: locale → key → text, read by the t helper
partialsNoPartials the template includes (name → source)
settingsNoPaper, margins, header, footer, fonts and the other settings, as get_template_source returns them; replaces the stored settings as a whole
templateNoSlug or tpl_ id of the template to save a new draft of; pass this or new_template
data_setsNoNamed sample data sets besides sample_data (name → data)
change_noteYesWhat the draft changes, in one sentence, shown in the version history
data_schemaNoJSON Schema of data; null removes the stored one
sample_dataNoThe data the editor previews with and the draft is checked with; never used by a render
new_templateNoCreates a template whose version 1 is this draft; pass this and html, or template
base_checksumNoWith template: the checksum get_template_source returned. When someone saved a newer version since, nothing is saved: read the source again and redo the change on it

Output Schema

NameRequiredDescription
okYesfalse when the check of the draft found an error; null when the check could not run
nextYes
versionYes
templateYes
review_urlNoThe page in Formfeed where the person reviews and publishes the draft
diagnosticsYes

TDQS

A4.9/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Beyond the annotations, it discloses the key behavioral trait that the save is draft-only and does not affect renders until a person publishes. It also covers authorization requirements, the return contents including review_url, the validation loop with sample data, base_checksum conflict behavior, and plan-limit implications.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness5/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is dense but appropriately sized for a 13-parameter mutation tool with nested objects. The most important fact, that this saves a draft and never publishes, is front-loaded, and each subsequent sentence adds operational guidance rather than repeating schema details.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

It covers the essential context an agent needs: draft semantics, the two invocation modes, prerequisite read via get_template_source, authorization, unsupported template types, validation expectations, and the review workflow. Although an output schema exists, the description's mention of review_url and validation errors is still useful for agent behavior.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is already 100%, so the schema carries most parameter documentation. The description still adds meaningful semantics beyond the schema for the central parameters: partial updates keep unchanged parts from the read version, base_checksum detects newer versions, and change_note is read by the person before publishing.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource ('Saves a template as a draft') and immediately distinguishes it from publishing or rendering by noting that renders keep using the published version. It also clearly separates the two save modes: updating an existing template versus creating a new one.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit workflow guidance: read with get_template_source first, change only what the user asked for, and pass template plus base_checksum for an existing template, or new_template plus html for a new one. It also names a limitation (Word and PowerPoint templates cannot be saved here), which helps the agent avoid misuse.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

validate_templateValidate a template with dataA
Read-only

Checks a template and its data without rendering: free, no units, nothing stored, no document produced. Call it before render when you assembled the data yourself, or after writing ad-hoc html. With template, the API checks the published version (else the latest, or the version you name) as a render would: syntax, header and footer, errors only this data triggers, and the data against the stored JSON Schema (a wrong type or a missing required field is an error). With html and engine it compiles offline and reports syntax errors, unknown filters and variables missing from data. Returns ok and diagnostics (severity, code, message, plus path, line and column, or part and paragraph for Word and PowerPoint). Warnings leave ok true: settle each before rendering.

NameRequiredDescriptionDefault
dataNoThe data the document will be rendered with, shaped as get_template_schema describes. Left out, a stored template is checked with its sample data
htmlNoTemplate source to check offline, when there is no stored template; pass this or template
engineNoTemplate language of html; required with html
versionNoWith template: the version to check, such as latest for the newest draft or a number; left out, the published one, else the latest
templateNoSlug or tpl_ id of a stored template; pass this or html

Output Schema

NameRequiredDescription
okYesfalse when a diagnostic is an error
templateNoThe stored version checked; absent for html
diagnosticsYes

TDQS

A4.6/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

Adds substantial context beyond the readOnly/non-destructive annotations: the call is free, consumes no units, stores nothing, and produces no document. It also discloses result semantics — `ok` plus `diagnostics` with severity, code, message, path/line/column, or part/paragraph for Word and PowerPoint — and clarifies that warnings leave `ok` true but should be settled before rendering.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

Dense but front-loaded: cost and side-effect guarantees come first, then when to call, then per-mode behavior, then return semantics. A few clauses restate schema-documented defaults (version fallback, data omission), but the length is justified by the tool's two-mode complexity.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Covers everything an agent needs for a 5-parameter, mode-switching validation tool: cost, side effects, mode selection, what each mode checks, and how to interpret warnings versus errors. An output schema exists, yet the description still summarizes the return contract helpfully rather than leaving a gap.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema coverage is 100%, so the baseline is 3, but the description adds cross-parameter behavior the schema does not convey: the `template` path validates against the published version falling back to latest or a named version, whereas `html` + `engine` compiles offline and reports unknown filters and variables missing from `data`. It also explains what the data is checked against (the stored JSON Schema, with wrong types or missing required fields as errors).

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

States a specific verb and resource ("Checks a template and its data without rendering") and immediately distinguishes itself from `render` by declaring no units are consumed and no document is produced. It further splits the tool's two operating modes (stored template vs. ad-hoc html) so an agent can tell exactly which capability it is invoking.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines4/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

Gives explicit triggering conditions: call it "before render when you assembled the data yourself, or after writing ad-hoc html," which effectively routes the agent away from `render` when validation is the goal. It does not state any when-not conditions (e.g., cases where validation is redundant), so it falls just short of a 5.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

  1. 3 tool updatesv0.3.22
    • Changedconvert_to_pdf1 field changed
      • addedOutput schema / properties / pdfa
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "The PDF/A verdict (PDF/A-2b or PDF/A-3b), when the template declares it",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
    • Changedget_render1 field changed
      • addedOutput schema / properties / pdfa
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "The PDF/A verdict (PDF/A-2b or PDF/A-3b), when the template declares it",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
    • Changedrender1 field changed
      • addedOutput schema / properties / pdfa
        Added value: +{
        +  "additionalProperties": {},
        +  "description": "The PDF/A verdict (PDF/A-2b or PDF/A-3b), when the template declares it",
        +  "propertyNames": {
        +    "type": "string"
        +  },
        +  "type": "object"
        +}
  2. 3 tool updatesv0.3.21
    • Addedget_template_source
    • Addedsave_template
    • Changedvalidate_template1 field changed
      • addedInput schema / properties / version
        Added value: +{
        +  "anyOf": [
        +    {
        +      "maxLength": 32,
        +      "minLength": 1,
        +      "type": "string"
        +    },
        +    {
        +      "exclusiveMinimum": 0,
        +      "maximum": 9007199254740991,
        +      "type": "integer"
        +    }
        +  ],
        +  "description": "With template: the version to check, such as latest for the newest draft or a number; left out, the published one, else the latest"
        +}
  3. 8 tool updatesv0.3.19
    • Changedcheck_invoice1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "ok": {
        +      "type": "boolean"
        +    },
        +    "problems": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "message": {
        +            "type": "string"
        +          },
        +          "path": {
        +            "description": "The field, e.g. _invoice.seller.vat_id",
        +            "type": "string"
        +          },
        +          "rule": {
        +            "description": "The EN 16931 rule, e.g. BR-03",
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "path",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "ok",
        +    "problems"
        +  ],
        +  "type": "object"
        +}
    • Changedconvert_to_pdf1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "accessibility": {
        +      "additionalProperties": {},
        +      "description": "The PDF/UA-1 verdict, when the template declares it",
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "download_url": {
        +      "description": "Signed link to the file; null until the render succeeded",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "einvoice": {
        +      "additionalProperties": {},
        +      "description": "The e-invoice report, when the render made one",
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "environment": {
        +      "enum": [
        +        "live",
        +        "test"
        +      ],
        +      "type": "string"
        +    },
        +    "error": {
        +      "anyOf": [
        +        {
        +          "additionalProperties": false,
        +          "properties": {
        +            "code": {
        +              "type": "string"
        +            },
        +            "message": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "Why a failed render failed"
        +    },
        +    "expires_at": {
        +      "description": "When download_url stops working; get_render issues a fresh one",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "id": {
        +      "description": "rnd_ id of the render",
        +      "type": "string"
        +    },
        +    "page_count": {
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "status": {
        +      "enum": [
        +        "queued",
        +        "rendering",
        +        "succeeded",
        +        "failed"
        +      ],
        +      "type": "string"
        +    },
        +    "template": {
        +      "anyOf": [
        +        {
        +          "additionalProperties": false,
        +          "properties": {
        +            "canary": {
        +              "type": "boolean"
        +            },
        +            "channel": {
        +              "type": [
        +                "string",
        +                "null"
        +              ]
        +            },
        +            "id": {
        +              "type": "string"
        +            },
        +            "slug": {
        +              "type": "string"
        +            },
        +            "version": {
        +              "type": "number"
        +            }
        +          },
        +          "required": [
        +            "id",
        +            "slug",
        +            "version"
        +          ],
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "The template and version rendered; null for html and conversions"
        +    },
        +    "units": {
        +      "description": "Units the render counted",
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "id",
        +    "status",
        +    "download_url",
        +    "expires_at",
        +    "page_count",
        +    "units",
        +    "environment",
        +    "template",
        +    "error"
        +  ],
        +  "type": "object"
        +}
    • Changedget_render1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "accessibility": {
        +      "additionalProperties": {},
        +      "description": "The PDF/UA-1 verdict, when the template declares it",
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "download_url": {
        +      "description": "Signed link to the file; null until the render succeeded",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "einvoice": {
        +      "additionalProperties": {},
        +      "description": "The e-invoice report, when the render made one",
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "environment": {
        +      "enum": [
        +        "live",
        +        "test"
        +      ],
        +      "type": "string"
        +    },
        +    "error": {
        +      "anyOf": [
        +        {
        +          "additionalProperties": false,
        +          "properties": {
        +            "code": {
        +              "type": "string"
        +            },
        +            "message": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "Why a failed render failed"
        +    },
        +    "expires_at": {
        +      "description": "When download_url stops working; get_render issues a fresh one",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "id": {
        +      "description": "rnd_ id of the render",
        +      "type": "string"
        +    },
        +    "page_count": {
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "status": {
        +      "enum": [
        +        "queued",
        +        "rendering",
        +        "succeeded",
        +        "failed"
        +      ],
        +      "type": "string"
        +    },
        +    "template": {
        +      "anyOf": [
        +        {
        +          "additionalProperties": false,
        +          "properties": {
        +            "canary": {
        +              "type": "boolean"
        +            },
        +            "channel": {
        +              "type": [
        +                "string",
        +                "null"
        +              ]
        +            },
        +            "id": {
        +              "type": "string"
        +            },
        +            "slug": {
        +              "type": "string"
        +            },
        +            "version": {
        +              "type": "number"
        +            }
        +          },
        +          "required": [
        +            "id",
        +            "slug",
        +            "version"
        +          ],
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "The template and version rendered; null for html and conversions"
        +    },
        +    "units": {
        +      "description": "Units the render counted",
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "id",
        +    "status",
        +    "download_url",
        +    "expires_at",
        +    "page_count",
        +    "units",
        +    "environment",
        +    "template",
        +    "error"
        +  ],
        +  "type": "object"
        +}
    • Changedget_template_schema1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "sample_data": {
        +      "additionalProperties": {},
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "schema": {
        +      "additionalProperties": {},
        +      "description": "JSON Schema of data; inferred from sample_data when none is stored",
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "status": {
        +      "description": "published, or draft when nothing is published yet",
        +      "type": "string"
        +    },
        +    "template": {
        +      "type": "string"
        +    },
        +    "version": {
        +      "description": "The version the schema comes from",
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "template",
        +    "version",
        +    "status",
        +    "schema",
        +    "sample_data"
        +  ],
        +  "type": "object"
        +}
    • Changedget_workspace1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "environment": {
        +      "description": "live renders count units; test renders are free",
        +      "enum": [
        +        "live",
        +        "test"
        +      ],
        +      "type": "string"
        +    },
        +    "organization": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "id": {
        +          "type": "string"
        +        },
        +        "name": {
        +          "type": "string"
        +        },
        +        "slug": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "id",
        +        "slug",
        +        "name"
        +      ],
        +      "type": "object"
        +    },
        +    "period": {
        +      "additionalProperties": false,
        +      "description": "The current billing period",
        +      "properties": {
        +        "end": {
        +          "type": "string"
        +        },
        +        "start": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "start",
        +        "end"
        +      ],
        +      "type": "object"
        +    },
        +    "plan": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "id": {
        +          "type": "string"
        +        },
        +        "monthly_units": {
        +          "description": "Units included a month; null where the plan sets none",
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        },
        +        "name": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "id",
        +        "name"
        +      ],
        +      "type": "object"
        +    },
        +    "units": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "included": {
        +          "type": [
        +            "number",
        +            "null"
        +          ]
        +        },
        +        "overage_balance": {
        +          "description": "Prepaid units left beyond the included ones",
        +          "type": "number"
        +        },
        +        "used": {
        +          "type": "number"
        +        }
        +      },
        +      "required": [
        +        "used"
        +      ],
        +      "type": "object"
        +    },
        +    "workspace": {
        +      "additionalProperties": false,
        +      "properties": {
        +        "id": {
        +          "type": "string"
        +        },
        +        "name": {
        +          "type": "string"
        +        },
        +        "region": {
        +          "description": "eu, us or apac",
        +          "type": "string"
        +        },
        +        "slug": {
        +          "type": "string"
        +        }
        +      },
        +      "required": [
        +        "id",
        +        "slug",
        +        "name",
        +        "region"
        +      ],
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "workspace",
        +    "organization",
        +    "plan",
        +    "period",
        +    "units"
        +  ],
        +  "type": "object"
        +}
    • Changedlist_templates1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "templates": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "description": {
        +            "type": [
        +              "string",
        +              "null"
        +            ]
        +          },
        +          "engine": {
        +            "description": "jinja2, liquid or handlebars",
        +            "type": "string"
        +          },
        +          "id": {
        +            "description": "tpl_ id",
        +            "type": "string"
        +          },
        +          "kind": {
        +            "description": "pdf, image, docx (Word) or pptx (PowerPoint)",
        +            "type": "string"
        +          },
        +          "name": {
        +            "type": "string"
        +          },
        +          "published_version": {
        +            "description": "null: never published, so render cannot use it yet",
        +            "type": [
        +              "number",
        +              "null"
        +            ]
        +          },
        +          "slug": {
        +            "type": "string"
        +          },
        +          "tags": {
        +            "items": {
        +              "type": "string"
        +            },
        +            "type": "array"
        +          },
        +          "updated_at": {
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "id",
        +          "slug",
        +          "name",
        +          "kind",
        +          "engine",
        +          "description",
        +          "tags",
        +          "published_version",
        +          "updated_at"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    }
        +  },
        +  "required": [
        +    "templates"
        +  ],
        +  "type": "object"
        +}
    • Changedrender1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "accessibility": {
        +      "additionalProperties": {},
        +      "description": "The PDF/UA-1 verdict, when the template declares it",
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "download_url": {
        +      "description": "Signed link to the file; null until the render succeeded",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "einvoice": {
        +      "additionalProperties": {},
        +      "description": "The e-invoice report, when the render made one",
        +      "propertyNames": {
        +        "type": "string"
        +      },
        +      "type": "object"
        +    },
        +    "environment": {
        +      "enum": [
        +        "live",
        +        "test"
        +      ],
        +      "type": "string"
        +    },
        +    "error": {
        +      "anyOf": [
        +        {
        +          "additionalProperties": false,
        +          "properties": {
        +            "code": {
        +              "type": "string"
        +            },
        +            "message": {
        +              "type": "string"
        +            }
        +          },
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "Why a failed render failed"
        +    },
        +    "expires_at": {
        +      "description": "When download_url stops working; get_render issues a fresh one",
        +      "type": [
        +        "string",
        +        "null"
        +      ]
        +    },
        +    "id": {
        +      "description": "rnd_ id of the render",
        +      "type": "string"
        +    },
        +    "page_count": {
        +      "type": [
        +        "number",
        +        "null"
        +      ]
        +    },
        +    "status": {
        +      "enum": [
        +        "queued",
        +        "rendering",
        +        "succeeded",
        +        "failed"
        +      ],
        +      "type": "string"
        +    },
        +    "template": {
        +      "anyOf": [
        +        {
        +          "additionalProperties": false,
        +          "properties": {
        +            "canary": {
        +              "type": "boolean"
        +            },
        +            "channel": {
        +              "type": [
        +                "string",
        +                "null"
        +              ]
        +            },
        +            "id": {
        +              "type": "string"
        +            },
        +            "slug": {
        +              "type": "string"
        +            },
        +            "version": {
        +              "type": "number"
        +            }
        +          },
        +          "required": [
        +            "id",
        +            "slug",
        +            "version"
        +          ],
        +          "type": "object"
        +        },
        +        {
        +          "type": "null"
        +        }
        +      ],
        +      "description": "The template and version rendered; null for html and conversions"
        +    },
        +    "units": {
        +      "description": "Units the render counted",
        +      "type": "number"
        +    }
        +  },
        +  "required": [
        +    "id",
        +    "status",
        +    "download_url",
        +    "expires_at",
        +    "page_count",
        +    "units",
        +    "environment",
        +    "template",
        +    "error"
        +  ],
        +  "type": "object"
        +}
    • Changedvalidate_template1 field changed
      • changedOutput schema / (root)
        Previous value: -nullNew value: +{
        +  "$schema": "http://json-schema.org/draft-07/schema#",
        +  "additionalProperties": false,
        +  "properties": {
        +    "diagnostics": {
        +      "items": {
        +        "additionalProperties": false,
        +        "properties": {
        +          "code": {
        +            "type": "string"
        +          },
        +          "column": {
        +            "type": "number"
        +          },
        +          "line": {
        +            "type": "number"
        +          },
        +          "message": {
        +            "type": "string"
        +          },
        +          "paragraph": {
        +            "type": "number"
        +          },
        +          "part": {
        +            "description": "Word and PowerPoint templates: the file part of the tag",
        +            "type": "string"
        +          },
        +          "path": {
        +            "description": "Where in the data, for data errors",
        +            "type": "string"
        +          },
        +          "severity": {
        +            "enum": [
        +              "error",
        +              "warning",
        +              "info"
        +            ],
        +            "type": "string"
        +          }
        +        },
        +        "required": [
        +          "severity",
        +          "code",
        +          "message"
        +        ],
        +        "type": "object"
        +      },
        +      "type": "array"
        +    },
        +    "ok": {
        +      "description": "false when a diagnostic is an error",
        +      "type": "boolean"
        +    },
        +    "template": {
        +      "additionalProperties": false,
        +      "description": "The stored version checked; absent for html",
        +      "properties": {
        +        "id": {
        +          "type": "string"
        +        },
        +        "slug": {
        +          "type": "string"
        +        },
        +        "version": {
        +          "type": "number"
        +        }
        +      },
        +      "required": [
        +        "id",
        +        "slug",
        +        "version"
        +      ],
        +      "type": "object"
        +    }
        +  },
        +  "required": [
        +    "ok",
        +    "diagnostics"
        +  ],
        +  "type": "object"
        +}
  4. 2 tool updatesv0.3.17
    • Addedcheck_invoice
    • Changedrender1 field changed
      • addedInput schema / properties / einvoice
        Added value: +{
        +  "anyOf": [
        +    {
        +      "type": "boolean"
        +    },
        +    {
        +      "properties": {
        +        "display_check": {
        +          "description": "What a value of the XML that the PDF does not show does: a warning in the report (default) or a failed render",
        +          "enum": [
        +            "warn",
        +            "strict"
        +          ],
        +          "type": "string"
        +        },
        +        "flavour": {
        +          "description": "One specification under two names; the default factur-x and zugferd make the same file",
        +          "enum": [
        +            "factur-x",
        +            "zugferd"
        +          ],
        +          "type": "string"
        +        },
        +        "profile": {
        +          "description": "en16931 (default) carries the whole European standard; basic is the smallest full invoice and is refused between two French businesses",
        +          "enum": [
        +            "en16931",
        +            "basic"
        +          ],
        +          "type": "string"
        +        },
        +        "xml": {
        +          "description": "both also stores the XML as a file of its own, linked as einvoice.xml_url",
        +          "enum": [
        +            "embedded",
        +            "both"
        +          ],
        +          "type": "string"
        +        }
        +      },
        +      "type": "object"
        +    }
        +  ],
        +  "description": "Makes the PDF a ZUGFeRD / Factur-X e-invoice whose XML is built from data._invoice: true for the defaults, an object to choose, false to switch off what the template declares. PDF only; live renders from the Starter plan, test keys on Free make 20 marked ones a day"
        +}
  5. 1 tool updatev0.3.14
    • Addedget_workspace
  6. 6 tool updatesv0.3.10
    • Changedconvert_to_pdf5 fields changed
      • changedInput schema / properties / file_base64 / description
        Previous value: -"The document, base64 encoded"New value: +"The document to convert, base64 encoded; needs file_name"
      • changedInput schema / properties / filename / description
        Previous value: -"Name of the PDF"New value: +"Name of the PDF behind download_url, e.g. report.pdf"
      • changedInput schema / properties / page_ranges / description
        Previous value: -"Pages to convert, e.g. 1-3,5"New value: +"Pages to convert, e.g. 1-3,5; all pages when left out"
      • changedInput schema / properties / path / description
        Previous value: -"Absolute path of a document on this machine"New value: +"Absolute path of the document on this machine"
      • changedInput schema / properties / render_id / description
        Previous value: -"rnd_ id of a render whose output is docx or pptx"New value: +"rnd_ id of a render whose output is docx or pptx, to get that document as a PDF"
    • Changedget_render1 field changed
      • addedInput schema / properties / id / description
        Added value: +"rnd_ id of the render, as render or convert_to_pdf returned it"
    • Changedget_template_schema1 field changed
      • changedInput schema / properties / template / description
        Previous value: -"Template slug or tpl_ id"New value: +"Slug (e.g. invoice) or tpl_ id, as list_templates returns them"
    • Changedlist_templates4 fields changed
      • addedInput schema / properties / engine / description
        Added value: +"Only templates written in this template language"
      • addedInput schema / properties / kind / description
        Added value: +"Only templates that produce this kind of document"
      • changedInput schema / properties / q / description
        Previous value: -"Search in name and slug"New value: +"Text to find in the name or slug, case-insensitive (e.g. invoice)"
      • addedInput schema / properties / tag / description
        Added value: +"Only templates with this tag; exact match, tags are lowercase with dashes (e.g. billing)"
    • Changedrender6 fields changed
      • addedInput schema / properties / data / description
        Added value: +"Values for the template, shaped as get_template_schema describes; leave out when it needs none"
      • changedInput schema / properties / engine / description
        Previous value: -"Engine for html that contains template syntax"New value: +"Template language of html, when it contains expressions to fill from data"
      • addedInput schema / properties / filename / description
        Added value: +"Name of the file behind download_url, e.g. invoice-2026-0042.pdf"
      • changedInput schema / properties / html / description
        Previous value: -"Raw HTML instead of a template"New value: +"A complete HTML document to render instead of a stored template, up to 5 MB"
      • changedInput schema / properties / template / description
        Previous value: -"Template slug or tpl_ id"New value: +"Slug or tpl_ id of a stored template; pass this or html"
      • changedInput schema / properties / wait / description
        Previous value: -"Wait for the render to finish (sync renders finish immediately)"New value: +"Most renders are finished when the call returns; true also waits for one that continues in the background, false returns it as it is (queued or rendering) to check later with get_render"
    • Changedvalidate_template4 fields changed
      • addedInput schema / properties / data / description
        Added value: +"The data the document will be rendered with, shaped as get_template_schema describes. Left out, a stored template is checked with its sample data"
      • changedInput schema / properties / engine / description
        Previous value: -"Required with html"New value: +"Template language of html; required with html"
      • changedInput schema / properties / html / description
        Previous value: -"Template source when no slug is given"New value: +"Template source to check offline, when there is no stored template; pass this or template"
      • changedInput schema / properties / template / description
        Previous value: -"Template slug or tpl_ id"New value: +"Slug or tpl_ id of a stored template; pass this or html"
  7. 6 tool updatesv0.3.7
    • First observedconvert_to_pdf
    • First observedget_render
    • First observedget_template_schema
    • First observedlist_templates
    • First observedrender
    • First observedvalidate_template

TDQS

A4.4/5.0

Scored across 10 tools

Disambiguation4/5

Most tools target a clearly distinct operation (listing, reading source, reading schema, saving, validating, rendering, converting, checking status, validating invoices, workspace info), and the descriptions explicitly cross-reference each other (e.g. render vs convert_to_pdf, validate_template vs render). The remaining soft overlaps are get_template_schema vs get_template_source (both 'read about a template') and validate_template vs check_invoice (both 'validate'), but the descriptions disambiguate them well enough to avoid misselection.

Naming Consistency4/5

Names follow a consistent snake_case verb_noun pattern: get_template_source, get_template_schema, get_render, get_workspace, list_templates, save_template, validate_template, convert_to_pdf, check_invoice. The lone deviation is `render`, a bare verb with no object, which slightly breaks the pattern but is unambiguous in context.

Tool Count5/5

Ten tools is well within the sweet spot and each earns its place: discovery, schema, source, edit, validation, render, conversion, polling, e-invoice check, and workspace context. Nothing feels padded or redundant.

Completeness4/5

The core lifecycle is covered: list/read/schema/save-draft/validate/render/convert/poll, with a deliberate human publish step and invoice validation for e-invoicing. Gaps exist around template housekeeping (no archive/delete, no list of versions or past renders beyond a single id), but agents can work around these via the review_url and Formfeed UI.

Maintenance

ActivityActive
ResponsivenessNo issues

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables PDF and image generation from templates, JSON, HTML, or URLs through the PDF Gen Studio API. Supports rendering, template management, and multiple output formats.
    6 npm
    1
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables creating professional documents (invoices, contracts, certificates, proposals, reports) via the DocuQueue API, with tools for template management, filling, previewing, and PDF generation.
    70 npm
    1
    MIT