@formfeed/mcp 0.3.8 → 0.3.10
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/README.md +2 -0
- package/bin/formfeed-mcp.mjs +38 -35
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
# @formfeed/mcp
|
|
2
2
|
|
|
3
|
+
[](https://glama.ai/mcp/servers/formfeed-dev/formfeed)
|
|
4
|
+
|
|
3
5
|
Model Context Protocol server for [Formfeed](https://formfeed.dev/?utm_source=npm&utm_content=mcp).
|
|
4
6
|
Gives Claude, Cursor and other agents six tools: `list_templates`, `get_template_schema`,
|
|
5
7
|
`validate_template` (free: the data against the template's schema, ad-hoc HTML offline), `render`, `convert_to_pdf` (Word, Excel,
|
package/bin/formfeed-mcp.mjs
CHANGED
|
@@ -81449,7 +81449,9 @@ var encoder2 = new TextEncoder();
|
|
|
81449
81449
|
// packages/mcp/src/lib/server.ts
|
|
81450
81450
|
import { z as z2 } from "zod";
|
|
81451
81451
|
var CONVERT_LIMIT_BYTES = 20 * 1024 * 1024;
|
|
81452
|
-
var SERVER_INFO = { name: "formfeed", version: "0.3.
|
|
81452
|
+
var SERVER_INFO = { name: "formfeed", version: "0.3.10" };
|
|
81453
|
+
var READS = { readOnlyHint: true, destructiveHint: false, openWorldHint: false };
|
|
81454
|
+
var CREATES = { readOnlyHint: false, destructiveHint: false, idempotentHint: false, openWorldHint: false };
|
|
81453
81455
|
var engineSchema = z2.enum(["jinja2", "liquid", "handlebars"]);
|
|
81454
81456
|
var outputSchema = z2.enum(outputFormats);
|
|
81455
81457
|
var kindSchema = z2.enum(["pdf", "image", "docx", "pptx"]);
|
|
@@ -81497,14 +81499,14 @@ function createFormfeedServer(options) {
|
|
|
81497
81499
|
"list_templates",
|
|
81498
81500
|
{
|
|
81499
81501
|
title: "List templates",
|
|
81500
|
-
description: "
|
|
81502
|
+
description: "Lists the templates of the workspace the API key belongs to, 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.",
|
|
81501
81503
|
inputSchema: {
|
|
81502
|
-
kind: kindSchema.optional(),
|
|
81503
|
-
engine: engineSchema.optional(),
|
|
81504
|
-
tag: z2.string().optional(),
|
|
81505
|
-
q: z2.string().optional().describe("
|
|
81504
|
+
kind: kindSchema.optional().describe("Only templates that produce this kind of document"),
|
|
81505
|
+
engine: engineSchema.optional().describe("Only templates written in this template language"),
|
|
81506
|
+
tag: z2.string().optional().describe("Only templates with this tag; exact match, tags are lowercase with dashes (e.g. billing)"),
|
|
81507
|
+
q: z2.string().optional().describe("Text to find in the name or slug, case-insensitive (e.g. invoice)")
|
|
81506
81508
|
},
|
|
81507
|
-
annotations:
|
|
81509
|
+
annotations: READS
|
|
81508
81510
|
},
|
|
81509
81511
|
async (args2) => {
|
|
81510
81512
|
try {
|
|
@@ -81519,9 +81521,9 @@ function createFormfeedServer(options) {
|
|
|
81519
81521
|
"get_template_schema",
|
|
81520
81522
|
{
|
|
81521
81523
|
title: "Get the data schema of a template",
|
|
81522
|
-
description: "JSON Schema of the `data` object a template expects
|
|
81523
|
-
inputSchema: { template: z2.string().describe("
|
|
81524
|
-
annotations:
|
|
81524
|
+
description: "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.",
|
|
81525
|
+
inputSchema: { template: z2.string().describe("Slug (e.g. invoice) or tpl_ id, as list_templates returns them") },
|
|
81526
|
+
annotations: READS
|
|
81525
81527
|
},
|
|
81526
81528
|
async ({ template }) => {
|
|
81527
81529
|
try {
|
|
@@ -81540,14 +81542,14 @@ function createFormfeedServer(options) {
|
|
|
81540
81542
|
"validate_template",
|
|
81541
81543
|
{
|
|
81542
81544
|
title: "Validate a template with data",
|
|
81543
|
-
description: "Checks a template
|
|
81545
|
+
description: "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) 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.",
|
|
81544
81546
|
inputSchema: {
|
|
81545
|
-
template: z2.string().optional().describe("
|
|
81546
|
-
html: z2.string().optional().describe("Template source when no
|
|
81547
|
-
engine: engineSchema.optional().describe("
|
|
81548
|
-
data: z2.record(z2.string(), z2.unknown()).optional()
|
|
81547
|
+
template: z2.string().optional().describe("Slug or tpl_ id of a stored template; pass this or html"),
|
|
81548
|
+
html: z2.string().optional().describe("Template source to check offline, when there is no stored template; pass this or template"),
|
|
81549
|
+
engine: engineSchema.optional().describe("Template language of html; required with html"),
|
|
81550
|
+
data: z2.record(z2.string(), z2.unknown()).optional().describe("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")
|
|
81549
81551
|
},
|
|
81550
|
-
annotations:
|
|
81552
|
+
annotations: READS
|
|
81551
81553
|
},
|
|
81552
81554
|
async ({ template, html, engine, data }) => {
|
|
81553
81555
|
try {
|
|
@@ -81592,20 +81594,20 @@ function createFormfeedServer(options) {
|
|
|
81592
81594
|
"render",
|
|
81593
81595
|
{
|
|
81594
81596
|
title: "Render a document",
|
|
81595
|
-
description: "
|
|
81597
|
+
description: "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. 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 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. The link expires at expires_at; get_render issues a fresh one.",
|
|
81596
81598
|
inputSchema: {
|
|
81597
|
-
template: z2.string().optional().describe("
|
|
81598
|
-
html: z2.string().optional().describe("
|
|
81599
|
-
engine: engineSchema.optional().describe("
|
|
81600
|
-
data: z2.record(z2.string(), z2.unknown()).optional(),
|
|
81599
|
+
template: z2.string().optional().describe("Slug or tpl_ id of a stored template; pass this or html"),
|
|
81600
|
+
html: z2.string().optional().describe("A complete HTML document to render instead of a stored template, up to 5 MB"),
|
|
81601
|
+
engine: engineSchema.optional().describe("Template language of html, when it contains expressions to fill from data"),
|
|
81602
|
+
data: z2.record(z2.string(), z2.unknown()).optional().describe("Values for the template, shaped as get_template_schema describes; leave out when it needs none"),
|
|
81601
81603
|
output: outputSchema.optional().describe(
|
|
81602
81604
|
"Left 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"
|
|
81603
81605
|
),
|
|
81604
|
-
filename: z2.string().optional(),
|
|
81606
|
+
filename: z2.string().optional().describe("Name of the file behind download_url, e.g. invoice-2026-0042.pdf"),
|
|
81605
81607
|
locale: z2.string().optional().describe("BCP 47 tag for helpers and translations, e.g. de-DE"),
|
|
81606
|
-
wait: z2.boolean().default(true).describe("
|
|
81608
|
+
wait: z2.boolean().default(true).describe("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")
|
|
81607
81609
|
},
|
|
81608
|
-
annotations:
|
|
81610
|
+
annotations: CREATES
|
|
81609
81611
|
},
|
|
81610
81612
|
async ({ template, html, engine, data, output, filename, locale, wait }) => {
|
|
81611
81613
|
try {
|
|
@@ -81632,22 +81634,23 @@ function createFormfeedServer(options) {
|
|
|
81632
81634
|
{
|
|
81633
81635
|
title: "Convert an office document to PDF",
|
|
81634
81636
|
description: [
|
|
81635
|
-
"Converts
|
|
81637
|
+
"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.",
|
|
81638
|
+
"To make a document from a template and data, use render instead.",
|
|
81636
81639
|
"Pass exactly one source: render_id, the render of a Word or PowerPoint template (output docx or pptx);",
|
|
81637
81640
|
options.localFiles ? "path, a file on this machine; or file_base64 with file_name." : "or file_base64 with file_name, the document itself.",
|
|
81638
|
-
"The document is converted and not kept."
|
|
81641
|
+
"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."
|
|
81639
81642
|
].join(" "),
|
|
81640
81643
|
inputSchema: {
|
|
81641
|
-
render_id: z2.string().optional().describe("rnd_ id of a render whose output is docx or pptx"),
|
|
81642
|
-
...options.localFiles ? { path: z2.string().optional().describe("Absolute path of
|
|
81643
|
-
file_base64: z2.string().optional().describe("The document, base64 encoded"),
|
|
81644
|
+
render_id: z2.string().optional().describe("rnd_ id of a render whose output is docx or pptx, to get that document as a PDF"),
|
|
81645
|
+
...options.localFiles ? { path: z2.string().optional().describe("Absolute path of the document on this machine") } : {},
|
|
81646
|
+
file_base64: z2.string().optional().describe("The document to convert, base64 encoded; needs file_name"),
|
|
81644
81647
|
file_name: z2.string().optional().describe("Name of the document, e.g. report.xlsx; the type is read from the content"),
|
|
81645
|
-
page_ranges: z2.string().regex(/^\d+(-\d+)?(,\d+(-\d+)?)*$/).optional().describe("Pages to convert, e.g. 1-3,5"),
|
|
81648
|
+
page_ranges: z2.string().regex(/^\d+(-\d+)?(,\d+(-\d+)?)*$/).optional().describe("Pages to convert, e.g. 1-3,5; all pages when left out"),
|
|
81646
81649
|
landscape: z2.boolean().optional().describe("Landscape for spreadsheets and documents without their own page setup"),
|
|
81647
81650
|
single_page_sheets: z2.boolean().optional().describe("Each spreadsheet sheet on one page"),
|
|
81648
|
-
filename: z2.string().optional().describe("Name of the PDF")
|
|
81651
|
+
filename: z2.string().optional().describe("Name of the PDF behind download_url, e.g. report.pdf")
|
|
81649
81652
|
},
|
|
81650
|
-
annotations:
|
|
81653
|
+
annotations: CREATES
|
|
81651
81654
|
},
|
|
81652
81655
|
async (args2) => {
|
|
81653
81656
|
try {
|
|
@@ -81694,9 +81697,9 @@ function createFormfeedServer(options) {
|
|
|
81694
81697
|
"get_render",
|
|
81695
81698
|
{
|
|
81696
81699
|
title: "Get a render",
|
|
81697
|
-
description: "
|
|
81698
|
-
inputSchema: { id: z2.string() },
|
|
81699
|
-
annotations:
|
|
81700
|
+
description: "Returns the current state of a render: status (queued, rendering, succeeded or failed), download_url with expires_at, page_count, units and error. 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.",
|
|
81701
|
+
inputSchema: { id: z2.string().describe("rnd_ id of the render, as render or convert_to_pdf returned it") },
|
|
81702
|
+
annotations: READS
|
|
81700
81703
|
},
|
|
81701
81704
|
async ({ id }) => {
|
|
81702
81705
|
try {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@formfeed/mcp",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.10",
|
|
4
4
|
"mcpName": "io.github.formfeed-dev/formfeed",
|
|
5
5
|
"description": "Model Context Protocol server for Formfeed: list templates, read data schemas, validate and render documents from AI agents.",
|
|
6
6
|
"license": "MIT",
|