@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 CHANGED
@@ -1,5 +1,7 @@
1
1
  # @formfeed/mcp
2
2
 
3
+ [![formfeed MCP server – quality and maintenance score on Glama](https://glama.ai/mcp/servers/formfeed-dev/formfeed/badges/score.svg)](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,
@@ -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.8" };
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: "Templates of the workspace the API key belongs to, with slug, kind (pdf, image, docx for Word, pptx for PowerPoint), engine and published version.",
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("Search in name and slug")
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: { readOnlyHint: true }
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, plus the sample data it was designed with. Use it to build the data for render.",
81523
- inputSchema: { template: z2.string().describe("Template slug or tpl_ id") },
81524
- annotations: { readOnlyHint: true }
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 with data without rendering; free. With a template slug the API checks the version a render uses (the published one, else the latest) as the render would: syntax, header and footer, errors that happen only with this data, and the data against the template's stored JSON Schema (a wrong type or a missing required field is an error). With html plus engine it compiles offline and reports syntax errors, unknown filters and variables missing from the data. Warnings leave ok true: treat each one as a question to settle before rendering. For Word and PowerPoint templates the findings name the document part and paragraph.",
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("Template slug or tpl_ id"),
81546
- html: z2.string().optional().describe("Template source when no slug is given"),
81547
- engine: engineSchema.optional().describe("Required with html"),
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: { readOnlyHint: true }
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: "Renders a template (with data) or raw HTML to a PDF or image, or a Word or PowerPoint template to DOCX, PPTX or PDF, and returns a download URL. Live keys consume units; test keys render free with a watermark.",
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("Template slug or tpl_ id"),
81598
- html: z2.string().optional().describe("Raw HTML instead of a template"),
81599
- engine: engineSchema.optional().describe("Engine for html that contains template syntax"),
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("Wait for the render to finish (sync renders finish immediately)")
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: { readOnlyHint: false, idempotentHint: false }
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 a Word, Excel, PowerPoint, OpenDocument, RTF or HTML document (up to 20 MB) to a PDF and returns a download URL (Starter plan and above; units follow the PDF rule).",
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 a document on this machine") } : {},
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: { readOnlyHint: false, idempotentHint: false }
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: "Status, download URL and error of a render by id (rnd_\u2026).",
81698
- inputSchema: { id: z2.string() },
81699
- annotations: { readOnlyHint: true }
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.8",
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",