formbasedocs
Naar de appApp

Ontwikkelaars

MCP-server

De Model Context Protocol (MCP)-server laat AI-agents je formbase-formulieren lezen en bewerken via uitgebreide, schema-gestuurde tools.


Wat het is

MCP is een open standaard waarmee AI-tools verbinding kunnen maken met externe diensten. formbase biedt een gehoste MCP-endpoint aan waarmee elke MCP-compatibele client verbinding kan maken, waaronder Claude Code, Claude desktop en Cursor.

Verbinding

text
URL:  https://api.formbase.so/api/mcp   (POST, streamable HTTP)
Auth: Bearer <token>

Twee soorten bearer token werken:

  • API-token (fb_…) — aangemaakt via API-tokens. Het beste voor persoonlijk gebruik en snelle configuratie.

  • OAuth-toegangstoken (fbo_…) — uitgegeven door de OAuth-flow. Het beste voor apps van derden die namens een gebruiker verbinding maken.

Beide zijn gebonden aan precies één werkruimte en bereiken dezelfde tools. Een tool-aanroep die een andere werkruimte noemt, of een formulier daarin, faalt met FORBIDDEN. OAuth-tokens dragen ook scopes (mcp:read, mcp:write, offline_access), maar vandaag wordt geen enkele tool erdoor beperkt — behandel elk token als volledige toegang binnen zijn werkruimte.

Tool-aanroepen zijn beperkt tot 120 per minuut per token, gedeeld met de API: alleen tools/call verbruikt het budget, terwijl initialize, tools/list, prompts/ en resources/ gratis zijn. Bij overschrijding geeft de aanroep nog steeds HTTP 200 terug met een mislukt toolresultaat dat RATE_LIMITED en een retryAfterMs draagt — poll op een timer, nooit in een lus.

Waar je een token krijgt

Open OAuth en API-sleutels in de zijbalk van je workspace om API-tokens aan te maken en verbonden OAuth-apps te bekijken. Zie API-tokens voor een stapsgewijze handleiding.

Kerntools

Elke tool wordt geadverteerd via tools/list wanneer een client verbinding maakt. Clients die schema’s on demand laden, zoals Claude Code, halen het volledige schema van een tool op zodra een taak hem nodig heeft. De onderstaande tabel toont de kerntools waarmee de meeste taken beginnen; load_tools (catalogi) en load_skill (domeinhandleidingen) documenteren de rest.

