Développeurs
Serveur MCP
Le serveur Model Context Protocol (MCP) permet aux agents IA de lire et de modifier vos formulaires formbase grâce à des outils riches et pilotés par schéma.
Qu’est-ce que c’est
MCP est un standard ouvert permettant aux outils IA de se connecter à des services externes. formbase expose un point de terminaison MCP hébergé auquel tout client compatible MCP peut se connecter, notamment Claude Code, Claude desktop et Cursor.
Connexion
URL: https://api.formbase.so/api/mcp (POST, streamable HTTP)
Auth: Bearer <token>Deux types de token porteur (bearer) fonctionnent :
Token API (
fb_…) — créé depuis les tokens API. Idéal pour un usage personnel et une configuration rapide.Token d’accès OAuth (
fbo_…) — émis par le flux OAuth. Idéal pour les applications tierces qui se connectent au nom d’un utilisateur.
Les deux sont liés à exactement un espace de travail et atteignent les mêmes outils. Un appel d’outil qui nomme un autre espace de
travail, ou un formulaire qui s’y trouve, échoue avec FORBIDDEN. Les tokens OAuth portent aussi des portées
mcp:read, mcp:write et offline_access, mais aucun outil n’est aujourd’hui conditionné par elles —
traitez tout token comme un accès complet à l’intérieur de son espace de travail.
Les appels d’outils sont limités à 120 par minute et par token, en commun avec l’API : seul
tools/call consomme ce budget, tandis que initialize, tools/list, prompts/ et
sont gratuits. Au-delà du budget, l’appel renvoie tout de même HTTP 200 avec un résultat d’outil en échec portant
resources/RATE_LIMITED et un retryAfterMs — sondez sur une minuterie, jamais en boucle.
Où obtenir un token
Ouvrez OAuth et clés API dans la barre latérale de votre espace de travail pour créer des tokens API et consulter les applications OAuth connectées. Consultez les tokens API pour un guide pas à pas.
Outils principaux
Chaque outil est annoncé sur tools/list lorsqu’un client se connecte. Les clients qui chargent les schémas à la demande,
comme Claude Code, récupèrent le schéma complet d’un outil quand une tâche en a besoin. Le tableau ci-dessous couvre les outils principaux
par lesquels la plupart des tâches commencent ; load_tools (catalogues) et load_skill (guides métier)
documentent le reste.
| Outil | Ce qu’il fait |
|---|---|
| form_list | Lister les formulaires dans un espace de travail. Prend en charge le filtre par dossier, la recherche floue par nom et la pagination par curseur. |
| form_get | Obtenir les détails complets d’un formulaire : questions, couverture, logo et une URL d’aperçu en direct. |
| form_create | Créer un nouveau formulaire vide dans un espace de travail. Retourne une URL d’aperçu pour l’édition en direct. |
| form_update | Mettre à jour les métadonnées d’un formulaire : nom, dossier, emoji, couverture ou logo. |
| form_delete | Suppression douce d’un formulaire (déplace vers la corbeille, révoque les liens de partage). |
| form_publish | Publier un formulaire pour qu’il puisse accepter des réponses. Idempotent. |
| workspace_list | Lister tous les espaces de travail accessibles par votre token. |
| workspaceFolder_list | Lister les dossiers dans un espace de travail. |
| formSubmission_list | Lister les soumissions d’un formulaire avec pagination. Inclut les brouillons sur Pro et Business ; Free ne liste que les réponses complètes. |
| fields_list | Liste les clés de champ qu’une demande peut adresser sur un formulaire publié, chacune avec son type de valeur, les clés d’options, et une ligne d’utilisation. À appeler avant request_create. |
| request_create | Assigne un formulaire publié à un destinataire nommé : préremplissage, champs verrouillés, contexte, livraison, expiration, et un callback optionnel. |
| request_get | Lit une demande : statut, chronologie, et — une fois terminée — les réponses indexées par clé de champ, plus display. |
| request_list | Liste les demandes d’un formulaire ou de tout un espace de travail, filtrées par statut, résultat, ou votre propre id externe. |
| editor_getDocument | Obtenir la structure complète du document d’un formulaire : tous les éléments, leurs types et propriétés. |
| editor_updateElement | Modifier un élément de formulaire existant : remplacer son texte, changer ses propriétés (titre, obligatoire, etc.) ou le repositionner. |
| editor_deleteElement | Supprimer un élément du formulaire. |
| editor_insertTextQuestion | Insérer une question de texte court ou long. Chaque type de question possède son propre outil d’insertion avec un schéma précis. |
| editor_insertContactQuestion | Insérer une question d’email, de numéro de téléphone ou d’URL de site web. |
| editor_insertNumberQuestion · editor_insertDateQuestion | Insérer une question de nombre ou de date. |
| editor_insertRadioQuestion · editor_insertCheckboxQuestion · editor_insertSelectQuestion | Insérer des questions à choix unique (radio), à choix multiple (case à cocher) ou à liste déroulante. |
| editor_insertDecisionQuestion | Insérer la question de décision : le choix approuver / refuser / demander des modifications dont la réponse devient le résultat d’une demande. Un bouton radio construit à la main n’en produit jamais un. |
| editor_insertRatingQuestion · editor_insertLinearScaleQuestion | Insérer une question d’évaluation par étoiles ou d’échelle linéaire. |
| editor_insertHeader · editor_insertParagraph · editor_insertImage · editor_insertPageDivider | Insérer du contenu non-question : titres, paragraphes, images et sauts de page. |
| load_tools | Charger la documentation d’un catalogue d’outils. Retourne les schémas et les patterns d’utilisation pour les outils groupés. |
| load_skill | Charger un guide de connaissances métier (thèmes, types de questions, règles de logique, etc.). |
D’autres variantes d’insertion — heure, téléchargement de fichier, signature, paiement, matrice/grille, classement, choix d’image, bouton
bascule, tableau, liste, ligne, champ calculé, champ masqué, variable en ligne, contenu intégré (editor_insertEmbedded pour
YouTube, Google Maps ou des intégrations iframe) et un bloc de logique conditionnelle (editor_insertLogic) — sont aussi sur
tools/list. Chargez load_skill(“question-types”) pour l’ensemble complet, avec le nom de l’outil et les champs
de chacun. La logique conditionnelle s’écrit avec editor_setLogic dans le catalogue
editor-actions.
Catalogues d’outils
Ces outils sont aussi sur tools/list. Exécutez load_tools avec un nom de catalogue pour obtenir une
documentation enrichie (introduction, schémas complets, patterns d’utilisation, cas limites) pour les outils groupés, puis appelez-les
directement.
| Catalogue | Outils inclus |
|---|---|
| form-data | formAnalytics_get — métriques agrégées (vues, soumissions, taux de complétion, répartitions par appareil, pays, navigateur, source). Nécessite le plan Pro ou Business ; sans lui, l’appel échoue avec un message qui nomme le plan. |
| form-appearance | formTheme_get, formTheme_set, form_update — thèmes par mode (clair et sombre), plus la couverture et le logo sur form_update. |
| form-behavior | formSettings_get, formSettings_update — notifications par email, redirection après complétion, mot de passe, rétention, langue, paiement. |
| form-sharing | formShareLink_list, formShareLink_create, formShareLink_update — CRUD des liens de partage avec prise en charge des domaines personnalisés. |
| form-translations | translationLanguage_list, translationDraft_get, translationDraft_update, translationDraft_publish, translationLanguage_delete — flux de travail multilingue brouillon puis publication. Publier un brouillon vide est le seul moyen de dépublier une langue. |
| form-lifecycle | form_unpublish, form_restore — opérations de cycle de vie au-delà de la publication et suppression principales. |
| workspace-management | workspaceFolder_create, workspaceFolder_update, workspaceFolder_delete — CRUD des dossiers au-delà des verbes de liste principaux. |
| editor-actions | editor_formatText, editor_setLogic, editor_testLogic — mise en forme du texte, création de logique conditionnelle et simulation de logique. |
| request-lifecycle | fields_list, request_create, request_get, request_list, request_cancel, request_remind, request_replayCallback, document_create — toute la surface des demandes : retirer une demande en attente, relancer le destinataire, rejouer un callback qui n’est jamais arrivé, réserver un téléversement de document par demande. |
| editor-inserts | La longue traîne des outils editor_insert* : heure, interrupteur, fichier, signature, bloc Documents, matrice, classement, paiement, rendez-vous, choix d’image, contenu intégré, tableau, liste, ligne, champ calculé, champ masqué, groupe répétable, logique et variable. |
Le catalogue request-lifecycle liste les huit outils de demandes car le chat intégré annonce un ensemble principal plus
restreint. Sur ce point de terminaison, les huit sont déjà sur tools/list, donc ce que le catalogue ajoute, c’est la
documentation.
Compétences (connaissances métier)
Les compétences sont des guides intégrés que l’agent peut charger via load_skill. Elles fournissent des connaissances métier
qui aident l’agent à prendre de meilleures décisions — pas des schémas d’outils, mais des conseils de conception et la sémantique des
champs.
| Compétence | Ce qu’elle couvre |
|---|---|
| question-types | Chaque type de question, ses champs et quand utiliser chacun. |
| logic-rules | Logique conditionnelle : opérateurs, actions, combinateurs et cas limites. |
| editing-flows | Schémas pour construire des formulaires : ordre, sauts de page, piping. |
| form-best-practices | Recommandations UX pour une conception de formulaire efficace. |
| form-themes | Structure des thèmes, référence des tokens et directives de style. |
| form-settings | Référence des paramètres : notifications, modèles d’email, variables. |
| analytics | Définitions des métriques et comment interpréter les analytiques des formulaires. |
| toon-format | Format de sortie compact pour l’affichage de données structurées. |
| requests | Les demandes de bout en bout : clés de champ, formes de valeur de préremplissage, livraison, documents par demande, callbacks, sondage, et récupération d’erreurs. |
Demandes
Une demande assigne un formulaire publié à un destinataire nommé, avec son propre lien, ses propres réponses préremplies, et son propre résultat. C’est ainsi qu’un agent demande quelque chose à une personne réelle et découvre ce qu’elle a répondu.
Créer une demande
Commencez toujours par fields_list(formId). Cela renvoie les clés adressables de la version actuellement publiée du
formulaire, chacune avec une ligne usage indiquant dans quel argument la clé doit aller — les questions visibles vont dans
prefill, les champs cachés dans context. Ne dérivez jamais une clé à partir du titre d’une question, et relisez
après form_publish.
{
"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"
}Le résultat contient le lien et l’horloge :
{
"id": "kd7...",
"status": "pending",
"url": "https://form.formbase.so/r/rq_...",
"deliveryStatus": "queued",
"expiresAt": 1780000000000,
"createdAt": 1747000000000,
"deduplicated": false,
"next": "..."
}delivery vaut “none” par défaut, ce qui vous donne url à livrer vous-même ; “email”
envoie l’invitation et nécessite recipient.email sur un plan Pro ou Business, ou sur l’une des 10 invitations gratuites d’un
compte Free. readonly verrouille des champs que le destinataire ne peut pas modifier, et toute clé verrouillée doit aussi
être préremplie. context n’accepte que des clés de champs cachés, tandis que metadata est un suivi opaque
renvoyé dans request_get et dans le callback. expiresAt est en millisecondes epoch, par défaut 30 jours et
plafonné à 365 jours. idempotencyKey est valable à l’échelle de l’espace de travail pendant 30 jours : la même clé avec le
même corps renvoie la demande d’origine avec deduplicated: true, et un corps différent est un conflit. Chaque réponse porte
aussi une ligne next qui indique à l’agent quoi faire ensuite.
deliveryStatus vaut not_requested jusqu’à ce qu’une invitation soit mise en file, puis queued →
sent ou failed, et bounced une fois que le fournisseur d’e-mail signale un rejet définitif ou une
plainte. Créer une demande dépense une unité de l’allocation mensuelle de l’espace de travail, que le destinataire réponde ou non ; une
fois épuisée, request_create échoue avec MONTHLY_ALLOWANCE_REACHED.
Callbacks ou sondage
Avec une callbackUrl, formbase envoie un POST une fois par événement terminal — complétion, expiration, annulation — signé
avec le secret de signature des demandes de l’espace de travail. Voir Callbacks et signature pour le
payload et la recette de vérification.
Les agents autonomes devraient sonder
Le secret de signature des demandes n’apparaît que sur la page Identifiants de votre espace de travail — il n’est jamais renvoyé via MCP
ou l’API. Un agent qui s’exécute seul, sans humain pour mettre en place et configurer un récepteur, ne peut donc pas vérifier un
callback. Omettez callbackUrl et sondez plutôt request_get(requestId), à l’échelle de quelques minutes plutôt
que de quelques secondes, jusqu’à ce que status quitte “pending”. expiresAt borne combien de
temps cela vaut la peine.
Mode test
Passez test: true pour répéter tout le circuit avant une exécution réelle. Le lien s’ouvre toujours et peut être complété, et
le callback se déclenche avec “test”: true — mais rien n’est envoyé par e-mail quoi que dise delivery, la
demande reste masquée de la page Demandes et de l’entonnoir analytique, et sa soumission ne compte nulle part : pas de quota, pas
d’exports, pas d’intégrations. Les demandes de test n’apparaissent dans request_list que si vous passez
includeTest: true. Le lien se ferme dans les 24 heures, et sur Free un workspace peut créer 10 demandes de test par jour.
Documents par demande
Pour remettre un fichier à un destinataire — un projet de contrat, son propre devis — le formulaire a besoin d’un
bloc Documents, qu’un auteur ou un agent insère avec editor_insertDocumentsBlock. fields_list
le signale comme type: “documents”. Les octets ne transitent jamais par un outil :
Appelez
document_createavecformId,name,contentType, et lesizeexact en octets. Vous récupérez{ id, name, contentType, size, uploadUrl, expiresAt }. PDF et images uniquement (pas de documents Office), 25 Mo par fichier, et 100 Mo de documents par demande.Faites un
PUTdes octets bruts versuploadUrldans l’heure, avecContent-Typeréglé sur le type déclaré.Référencez-le depuis
request_create:documents: [{ documentId, field?, name? }].fieldest la clé de champ du bloc Documents, optionnelle seulement quand le formulaire a exactement un bloc de ce type.nameremplace le nom d’affichage pour cette demande.
Les documents de l’auteur du bloc restent en place et les vôtres apparaissent en dessous, pour ce seul destinataire.
request_create vérifie le téléversement avant que la demande n’existe, donc DOCUMENT_NOT_UPLOADED signifie que
l’étape 2 a été sautée. Un téléversement peut être référencé par un nombre quelconque de demandes, et ses octets comptent dans le stockage
de votre espace de travail.
Domaines personnalisés
Passez domainId à request_create pour créer le lien sur l’un des
domaines personnalisés de l’espace de travail. Les ids viennent de
formShareLink_list, qui les renvoie sous availableCustomDomains. Si vous l’omettez, le lien prend le domaine sur
lequel le formulaire est déjà publié.
Lire les résultats
request_get renvoie la demande entière. Une fois terminée, answers contient les valeurs du destinataire indexées
par clé de champ, display les mêmes clés en texte lisible, et outcome — approbation, refus ou modifications —
est son verdict quand le formulaire a une question de décision. Un horodatage
callbackFailedAt signifie que la livraison a épuisé ses tentatives et que rien n’a atteint votre endpoint ; réparez le
récepteur, puis appelez request_replayCallback, qui renvoie l’id de l’événement d’origine pour que votre récepteur déduplique
au lieu de relancer. Une fois que la politique de rétention du formulaire a supprimé une demande, dataPurgedAt est défini et
les réponses sont perdues pour de bon.
request_list balaie plusieurs demandes à la fois, filtrées par status, outcome,
externalId, et includeTest. Paginez avec nextCursor : une page peut rarement revenir avec des
items vides et hasMore: true, ce qui ne marque pas la fin de la liste — renvoyez le curseur et continuez.
Ressources et prompts
Chaque compétence et catalogue d’outils est aussi une ressource MCP à skill://<nom> — skill://requests,
skill://editor-inserts. Un client qui prend en charge resources/list peut les parcourir et les lire sans appeler
load_skill ou load_tools. Le serveur sert aussi quatre prompts sur prompts/list :
identity, capabilities, data_tools, et editor_tools.
Les outils qui demandent d’abord confirmation
Chaque outil porte les indices MCP readOnlyHint et destructiveHint, dérivés de son verbe. Ces outils sont
marqués comme destructifs, car les annuler nécessite un autre appel ou n’est pas possible : form_delete,
form_unpublish, workspaceFolder_delete, editor_deleteElement,
translationLanguage_delete, et request_cancel. La plupart des clients demandent une confirmation à l’utilisateur
avant de les exécuter, mais l’invite reste la décision du client — vérifiez ses paramètres d’approbation si vous avez besoin d’un blocage
strict.
Limites
Aucun téléversement binaire via un appel d’outil. Les images sont définies par URL : couvertures, logos et blocs image acceptent des URI
http(s)://oudata:image. Un document par demande fait exception :document_createrenvoie une URL de téléversement qu’un client avec accès HTTP peut cibler avecPUT(voir Documents par demande). Pour transformer un PDF ou une capture d’écran en formulaire, utilisez le chat IA intégré.Aucune compétence IA d’espace de travail. Les compétences écrites dans formbase ne sont disponibles que dans le chat IA intégré. Les compétences propres au serveur (
load_skill) sont disponibles via MCP.
Se connecter avec un token API
La plupart des clients se connectent avec OAuth : ajoutez l’URL sans en-tête et suivez Connecter un agent IA. Un client qui ne peut pas ouvrir de navigateur, comme un script, un job CI ou un agent headless, envoie plutôt un token API en en-tête.
Claude Code, en ligne de commande :
claude mcp add --transport http formbase https://api.formbase.so/api/mcp \
--header "Authorization: Bearer fb_YOUR_TOKEN"Ou dans le .mcp.json d’un projet :
{
"mcpServers": {
"formbase": {
"type": "http",
"url": "https://api.formbase.so/api/mcp",
"headers": {
"Authorization": "Bearer fb_YOUR_TOKEN"
}
}
}
}Cursor, dans .cursor/mcp.json ou ~/.cursor/mcp.json :
{
"mcpServers": {
"formbase": {
"url": "https://api.formbase.so/api/mcp",
"headers": {
"Authorization": "Bearer fb_YOUR_TOKEN"
}
}
}
}Pour vous connecter avec OAuth plutôt qu’avec un token, utilisez
Ajouter à Cursor
. Cela ajoute l’URL du serveur sans en-tête, et Cursor vous demande de vous connecter à formbase.
Les autres clients prennent la même URL et le même en-tête ; consultez leur documentation pour savoir où les placer.
Utiliser OAuth plutôt que des tokens API
Une application tierce qui se connecte au nom d’un utilisateur devrait utiliser OAuth plutôt que de demander un token collé à la main.
formbase est un serveur d’autorisation OAuth 2.1 avec PKCE obligatoire (S256) et des tokens opaques — pas de JWT, pas de grant implicite.
Claude desktop, Claude Code et le connecteur web Claude.ai découvrent tout cela depuis le point de terminaison MCP, donc coller l’URL sans
en-tête suffit : le 401 pointe vers /.well-known/oauth-protected-resource, et le client prend le relais à partir de là.
Le flux, pour un client que vous écrivez vous-même :
GET /.well-known/oauth-protected-resource, puisGET /.well-known/oauth-authorization-serverpour les URLs des points de terminaison, les portées et les méthodes d’authentification prises en charge.POST /oauth/registeravec vosredirect_uris(enregistrement de client dynamique, aucun identifiant requis). Vous obtenez unclient_id, plus unclient_secretsi vous avez demandé autre chose quetoken_endpoint_auth_method: “none”. Les URIs de redirection doivent être en HTTPS, ou en HTTP surlocalhost. L’enregistrement est plafonné à 20 par heure et par IP.Envoyez l’utilisateur vers
/oauth/authorizeavecresponse_type=code, votreclient_id, leredirect_urienregistré,scope=mcp:read mcp:write offline_access,state, et uncode_challengeaveccode_challenge_method=S256. Il se connecte, choisit un espace de travail, et autorise.Échangez le code sur
POST /oauth/tokenavecgrant_type=authorization_codeet votrecode_verifier, dans les 60 secondes. Les codes sont à usage unique.Appelez le point de terminaison MCP avec
Authorization: Bearer fbo_…. Les tokens d’accès durent 1 heure ; les tokens de rafraîchissement durent 30 jours et tournent à chaque utilisation. Réutiliser un token de rafraîchissement déjà consommé brûle toute la chaîne, donc conservez le plus récent.
POST /oauth/revoke (RFC 7009) révoque un token d’accès ou de rafraîchissement. Un utilisateur peut aussi déconnecter toute
l’application depuis Applications connectées sur la page OAuth et clés API, ce qui tue tous les tokens qu’elle détient
pour cet espace de travail.
Si vous avez déjà un token en main, il va au même endroit qu’une clé API :
{
"mcpServers": {
"formbase": {
"type": "http",
"url": "https://api.formbase.so/api/mcp",
"headers": {
"Authorization": "Bearer fbo_USER_OAUTH_TOKEN"
}
}
}
}Applications connectées
Chaque connexion OAuth est listée sous Applications connectées sur la page OAuth et clés API, avec la date de connexion et de dernière utilisation. Les connexions sont personnelles : seul l’utilisateur qui a autorisé une connexion peut la voir, et les administrateurs de l’espace de travail ne peuvent ni la consulter ni la révoquer pour un autre membre. La déconnexion prend effet immédiatement. Un utilisateur qui quitte l’espace de travail ou en est retiré perd toutes ses connexions à celui-ci.