MCP-Server
@formfeed/mcp stellt Formfeed Agenten bereit, die das Model Context Protocol
(MCP) sprechen: Claude Desktop, Claude Code, Cursor, VS Code, Zapier-Agenten und Ihre eigenen. Er läuft auf
eine von zwei Arten:
- Lokal (stdio): Ihr Client startet
npx -y @formfeed/mcpmit einem API-Schlüssel inFORMFEED_API_KEY. Siehe Lokal betreiben. - Gehostet (Streamable HTTP): Ihr Client verbindet sich mit
https://mcp.formfeed.dev/mcp, mit einem API-Schlüssel oder per Anmeldung mit Ihrem Formfeed-Konto. Siehe Gehosteter Endpunkt.
Ein Server handelt in einem Workspace: dem, für den sein API-Schlüssel angelegt wurde, oder dem, den Sie
bei der Anmeldung wählen. In der offiziellen MCP-Registry steht der Server als
io.github.formfeed-dev/formfeed.
Tools
| Tool | Was es tut | Kosten |
|---|---|---|
list_templates | Die Vorlagen des Workspace, zuletzt geänderte zuerst und ohne archivierte: id (tpl_…), Slug, Name, Art (pdf, image, docx, pptx), Engine, Beschreibung, Tags und published_version (null heißt nie veröffentlicht, render kann sie also noch nicht nutzen). Filtert nach Art, Engine, Tag und Suche | kostenlos |
get_template_schema | Das JSON-Schema der data, die eine Vorlage erwartet, und ihre Beispieldaten, aus der veröffentlichten Version, sonst aus dem neuesten Entwurf. Speichert die Vorlage kein Schema, wird eines aus den Beispieldaten abgeleitet: ein Anhaltspunkt, kein Vertrag | kostenlos |
validate_template | Prüft eine Vorlage mit Daten, ohne zu rendern; gespeichert wird nichts. Mit einem Slug prüft die API die veröffentlichte Version (sonst den neuesten Entwurf) wie ein Rendering: Syntax, Kopf- und Fußzeile, Fehler, die erst mit diesen Daten auftreten, und die Daten gegen das gespeicherte Datenschema (ein falscher Typ oder ein fehlendes Pflichtfeld ist ein Fehler). Mit html plus engine kompiliert es offline und meldet Syntaxfehler, unbekannte Filter und fehlende Variablen. Liefert ok und diagnostics; bei einer Word- oder PowerPoint-Vorlage nennt ein Befund Teil und Absatz. Warnungen lassen ok auf true | kostenlos |
check_invoice | Prüft den _invoice-Block einer E-Rechnung offline, wie die API es vor dem Rendern tut: die Felder, die EN 16931 verlangt, die Summen auf den Cent, Umsatzsteuerkategorien und Codelisten sowie Frankreichs Regeln für eine Rechnung zwischen zwei französischen Unternehmen. An die API geht nichts. Liefert ok und problems, jedes mit dem Feld (path), der Regel (BR-…), wo eine greift, und einer Meldung | kostenlos |
render | Rendert eine gespeicherte Vorlage oder rohes HTML mit Daten und liefert das Rendering mit status und download_url: PDF, PNG, JPG oder WebP sowie DOCX, PPTX oder PDF für Word- und PowerPoint-Vorlagen; ohne output entscheidet die Vorlage. Eine gespeicherte Vorlage rendert ihre veröffentlichte Version. Mit einvoice wird das PDF eine ZUGFeRD- / Factur-X-E-Rechnung aus data._invoice, und das Rendering trägt den Bericht des Validators. Ein Bild bis 2 MB kommt zusätzlich als Bild zurück, das der Agent ansehen kann; ein PDF kommt als Link | Einheiten; kostenlos mit Test-Schlüssel |
convert_to_pdf | Wandelt ein vorhandenes Word-, Excel-, PowerPoint-, OpenDocument-, RTF- oder HTML-Dokument (bis 20 MB, wird nicht gespeichert) oder das Rendering einer Word- oder PowerPoint-Vorlage unverändert, ohne Daten, in ein PDF um und liefert das Rendering. Übergeben Sie render_id, file_base64 mit file_name oder, nur beim lokalen Server, path | Einheiten wie ein PDF dieser Länge; ab dem Starter-Tarif |
get_render | Status, download_url mit ihrem expires_at, Seitenzahl, Einheiten und Fehler eines Renderings. Es stellt einen frischen Link aus, ist also der Weg, wenn der alte abgelaufen ist | kostenlos |
get_workspace | Workspace (mit seiner Region) und Organisation, in denen der Server arbeitet, der Tarif, die Umgebung (live oder test) und die Einheiten des laufenden Zeitraums: enthaltene, verbrauchte und übrige vorausbezahlte | kostenlos |
Ein typischer Ablauf für Agenten: list_templates → get_template_schema → Daten bauen → validate_template → render → download_url an den Nutzer geben.
Für eine E-Rechnung baut der Agent den _invoice-Block, korrigiert ihn mit check_invoice, bis er ok ist, und ruft render mit einvoice und dem Block als data._invoice auf. Die Vorlage druckt denselben Block, wie es das Beispiel „E-Rechnung“ der Galerie tut. Eine abgelehnte Rechnung kommt als Tool-Fehler zurück, der jedes Feld und jede Regel nennt, sodass der Agent den Block korrigieren und es erneut versuchen kann. Live-E-Rechnungen brauchen den Starter-Tarif; Test-Schlüssel erzeugen eine begrenzte Zahl am Tag, jede mit der Testmarkierung (siehe Tarife und Einheiten).
Jedes Tool antwortet neben dem Text mit strukturiertem Inhalt und gibt dessen Form als Ausgabeschema an (outputSchema in MCP), sodass ein Client die Felder prüfen kann, die er liest: status, download_url und units eines Renderings, die diagnostics einer Prüfung, Tarif und Einheiten des Workspace. Ein Tool-Fehler kommt nur als Text.
Argumente
Der Agent liest sie vom Server selbst; hier stehen sie, damit Sie wissen, worauf er zugreifen kann. Jedes Argument ist optional, sofern nicht anders vermerkt, und ein Tool ohne Argumente braucht keine.
list_templates — schränkt die Liste ein; ohne Argumente kommen alle Vorlagen des Workspace zurück.
| Argument | Typ | Bedeutung |
|---|---|---|
kind | pdf | image | docx | pptx | Nur Vorlagen dieser Art |
engine | jinja2 | liquid | handlebars | Nur Vorlagen in dieser Engine |
tag | String | Genau dieser Tag, wie die App ihn schreibt (klein, mit Bindestrichen) |
q | String | Suche in Name und Slug, ohne Unterschied von Groß- und Kleinschreibung |
get_template_schema
| Argument | Typ | Bedeutung |
|---|---|---|
template | String, erforderlich | Slug oder tpl_…-ID. Die veröffentlichte Version, sonst die neueste |
validate_template — entweder template oder html mit engine.
| Argument | Typ | Bedeutung |
|---|---|---|
template | String | Slug oder tpl_…-ID |
html | String | Vorlagenquelle, wenn kein Slug angegeben ist |
engine | jinja2 | liquid | handlebars | Mit html erforderlich |
data | Objekt | Wird gegen die Vorlage geprüft; ohne Angabe gelten die Beispieldaten der Vorlage |
check_invoice
| Argument | Typ | Bedeutung |
|---|---|---|
invoice | Objekt, erforderlich | Der _invoice-Block, mit den Feldern der Feldreferenz |
profile | en16931 | basic | Das Profil, das das Rendering verlangen wird, ohne Angabe en16931. basic kann keinen Rundungsbetrag tragen und wird zwischen zwei französischen Unternehmen abgelehnt |
render — entweder template oder html.
| Argument | Typ | Bedeutung |
|---|---|---|
template | String | Slug oder tpl_…-ID. Rendert die veröffentlichte Version; eine nie veröffentlichte Vorlage scheitert mit template_not_found |
html | String | Ein vollständiges HTML-Dokument statt einer Vorlage, bis 5 MB |
engine | jinja2 | liquid | handlebars | Für html mit Vorlagensyntax, die aus data gefüllt wird |
data | Objekt | Wird an die Vorlage gebunden, in der Form, die get_template_schema beschreibt |
output | pdf | png | jpg | webp | docx | pptx | Ohne Angabe entscheidet die Vorlage: PDF bei PDF-Vorlagen und html, das Bildformat bei Bildvorlagen, die Vorgabe bei Word- und PowerPoint-Vorlagen. Word-Vorlagen rendern docx oder pdf, PowerPoint-Vorlagen pptx oder pdf |
filename | String | Name der Datei hinter download_url, etwa rechnung-2026-0042.pdf |
locale | String | BCP-47-Tag für Helfer und Übersetzungen, etwa de-DE |
wait | Boolean, Vorgabe true | Das Tool fragt das Dokument synchron an, die meisten Renderings sind also fertig, wenn es antwortet. Ein Rendering, das länger als die synchrone Grenze der API (eine Minute) braucht, läuft im Hintergrund weiter: mit true wartet das Tool darauf, bis zu zwei weitere Minuten; mit false liefert es das Rendering im aktuellen Stand (queued oder rendering), das Sie mit get_render verfolgen |
einvoice | Boolean | Objekt | Macht das PDF zu einer E-Rechnung aus data._invoice: true für die Vorgaben oder die Optionen profile, flavour, xml und display_check; false schaltet ab, was die Vorlage erklärt. Nur PDF. Live-E-Rechnungen ab dem Starter-Tarif; Test-Renderings erzeugen eine begrenzte Zahl am Tag, jede mit der Testmarkierung |
convert_to_pdf — genau eine Quelle angeben: render_id, file_base64 (mit file_name) oder path.
| Argument | Typ | Bedeutung |
|---|---|---|
render_id | String | rnd_… eines Renderings mit Ausgabe docx oder pptx |
file_base64 | String | Das Dokument selbst, base64-kodiert, bis 20 MB |
file_name | String | Mit file_base64 erforderlich. Sein Name, etwa report.xlsx; der Typ wird aus dem Inhalt gelesen, nicht aus der Endung |
path | String | Absoluter Pfad einer Datei auf diesem Rechner. Nur lokaler Server: Der gehostete Endpunkt bietet dieses Argument nicht an und hat keinen Zugriff auf Ihre Festplatte |
page_ranges | String | Zu konvertierende Seiten, etwa 1-3,5; ohne Angabe alle Seiten |
landscape | Boolean | Querformat, für Tabellen und Dokumente ohne eigenes Seiten-Setup |
single_page_sheets | Boolean | Jedes Tabellenblatt auf eine Seite |
filename | String | Name des PDFs; ohne Angabe der Name des Dokuments mit .pdf |
get_render
| Argument | Typ | Bedeutung |
|---|---|---|
id | String, erforderlich | rnd_…-ID des Renderings |
get_workspace nimmt keine Argumente. Es antwortet mit workspace, organization, plan,
environment, period und units, wie GET /account.
Lokal betreiben (stdio)
Der lokale Server braucht Node.js 22 oder neuer; npx lädt und startet ihn. Claude Desktop
(claude_desktop_config.json) und Cursor (~/.cursor/mcp.json für alle Projekte, .cursor/mcp.json
für eines) nehmen denselben Eintrag:
{
"mcpServers": {
"formfeed": {
"command": "npx",
"args": ["-y", "@formfeed/mcp"],
"env": { "FORMFEED_API_KEY": "ff_test_…" }
}
}
}
Claude Code fügt ihn mit einem Befehl hinzu. Der Name des Servers steht vor --env, denn die Option
nimmt mehrere Werte und hielte den Namen sonst für einen davon; alles nach -- ist der Befehl, den
Claude Code startet:
claude mcp add --transport stdio formfeed --env FORMFEED_API_KEY=ff_test_… -- npx -y @formfeed/mcp
VS Code liest .vscode/mcp.json; der Schlüssel heißt dort servers, und eine Eingabevariable hält
den API-Schlüssel aus der Datei heraus:
{
"inputs": [
{
"type": "promptString",
"id": "formfeed-key",
"description": "Formfeed API key",
"password": true
}
],
"servers": {
"formfeed": {
"type": "stdio",
"command": "npx",
"args": ["-y", "@formfeed/mcp"],
"env": { "FORMFEED_API_KEY": "${input:formfeed-key}" }
}
}
}
Der lokale Server liest diese Umgebungsvariablen:
| Variable | Bedeutung |
|---|---|
FORMFEED_API_KEY | Ein API-Schlüssel des Workspace. Ohne ihn startet der Server nur mit den Offline-Prüfungen, validate_template mit html und check_invoice; jedes andere Tool antwortet, wie man einen Schlüssel bekommt |
FORMFEED_REGION | eu (die Vorgabe) oder us: der API-Host dieser Region. Jeder Workspace liegt heute in der EU |
FORMFEED_BASE_URL | Eine andere API-Adresse, mit /v1, etwa https://api-eu.formfeed.dev/v1; sie geht der Region vor |
Nutzen Sie beim Bauen einen Test-Schlüssel (ff_test_…): Seine Renderings sind kostenlos (im
Free-Tarif mit Testmarkierung). Wechseln Sie auf einen Live-Schlüssel (ff_live_…), wenn der Agent in
Produktion geht. Der Schlüssel braucht die Scopes der Tools, die der
Agent nutzt; die Vorgaben eines neuen Schlüssels (render:create, render:read, template:read,
account:read) decken alle acht ab.
Eine Schritt-für-Schritt-Einrichtung für 18 Clients und Agent-Frameworks (Claude Desktop und Code, Cursor, VS Code, Windsurf (heute Devin Desktop), Zed, Codex, Gemini CLI, das OpenAI Agents SDK, LangChain, Mastra und weitere) finden Sie unter formfeed.dev/agents.
Für Coding-Agenten fügt das Formfeed-Plugin den gehosteten Server zusammen mit zwei Skills hinzu, die Vorlagen und den Code, der sie rendert, schreiben und prüfen: siehe Coding-Agenten.
Gehosteter Endpunkt
mcp.formfeed.dev liefert dieselben Tools über Streamable HTTP, für Clients, die sich aus der Ferne
verbinden (Claude.ai-Konnektoren, Claude Code, Cursor, ChatGPT, n8n und die Agenten-Frameworks):
| URL | Anmeldung mit | Für |
|---|---|---|
https://mcp.formfeed.dev/mcp | Ihrem Formfeed-Konto (OAuth) oder Authorization: Bearer ff_… | alle: Ein Chat-Client öffnet die Anmeldung selbst, und Sie wählen den Workspace; ein Server oder eine Automatisierung schickt den API-Schlüssel |
https://mcp.formfeed.dev/mcp/<workspace id> | Ihrem Formfeed-Konto (OAuth) | eine zweite Verbindung, die in einem anderen Workspace arbeiten soll als dem gewählten |
Mit einem API-Schlüssel schickt der Client ihn als Header. In Claude Code:
claude mcp add --transport http formfeed https://mcp.formfeed.dev/mcp --header "Authorization: Bearer ff_test_…"
Ein Client, der Server nachschlägt, bevor er sich verbindet, findet diesen über
https://formfeed.dev/.well-known/ai-catalog.json, das auf die Server Card des Endpunkts zeigt,
https://mcp.formfeed.dev/mcp/server-card: Name, Version und beide Adressen, ohne Schlüssel lesbar.
Anmeldung mit Ihrem Konto
Tragen Sie https://mcp.formfeed.dev/mcp ohne Schlüssel im Client ein. Er entdeckt den OAuth-Server
von Formfeed, registriert sich selbst und öffnet den Browser: Sie melden sich bei Formfeed an, falls
noch nicht geschehen, sehen, welcher Client fragt und was er darf, wählen den Workspace, in dem der
Agent arbeitet, und erlauben es. Der Client behält ein Token und erneuert es selbst; die Abmeldung
im Client beendet den Zugriff.
# Claude Code
claude mcp add --transport http formfeed https://mcp.formfeed.dev/mcp
Der Workspace bleibt beim Client: Der Agent arbeitet dort, bis Sie es in der App unter
Verbundene Agenten im Kontomenü ändern, wo jeder erlaubte Agent mit seinem Workspace steht und sich
der Zugriff widerrufen lässt. Eine Änderung erreicht den Agenten innerhalb einer Stunde, mit seinem
nächsten Token. Um in zwei Workspaces zugleich zu arbeiten, verbinden Sie den Client ein zweites Mal
mit der eigenen Adresse des Workspace, https://mcp.formfeed.dev/mcp/<workspace id> (die ID steht
unter Einstellungen → Details als Workspace-ID); ein so verbundener Client arbeitet dort, was
auch immer für ihn gewählt ist.
Ein angemeldeter Agent handelt in diesem Workspace als Sie, aber mit höchstens vier
Scopes, template:read, render:read, render:create und
account:read, und nie mit mehr, als Ihre Rolle erlaubt (der Agent eines Betrachters kann nicht
rendern). Er liest also Vorlagen und ihre Datenschemas, prüft Daten, rendert Dokumente und wandelt
Office-Dateien um (Einheiten zählen wie bei jedem Rendering), liest die Renderings des Workspace und
liest, in welchem Workspace er arbeitet und was der Zeitraum noch hat (get_workspace). Er kann keine
Vorlagen veröffentlichen oder ändern, keine Dateien hochladen oder löschen und weder Webhooks,
Schlüssel, Mitglieder noch Abrechnung verwalten, unabhängig von Ihrer Rolle. Ein angemeldeter Agent
rendert immer live; zum kostenlosen Rendern beim Bauen verbinden Sie ihn stattdessen mit einem
Test-Schlüssel.
Auf dem Endpunkt wird nichts gespeichert: Jede Anfrage bringt ihr Token mit, und die API prüft bei jedem Aufruf, dass Sie noch Mitglied des Workspace des Agenten sind.
Mit Zwei-Faktor-Authentifizierung auf Ihrem Konto
arbeitet ein Agent erst, nachdem Sie ihn auf der Zustimmungsseite aus einer Sitzung erlaubt haben, die
Ihren Code bestanden hat. Ein Agent, den Sie vor dem Einschalten der Zwei-Faktor-Authentifizierung
erlaubt haben, wird ab seinem nächsten Token (innerhalb der Stunde) abgewiesen: Verbinden Sie ihn neu
und erlauben Sie ihn noch einmal. Bis dahin, und für jeden Agenten, der nie so erlaubt wurde,
antwortet die API mit 403 forbidden und dem Grund.
Den Endpunkt selbst betreiben
Derselbe Server läuft überall, wo Node.js 22 läuft:
npx -y @formfeed/mcp --http --port 8790 --host 0.0.0.0
--port ist ohne Angabe 8790, --host ist 127.0.0.1. Der Server nimmt API-Schlüssel auf /mcp,
mit jeder Anfrage als Authorization: Bearer ff_… gesendet, und ruft den API-Host auf, den
FORMFEED_REGION oder FORMFEED_BASE_URL wählt. --auth-server <issuer> (oder
FORMFEED_AUTH_SERVER) ergänzt die OAuth-Anmeldung auf /mcp und /mcp/<workspace id>; so läuft der
gehostete Endpunkt. Der Server reicht die Zugriffstokens an die Formfeed-API weiter, und die nimmt nur
Tokens der Formfeed-eigenen Anmeldung an: Ein selbst betriebener Endpunkt ist also für API-Schlüssel
da. --public-origin <url> (oder FORMFEED_PUBLIC_ORIGIN) nennt den Origin, den Clients hinter einem
Proxy sehen. Seine Server Card liegt unter /mcp/server-card dieses Origins.
Hinweise
- Die Validierung nutzt dieselbe Engine wie der Editor und die Render-Server, ein Agent kann Daten- oder Vorlagenprobleme also beheben, bevor Einheiten verbraucht werden.
- Jeder Aufruf von
renderist ein neues Rendering, das seine Einheiten zählt; zwischen Aufrufen wird nichts dedupliziert. - Fehler kommen als Tool-Fehler zurück, deren Text mit dem API-Problemcode beginnt
(
quota_exceeded: …,template_not_found: …), nie als Ausnahmen. Eine abgelehnte E-Rechnung (einvoice_data_invalid,einvoice_display_mismatch,pdfa_conversion_failed) bringt zusätzlicherrorsund deneinvoice-Bericht des Problems mit, ein strikt gescheitertes PDF/UA (pdfua_validation_failed) seinaccessibility-Urteil. Fehler listet jeden Code.