ToolWat het doet
form_listFormulieren in een workspace weergeven. Ondersteunt mapfilter, fuzzy naamzoeken en cursorpaginering.
form_getVolledige details van een formulier ophalen: vragen, omslagafbeelding, logo en een live voorbeeld-URL.
form_createEen nieuw leeg formulier aanmaken in een workspace. Geeft een voorbeeld-URL terug voor live bewerking.
form_updateFormuliermetadata bijwerken: naam, map, emoji, omslagafbeelding of logo.
form_deleteEen formulier zacht verwijderen (verplaatst naar prullenbak, trekt deellinks in).
form_publishEen formulier publiceren zodat het reacties kan ontvangen. Idempotent.
workspace_listAlle workspaces weergeven die toegankelijk zijn via jouw token.
workspaceFolder_listMappen in een workspace weergeven.
formSubmission_listInzendingen voor een formulier weergeven met paginering. Bevat concepten op Pro en Business; Free toont alleen voltooide reacties.
fields_listDe veldsleutels weergeven die een aanvraag kan aanspreken op een gepubliceerd formulier, elk met het waardetype, de optiesleutels en een usage-regel. Roep dit aan vóór request_create.
request_createEen gepubliceerd formulier toewijzen aan één met naam genoemde ontvanger: prefill, vergrendelde velden, context, bezorging, verval, en een optionele callback.
request_getEén aanvraag lezen: status, tijdlijn, en — eenmaal voltooid — antwoorden geordend per veldsleutel, plus display.
request_listAanvragen weergeven voor een formulier of een hele workspace, gefilterd op status, outcome, of je eigen external id.
editor_getDocumentDe volledige documentstructuur van een formulier ophalen: alle elementen, hun typen en eigenschappen.
editor_updateElementEen bestaand formulierelement bewerken: de tekst vervangen, eigenschappen wijzigen (titel, verplicht, enz.) of het element verplaatsen.
editor_deleteElementEen element uit het formulier verwijderen.
editor_insertTextQuestionEen korte of lange tekstvraag invoegen. Elk vraagtype heeft zijn eigen invoeg-tool met een nauwkeurig schema.
editor_insertContactQuestionEen e-mail-, telefoonnummer- of website-URL-vraag invoegen.
editor_insertNumberQuestion · editor_insertDateQuestionEen getal- of datumvraag invoegen.
editor_insertRadioQuestion · editor_insertCheckboxQuestion · editor_insertSelectQuestionEnkelvoudige keuze (radio), meervoudige keuze (checkbox) of dropdown-vragen invoegen.
editor_insertDecisionQuestionDe beslissingsvraag invoegen: de keuze goedkeuren / afwijzen / wijzigen waarvan het antwoord een aanvraaguitkomst wordt. Een met de hand gebouwde radio-vraag levert er nooit een op.
editor_insertRatingQuestion · editor_insertLinearScaleQuestionEen sterrenbeoordeling of lineale schaalvraag invoegen.
editor_insertHeader · editor_insertParagraph · editor_insertImage · editor_insertPageDividerNiet-vraag-inhoud invoegen: koppen, alinea's, afbeeldingen en pagina-einden.
load_toolsDocumentatie laden voor een toolcatalogus. Geeft schema's en gebruikspatronen terug voor gegroepeerde tools.
load_skillEen domeinkennis-gids laden (thema's, vraagtypen, logica-regels, enz.).

Meer invoegvarianten — tijd, bestandsupload, handtekening, betaling, matrix/raster, rangschikking, afbeeldingskeuze, schakelaar, tabel, lijst, rij, berekend veld, verborgen veld, inline variabele, ingesloten inhoud (editor_insertEmbedded voor YouTube, Google Maps of iframe-insluitingen) en een conditioneel-logicablok (editor_insertLogic) — staan ook op tools/list. Laad load_skill(“question-types”) voor de volledige set, elk met zijn toolnaam en velden. Conditionele logica wordt geschreven met editor_setLogic in de editor-actions catalogus.

Toolcatalogi

Deze tools staan ook op tools/list. Voer load_tools uit met een catalogusnaam voor verrijkte documentatie (intro, volledige schema’s, gebruikspatronen, randgevallen) voor de gegroepeerde tools, en roep ze daarna direct aan.

CatalogusInbegrepen tools
form-dataformAnalytics_get — geaggregeerde statistieken (weergaven, inzendingen, voltooiingspercentage, uitsplitsingen per apparaat, land, browser, bron). Vereist het Pro- of Business-plan; zonder dat mislukt de aanroep met een melding die het plan noemt.
form-appearanceformTheme_get, formTheme_set, form_update — thema's per modus (licht en donker), plus de omslagafbeelding en het logo via form_update.
form-behaviorformSettings_get, formSettings_update — meldingsemails, omleidingen bij voltooiing, wachtwoord, bewaring, taal, betaling.
form-sharingformShareLink_list, formShareLink_create, formShareLink_update — CRUD voor deellinks met ondersteuning voor aangepaste domeinen.
form-translationstranslationLanguage_list, translationDraft_get, translationDraft_update, translationDraft_publish, translationLanguage_delete — meertalige concept-dan-publiceer-workflow. Een leeg concept publiceren is de enige manier om een taal te depubliceren.
form-lifecycleform_unpublish, form_restore — levenscyclusoperaties naast de kernacties publiceren en verwijderen.
workspace-managementworkspaceFolder_create, workspaceFolder_update, workspaceFolder_delete — folder CRUD naast de kern-lijstwerkwoorden.
editor-actionseditor_formatText, editor_setLogic, editor_testLogic — tekstopmaak, conditionele-logica-schrijven en logicasimulatie.
request-lifecyclefields_list, request_create, request_get, request_list, request_cancel, request_remind, request_replayCallback, document_create — het hele aanvraagoppervlak: trek een aanvraag in behandeling in, herinner de ontvanger, speel een callback af die nooit aankwam, reserveer een upload voor één aanvraag.
editor-insertsDe lange staart van editor_insert*-tools: tijd, schakelaar, bestand, handtekening, documentenblok, matrix, rangschikking, betaling, afspraak, afbeeldingskeuze, ingesloten inhoud, tabel, lijst, rij, berekend veld, verborgen veld, herhalende groep, logica en variabele.

De catalogus request-lifecycle vermeldt alle acht aanvraagtools omdat de in-app chat een kleinere kernset adverteert. Via dit endpoint staan alle acht al op tools/list, dus wat de catalogus toevoegt is documentatie.

Skills (domeinkennis)

Skills zijn ingebouwde gidsen die de agent kan laden via load_skill. Ze bieden domeinkennis die de agent helpt betere beslissingen te nemen — geen toolschema’s, maar ontwerpadvies en veldsemantiek.

SkillWat het behandelt
question-typesElk vraagtype, de bijbehorende velden en wanneer je elk type gebruikt.
logic-rulesConditionele logica: operators, acties, combinatoren en randgevallen.
editing-flowsPatronen voor het bouwen van formulieren: volgorde, pagina-einden, piping.
form-best-practicesUX-richtlijnen voor effectief formulierontwerp.
form-themesThemastructuur, tokenreferentie en stijlrichtlijnen.
form-settingsInstellingenreferentie: meldingen, e-mailsjablonen, variabelen.
analyticsMetrieken-definities en hoe je formulieranalytics interpreteert.
toon-formatCompact uitvoerformaat voor gestructureerde gegevensweergave.
requestsAanvragen van begin tot eind: veldsleutels, vormen van prefill-waarden, bezorging, aanvraag-specifieke documenten, callbacks, pollen, en foutherstel.

Aanvragen

Een aanvraag wijst één gepubliceerd formulier toe aan één met naam genoemde ontvanger, met zijn eigen link, zijn eigen vooraf ingevulde antwoorden, en zijn eigen uitkomst. Het is hoe een agent een echt persoon om iets vraagt en te weten komt wat die persoon heeft gezegd.

Een aanvraag maken

Begin altijd met fields_list(formId). Het geeft de aanspreekbare sleutels van de huidige gepubliceerde versie van het formulier terug, elk met een usage-regel die aangeeft in welk argument de sleutel thuishoort — zichtbare vragen gaan in prefill, verborgen velden in context. Leid nooit een sleutel af van een vraagtitel, en lees opnieuw na form_publish.

request_create
json
{
  "formId": "j57...",
  "recipient": { "email": "ada@acme.com", "name": "Ada" },
  "prefill": { "company_name": "Acme", "plan": "pro" },
  "readonly": ["company_name"],
  "context": { "crm_id": "A-42" },
  "metadata": { "run_id": "exec_918" },
  "delivery": "email",
  "expiresAt": 1780000000000,
  "callbackUrl": "https://hooks.acme.com/formbase",
  "idempotencyKey": "po-42"
}

Het resultaat bevat de link en de klok:

result
json
{
  "id": "kd7...",
  "status": "pending",
  "url": "https://form.formbase.so/r/rq_...",
  "deliveryStatus": "queued",
  "expiresAt": 1780000000000,
  "createdAt": 1747000000000,
  "deduplicated": false,
  "next": "..."
}

delivery staat standaard op “none”, wat je url geeft om zelf af te leveren; “email” verstuurt de uitnodiging en vereist recipient.email op een Pro- of Business-abonnement, of een van de 10 gratis uitnodigingen van een Free-account. readonly vergrendelt velden die de ontvanger niet mag bewerken, en elke vergrendelde sleutel moet ook vooraf zijn ingevuld. context accepteert alleen sleutels van verborgen velden, terwijl metadata ondoorzichtige administratie is die wordt teruggegeven op request_get en in de callback. expiresAt is in epoch-milliseconden, standaard 30 dagen vooruit en met een maximum van 365 dagen. idempotencyKey is 30 dagen geldig binnen de werkruimte: dezelfde sleutel met dezelfde body geeft de oorspronkelijke aanvraag terug met deduplicated: true, en een andere body is een conflict. Elke response bevat ook een next-regel die de agent vertelt wat hij hierna moet doen.

deliveryStatus is not_requested tot een uitnodiging in de wachtrij staat, dan queued → sent of failed, en bounced zodra de mailprovider een harde bounce of een klacht meldt. Een aanvraag aanmaken verbruikt één eenheid van de maandelijkse toewijzing van de werkruimte, ongeacht of de ontvanger ooit antwoordt; zodra die op is, faalt request_create met MONTHLY_ALLOWANCE_REACHED.

Callbacks of pollen

Met een callbackUrl post formbase één keer per eindgebeurtenis — voltooiing, verlopen, annulering — ondertekend met het request signing secret van de werkruimte. Zie Callbacks & ondertekening voor de payload en het verificatierecept.

Autonome agents moeten pollen

Het request signing secret verschijnt alleen ooit op de pagina met inloggegevens van je werkruimte — het wordt nooit teruggegeven via MCP of de API. Een agent die op zichzelf draait, zonder mens om een ontvanger op te zetten en te configureren, kan daarom geen callback verifiëren. Laat callbackUrl weg en poll in plaats daarvan request_get(requestId), in de orde van minuten in plaats van seconden, tot status niet meer “pending” is. expiresAt begrenst hoelang dat de moeite waard is.

Testmodus

Geef test: true op om de hele opzet te repeteren vóór een echte run. De link opent nog steeds en kan worden afgerond, en de callback vuurt met “test”: true — maar er wordt niets gemaild wat delivery ook zegt, de aanvraag blijft verborgen voor de pagina Aanvragen en de analytics-funnel, en de inzending telt nergens mee: geen quotum, geen exports, geen integraties. Testaanvragen verschijnen alleen in request_list als je includeTest: true opgeeft. De link sluit binnen 24 uur, en op Free mag een workspace 10 testaanvragen per dag aanmaken.

Documenten per aanvraag

Om één ontvanger een bestand te geven — een conceptcontract, hun eigen offerte — heeft het formulier een Documentenblok nodig, dat een auteur of een agent invoegt met editor_insertDocumentsBlock. fields_list rapporteert het als type: “documents”. De bytes reizen nooit via een tool:

  1. Roep document_create aan met formId, name, contentType, en de exacte size in bytes. Je krijgt { id, name, contentType, size, uploadUrl, expiresAt } terug. Alleen PDF en afbeeldingen (geen Office-documenten), 25 MB per bestand, en 100 MB aan documenten per aanvraag.

  2. PUT de ruwe bytes naar uploadUrl binnen het uur, met Content-Type ingesteld op het type dat je hebt opgegeven.

  3. Verwijs ernaar vanuit request_create: documents: [{ documentId, field?, name? }]. field is de veldsleutel van het Documentenblok, alleen optioneel wanneer het formulier precies één zo’n blok heeft. name overschrijft de weergavenaam voor deze aanvraag.

De aangeleverde documenten van het blok blijven staan en die van jou verschijnen eronder, alleen voor deze ontvanger. request_create verifieert de upload voordat de aanvraag bestaat, dus DOCUMENT_NOT_UPLOADED betekent dat stap 2 is overgeslagen. Eén upload kan door elk aantal aanvragen worden gerefereerd, en de bytes tellen mee voor je werkruimteopslag.

Aangepaste domeinen

Geef domainId mee aan request_create om de link te genereren op een van de aangepaste domeinen van de werkruimte. De ids komen van formShareLink_list, dat ze teruggeeft als availableCustomDomains. Laat je het weg, dan neemt de link het domein waaronder het formulier al is gepubliceerd.

Resultaten lezen

request_get geeft de hele aanvraag terug. Zodra deze is voltooid, bevat answers de waarden van de ontvanger, geordend per veldsleutel, bevat display dezelfde sleutels als leesbare tekst, en is outcome — goedkeuren, afwijzen of wijzigen — hun oordeel wanneer het formulier een beslissingsvraag heeft. Een callbackFailedAt-tijdstempel betekent dat de bezorging geen pogingen meer over had en niets je endpoint bereikte; herstel de ontvanger en roep dan request_replayCallback aan, die het oorspronkelijke event-id opnieuw verstuurt zodat jouw ontvanger dedupliceert in plaats van opnieuw uit te voeren. Nadat het bewaarbeleid van het formulier een aanvraag verwijdert, wordt dataPurgedAt ingesteld en zijn de antwoorden definitief verdwenen.

request_list haalt er in één keer veel op, gefilterd op status, outcome, externalId, en includeTest. Pagineer met nextCursor: een pagina kan zelden terugkomen met een lege items en hasMore: true, wat niet het einde van de lijst is — geef de cursor terug en ga door.

Resources en prompts

Elke skill en toolcatalogus is ook een MCP-resource op skill://<name> — skill://requests, skill://editor-inserts. Een client die resources/list ondersteunt, kan ze doorbladeren en lezen zonder load_skill of load_tools aan te roepen. De server serveert ook vier prompts op prompts/list: identity, capabilities, data_tools, en editor_tools.

Tools die eerst bevestiging vragen

Elke tool draagt de MCP-hints readOnlyHint en destructiveHint, afgeleid van het werkwoord. Deze tools zijn gemarkeerd als destructief, omdat ze ongedaan maken een extra aanroep vergt of niet mogelijk is: form_delete, form_unpublish, workspaceFolder_delete, editor_deleteElement, translationLanguage_delete, en request_cancel. De meeste clients vragen de gebruiker om bevestiging voordat ze deze uitvoeren, maar die prompt is de keuze van de client, dus controleer de goedkeuringsinstellingen ervan als je een harde stop nodig hebt.

Beperkingen

  • Geen binaire uploads via een tool-aanroep. Afbeeldingen worden ingesteld via URL: omslagen, logo’s en afbeeldingsblokken accepteren http(s)://- of data:image-URI’s. Een document per aanvraag is de uitzondering: document_create geeft een upload-URL terug waar een client met HTTP-toegang het bestand naartoe kan PUTen (zie Documenten per aanvraag). Om een PDF of screenshot om te zetten in een formulier, gebruik je de ingebouwde AI-chat.

  • Geen werkruimte-AI-vaardigheden. Vaardigheden geschreven in formbase zijn alleen beschikbaar in de ingebouwde AI-chat. De eigen skills van de server (load_skill) zijn wel beschikbaar via MCP.

Verbinden met een API-token

De meeste clients loggen in via OAuth: voeg de URL toe zonder header en volg Een AI-agent met formbase verbinden. Een client die geen browser kan openen, zoals een script, CI-taak of headless agent, stuurt in plaats daarvan een API-token mee als header.

Claude Code, vanaf de command line:

bash
claude mcp add --transport http formbase https://api.formbase.so/api/mcp \
  --header "Authorization: Bearer fb_YOUR_TOKEN"

Of in het .mcp.json-bestand van een project:

.mcp.json
json
{
  "mcpServers": {
    "formbase": {
      "type": "http",
      "url": "https://api.formbase.so/api/mcp",
      "headers": {
        "Authorization": "Bearer fb_YOUR_TOKEN"
      }
    }
  }
}

Cursor, in .cursor/mcp.json of ~/.cursor/mcp.json:

mcp.json
json
{
  "mcpServers": {
    "formbase": {
      "url": "https://api.formbase.so/api/mcp",
      "headers": {
        "Authorization": "Bearer fb_YOUR_TOKEN"
      }
    }
  }
}

Om in te loggen met OAuth in plaats van met een token, gebruik je

Toevoegen aan Cursor

. Dit voegt de server-URL toe zonder header, en Cursor vraagt je om in te loggen bij formbase.

Andere clients gebruiken dezelfde URL en header; raadpleeg hun documentatie voor waar.

OAuth gebruiken in plaats van API-tokens

Een app van een derde partij die namens een gebruiker verbinding maakt, moet OAuth gebruiken in plaats van om een geplakt token te vragen. formbase is een OAuth 2.1-autorisatieserver met verplichte PKCE (S256) en ondoorzichtige tokens — geen JWT’s, geen implicit grant. Claude desktop, Claude Code en de Claude.ai-webconnector ontdekken dit allemaal via het MCP-endpoint, dus alleen de URL plakken zonder header volstaat: de 401 wijst naar /.well-known/oauth-protected-resource, en de client neemt het vanaf daar over.

De flow, voor een client die je zelf schrijft:

  1. GET /.well-known/oauth-protected-resource, dan GET /.well-known/oauth-authorization-server voor de endpoint-URL’s, scopes en ondersteunde authenticatiemethoden.

  2. POST /oauth/register met jouw redirect_uris (dynamische clientregistratie, geen inloggegevens nodig). Je krijgt een client_id, plus een client_secret als je iets anders opgaf dan token_endpoint_auth_method: “none”. Redirect-URI’s moeten HTTPS zijn, of HTTP op localhost. Registratie is beperkt tot 20 per uur per IP.

  3. Stuur de gebruiker naar /oauth/authorize met response_type=code, jouw client_id, de geregistreerde redirect_uri, scope=mcp:read mcp:write offline_access, state, en een code_challenge met code_challenge_method=S256. Ze loggen in, kiezen één werkruimte, en autoriseren.

  4. Wissel de code in bij POST /oauth/token met grant_type=authorization_code en jouw code_verifier, binnen 60 seconden. Codes zijn eenmalig te gebruiken.

  5. Roep het MCP-endpoint aan met Authorization: Bearer fbo_…. Toegangstokens gelden 1 uur; refreshtokens gelden 30 dagen en roteren bij elk gebruik. Een gebruikt refreshtoken opnieuw gebruiken verbrandt de hele keten, dus bewaar het nieuwste.

POST /oauth/revoke (RFC 7009) trekt een toegangs- of refreshtoken in. Een gebruiker kan ook de hele app verbreken via Verbonden apps op de pagina OAuth en API-sleutels, wat elk token van die app voor die werkruimte tenietdoet.

Heb je wel al een token in handen, dan gaat het op dezelfde plek als een API-sleutel:

MCP config with OAuth token
json
{
  "mcpServers": {
    "formbase": {
      "type": "http",
      "url": "https://api.formbase.so/api/mcp",
      "headers": {
        "Authorization": "Bearer fbo_USER_OAUTH_TOKEN"
      }
    }
  }
}

Verbonden apps

Elke OAuth-verbinding staat vermeld onder Verbonden apps op de pagina OAuth en API-sleutels, met wanneer die tot stand kwam en voor het laatst is gebruikt. Verbindingen zijn persoonlijk: alleen de gebruiker die er een heeft geautoriseerd ziet hem, en werkruimtebeheerders kunnen die van een ander lid niet bekijken of intrekken. Verbreken werkt onmiddellijk. Een gebruiker die de werkruimte verlaat of eruit wordt verwijderd, verliest al zijn verbindingen ermee.

Volgende stappen