Tools
Every tool checks the token's abilities before running; missing the ability returns a refusal. The tables below cover the complete workspace surface area registered on the server (116 tools).
Plan visibility
tools/list, resources/list, and prompts/list are filtered by the authenticated team's plan. On Free, survey, funnel, webhook, and AI tools (and their matching resources/prompts) are omitted entirely - clients that only read the list will not see them. On Pro and above, the full catalogue is returned.
You can still mint token abilities for paid products on any plan; without the plan feature, those tools either never appear in the list or refuse at call time with a plan error.
| Plan | MCP products available |
|---|---|
| Free | Forms, submissions, links, automations, billing (read-only), tokens, framework catalog |
| Pro and above | Everything in Free + webhooks, surveys, funnels, AI insights |
Product routing
- Forms - single-screen contact-style forms. Use
create_form, notcreate_survey. - Surveys - multi-screen questionnaires, quizzes, NPS. Use
create_survey, notcreate_form. - Funnels - multi-step lead-gen with screens, blocks, scoring, pixels, CAPI. Use
create_funnel. - Links - branded short links and QR codes on every plan.
Call list_templates with product (form, survey, or funnel) before create_* when the user wants a starter. Pass the returned key as template on create_form, create_survey, or create_funnel.
Build a complete form, survey, or funnel in one call
set_form_document, set_survey_document, and set_funnel_document are the full authoring path. Each one builds a complete, styled product end-to-end from a single builder document - every field/question type, content blocks, conditional branching, welcome and ending screens, and styling - the same structure the visual builder saves. Prefer them over update_* (or add_screen / add_block) when you are laying out or restyling a product rather than patching one attribute.
Each create_* returns a public_id; pass it as form_id, survey_id, or funnel_id. Pass publish: true to make the result live in the same call.
Document shape
{
"builder": { "name": "Q4 NPS", "settings": { "display_mode": "one_per_screen", "progress": "bar" } },
"blocks": [ /* ordered screens / questions / content - see below */ ],
"theme_v2": { "tokens": { "color": { "primary": "#4f46e5" } } }
}
builder- the product name plus product-levelsettings(e.g. surveydisplay_mode/progress).blocks[]- the ordered content. Each block has anid, akind, and aposition. Aquestionblock carries one or moreelements(the input fields / content).welcome,ending_screen, andending_redirectblocks carry their copy inconfig. Ids and per-element config defaults are filled in when omitted.theme_v2- the unified styling envelope (colors, fonts, radius, spacing, …) undertokens. This is the canonical styling surface and round-trips with the visual Styling editor.update_*accepts the sametheme_v2when you only want to restyle.
Element vocabulary
The type on each element reaches the full builder palette:
open_text, multiple_choice_single, multiple_choice_multi, picture_selection, ranking, consent, file_upload, rating, nps, csat, ces, matrix, contact_info, cal, cta, timeslots, date, barcode, range_slider
Content blocks render without collecting a submission key: heading, paragraph (a statement, not a textarea input), html, divider. (A typed email input is an open_text element with config.format: "email".)
- Forms and surveys reject an unmapped
typewith a clear error (so a typo never silently drops a field). - Funnels never reject an unmapped type. Any type with no native funnel block (
nps,matrix,csat, …) degrades loss-free to an inerthtmlblock that preserves the original type, so layout and styling always save. Funnel screens that stack several inputs or advance buttons are auto-split one step per screen.
Conditional branching (logic)
Attach a logic rule graph to any question block to branch on an answer. then.action is goto / skip / next, and then.target is the id of the block to jump to (rewritten internally to the right screen):
"logic": {
"rules": [
{ "when": { "op": "and", "conditions": [ { "field": "score", "op": "lte", "value": 6 } ] },
"then": { "action": "goto", "target": "blk_reason" } }
],
"fallback": { "action": "next" }
}
Branching round-trips: re-saving a survey or funnel preserves the rules so a later edit never drops a jump.
Welcome and ending screens carry a body
Welcome and ending screens now support a multi-paragraph body alongside the headline and button_label. Author it with newline-separated paragraphs; the hosted page renders and themes each paragraph.
{ "id": "blk_welcome", "kind": "welcome", "position": 0,
"config": { "headline": "Hi there", "body": "Two minutes, promise.\n\nNo wrong answers.", "button_label": "Start" } }
Example: a survey with NPS, a branch, and a welcome body
set_survey_document {
"survey_id": "sv_8Qd2",
"publish": true,
"document": {
"builder": { "name": "Q4 NPS", "settings": { "display_mode": "one_per_screen", "progress": "bar" } },
"blocks": [
{ "id": "blk_welcome", "kind": "welcome", "position": 0,
"config": { "headline": "Hi there", "body": "Two minutes, promise.\n\nNo wrong answers.", "button_label": "Start" } },
{ "id": "blk_nps", "kind": "question", "position": 1,
"logic": { "rules": [ { "when": { "op": "and", "conditions": [ { "field": "score", "op": "lte", "value": 6 } ] }, "then": { "action": "goto", "target": "blk_reason" } } ], "fallback": { "action": "next" } },
"elements": [ { "type": "nps", "name": "score", "config": { "label": "How likely are you to recommend us?" } } ] },
{ "id": "blk_reason", "kind": "question", "position": 2,
"elements": [ { "type": "open_text", "name": "reason", "config": { "label": "What went wrong?", "long": true } } ] },
{ "id": "blk_email", "kind": "question", "position": 3,
"elements": [ { "type": "open_text", "name": "email", "config": { "label": "Email", "format": "email", "save_as_contact": true } } ] },
{ "id": "blk_end", "kind": "ending_screen", "position": 4,
"config": { "headline": "Thanks!", "body": "We appreciate it." } }
],
"theme_v2": { "tokens": { "color": { "primary": "#4f46e5" } } }
}
}
Example: a styled form in one call
set_form_document {
"form_id": "r2EdO-orF-3S",
"document": {
"builder": { "name": "Contact" },
"blocks": [
{ "id": "blk_welcome", "kind": "welcome", "position": 0, "config": { "headline": "Get in touch", "body": "We reply within a day." } },
{ "id": "blk_q", "kind": "question", "position": 1, "elements": [
{ "type": "heading", "config": { "text": "Your details", "level": "h2" } },
{ "type": "open_text", "name": "full_name", "config": { "label": "Full name", "required": true } },
{ "type": "open_text", "name": "email", "config": { "label": "Email", "format": "email", "required": true } },
{ "type": "rating", "name": "satisfaction", "config": { "label": "How was it?" } }
] },
{ "id": "blk_end", "kind": "ending_screen", "position": 2, "config": { "headline": "Thanks!" } }
],
"theme_v2": { "tokens": { "color": { "primary": "#0ea5e9" } } }
}
}
Example: a funnel - one block per screen
A funnel document uses one block per screen (a step); each screen's fields/content are its elements. Unmapped types degrade to html rather than failing.
set_funnel_document {
"funnel_id": "fn_lead_quiz",
"document": {
"builder": { "name": "Lead quiz" },
"blocks": [
{ "id": "blk_welcome", "kind": "welcome", "position": 0, "config": { "headline": "Find your plan", "body": "60 seconds." } },
{ "id": "blk_goal", "kind": "question", "position": 1,
"logic": { "rules": [ { "when": { "op": "and", "conditions": [ { "field": "goal", "op": "equals", "value": "pro" } ] }, "then": { "action": "goto", "target": "blk_pro" } } ], "fallback": { "action": "next" } },
"elements": [
{ "type": "heading", "config": { "text": "What's your goal?", "level": "h2" } },
{ "type": "multiple_choice_single", "name": "goal", "config": { "label": "Goal", "options": [ { "value": "starter", "label": "Starter" }, { "value": "pro", "label": "Pro" } ] } },
{ "type": "cta", "config": { "button_text": "Continue" } }
] },
{ "id": "blk_pro", "kind": "question", "position": 2,
"elements": [ { "type": "open_text", "name": "email", "config": { "label": "Work email", "format": "email", "required": true } } ] },
{ "id": "blk_end", "kind": "ending_screen", "position": 3, "config": { "headline": "Thanks!" } }
],
"theme_v2": { "tokens": { "color": { "primary": "#7c3aed" } } }
}
}
Per-entity captcha, scoring, and notifications
update_form, update_survey, and update_funnel now also set the surrounding configuration the document does not own:
- Captcha is always per-entity, never global. Set
hcaptcha_enabled/recaptcha_enabledplus the matching*_site_key/*_secreton the individual form, survey, or funnel. Leaving a secret empty keeps the existing key so an unrelated edit never wipes stored credentials. - Scoring (
scoring), hidden fields (hidden_fields, captured from URL params), notification emails (notification_emails), autoresponder (autoresponder), redirect (redirect_url), and the spam honeypot (honeypot_field).
Templates
| Tool | Ability | Description |
|---|---|---|
list_templates |
forms:read (form), surveys:read (survey), funnels:read (funnel) |
List starter templates; optional category and search filters. Survey and funnel products require a paid plan. |
Forms
| Tool | Ability | Description |
|---|---|---|
list_forms |
forms:read |
List active forms in the team |
get_form |
forms:read |
Fetch one form by public_id |
create_form |
forms:write |
Create a new form (optional template key from list_templates) |
update_form |
forms:write |
Patch name, slug, a full builder document (all field + content types + theme + welcome/ending), legacy fields, theme, settings, notification emails, autoresponder, redirect, honeypot, and per-form captcha |
set_form_document |
forms:write |
Build a complete, styled form in one call from a builder document. See Build in one call |
publish_form |
forms:write |
Set published_at = now() |
unpublish_form |
forms:write |
Clear published_at |
archive_form |
forms:write |
Soft-delete |
restore_form |
forms:write |
Reverse archive |
send_test_autoresponder |
forms:test-email |
Send preview autoresponder to your account email |
send_test_notification |
forms:test-email |
Send preview owner-notification |
Submissions
| Tool | Ability | Description |
|---|---|---|
list_submissions |
submissions:read |
Paginate, filter by folder |
get_submission |
submissions:read |
Fetch one with files |
update_submission |
submissions:write |
Patch payload or status |
delete_submission |
submissions:write |
Permanent delete + file cleanup |
bulk_submissions |
submissions:write |
Up to 500 ids: delete, mark_spam, mark_not_spam |
export_submissions |
submissions:export |
Inline JSON, up to 500 rows |
get_submission_file |
submissions:read |
Short-TTL signed URL |
mark_as_spam |
submissions:write |
Quick mark with reason manual:mcp |
get_form_stats |
submissions:read |
30-day totals, spam ratio, AI score average |
Webhooks
| Tool | Ability | Description |
|---|---|---|
list_webhooks |
webhooks:read |
Webhooks for a form, with delivery counts |
get_webhook |
webhooks:read |
Single webhook (no secret) |
create_webhook |
webhooks:write |
Returns plaintext signing secret ONCE |
update_webhook |
webhooks:write |
URL, label, active flag |
delete_webhook |
webhooks:write |
Remove |
list_webhook_deliveries |
webhooks:read |
Last 50 (configurable up to 200) |
replay_webhook_delivery |
webhooks:write |
Re-dispatch a previous delivery |
Surveys
Surveys are a separate product from Forms - multi-screen questionnaires, quizzes, and NPS flows with conditional logic. Never call create_form to make a survey, or create_survey to make a contact form. All survey tools require a paid plan.
| Tool | Ability | Description |
|---|---|---|
list_surveys |
surveys:read |
List surveys belonging to the current team |
get_survey |
surveys:read |
Fetch a single survey by public_id |
create_survey |
surveys:write |
Create a new survey (optionally from a template) |
update_survey |
surveys:write |
Update name, slug, redirect, a full builder document (all question types + branching logic + theme + welcome/ending), legacy fields, theme, settings, scoring, hidden fields, notification emails, autoresponder, and per-survey captcha |
set_survey_document |
surveys:write |
Build a complete, styled survey - questions, branching, theme - in one call from a builder document. See Build in one call |
publish_survey |
surveys:write |
Publish - make the survey live and respondable |
unpublish_survey |
surveys:write |
Return to draft, stop accepting responses |
delete_survey |
surveys:write |
Soft-delete (recoverable from the dashboard) |
get_survey_insights |
insights:read |
Read open-text AI insights (summary, sentiment, theme clustering) for a survey; returns { locked: true } when the plan lacks AI features |
regenerate_survey_insights |
insights:write |
Queue regeneration of a survey's open-text AI insights; optionally limit to one question by submission key. Idempotency-locked for 5 minutes |
Surveys capture CRM contacts from responses. A survey mints a contact whenever it has at least one typed email question. Capture is opt-in per email question via save_as_contact, which defaults on - set it false on a specific question (e.g. "your colleague's email") to opt that one out. Identity is read only from typed email / phone questions, never by scanning free-text answers. Set save_as_contact in the element config when building with set_survey_document.
Action classes
Action classes are the triggers that decide when an in-app or website survey fires - a code action fires from an SDK track(key) call, a noCode action auto-fires from a spec (page view, click, exit intent, scroll depth, dwell, with optional URL filters). A survey fires when any of its attached triggers fires. Part of the in-app / website survey suite; requires a paid plan.
| Tool | Ability | Description |
|---|---|---|
list_action_classes |
action-classes:read |
List action classes (survey triggers) for the current team |
get_action_class |
action-classes:read |
Fetch a single action class by public_id |
create_action_class |
action-classes:write |
Create a trigger; code actions fire from an SDK track(key) call, noCode actions auto-fire from a no_code_config spec (page view / click / exit intent / scroll / dwell with optional URL filters) |
update_action_class |
action-classes:write |
Update name, description, type, key, or no_code_config; partial payloads are last-write-wins |
delete_action_class |
action-classes:write |
Delete a trigger and its survey-trigger links; surveys simply stop firing on it. Queued |
attach_survey_trigger |
action-classes:write |
Attach a trigger to a survey (idempotent) |
detach_survey_trigger |
action-classes:write |
Detach a trigger from a survey (idempotent) |
Contacts
The CRM audience captured from in-app / website survey responses (and managed directly). A contact is identified by external_user_id and/or email; attributes merge last-write-wins. Requires a paid plan.
| Tool | Ability | Description |
|---|---|---|
list_contacts |
contacts:read |
List contacts belonging to the current team |
get_contact |
contacts:read |
Fetch a single contact by public_id, including its merged attributes |
create_contact |
contacts:write |
Create or upsert a contact (identified by external_user_id and/or email; attributes are merged) |
update_contact |
contacts:write |
Backfill identity (email / external_user_id) and merge attributes (last-write-wins) |
delete_contact |
contacts:write |
Erase a contact and its attributes; survey responses are de-identified, not deleted. Queued |
Segments
Segments are reusable survey audiences: each owns a recursive AND/OR filters tree over contact attributes, device class, and nested segment membership. A survey targets one segment. Part of the in-app / website survey suite; requires a paid plan.
| Tool | Ability | Description |
|---|---|---|
list_segments |
segments:read |
List segments (survey audiences) for the current team |
get_segment |
segments:read |
Fetch a single segment by public_id |
create_segment |
segments:write |
Create a segment with a recursive AND/OR filters tree over contact attributes, device class, and nested segment membership |
update_segment |
segments:write |
Update title, description, privacy, or filters; partial payloads are last-write-wins |
delete_segment |
segments:write |
Delete a segment; any survey targeting it becomes unsegmented (shows to everyone). Queued |
assign_survey_segment |
segments:write |
Set a segment as a survey's audience (a survey targets one segment) |
unassign_survey_segment |
segments:write |
Clear a survey's audience segment (it becomes unsegmented and shows to everyone) |
SDK keys
Public environment keys the in-app / website survey SDK embeds in the browser. Each key carries an allowed_origins CORS allow-list - an empty list denies all cross-origin browser use, so add your production origins explicitly. Part of the in-app / website survey suite; requires a paid plan.
| Tool | Ability | Description |
|---|---|---|
list_sdk_keys |
sdk-keys:read |
List the team's public SDK keys |
get_sdk_key |
sdk-keys:read |
Fetch a single SDK key by its public key value |
create_sdk_key |
sdk-keys:write |
Mint a new public SDK key; allowed_origins is a CORS allow-list and an empty list denies all cross-origin use |
update_sdk_key |
sdk-keys:write |
Rename, replace the allowed_origins CORS list, or toggle is_active; passing allowed_origins replaces the whole list (empty array denies all cross-origin use) |
revoke_sdk_key |
sdk-keys:write |
Deactivate the key (rejected immediately) and soft-delete it; historical displays/responses are preserved. Queued |
Displays (read-only)
Read-only analytics over survey displays / impressions captured by the SDK. Part of the in-app / website survey suite; requires a paid plan.
| Tool | Ability | Description |
|---|---|---|
list_displays |
displays:read |
List survey displays / impressions; optionally filter by survey_id and unresponded-only |
get_display |
displays:read |
Fetch a single display / impression by public_id |
get_survey_display_analytics |
displays:read |
Display-funnel analytics for a survey - completion rate, per-question drop-off, time-to-complete; optional date range and segment / contact-attribute filter |
Funnels
Funnels are multi-step lead-gen / quiz funnels with screens, blocks, scoring, pixels, A/B tests, and server-side CAPI. All funnel tools require a paid plan. Funnel tools accept either public_id (preferred, mirrors forms/surveys) or the legacy slug to identify a funnel.
| Tool | Ability | Description |
|---|---|---|
list_funnels |
funnels:read |
List funnels for the current team |
get_funnel |
funnels:read |
Get a funnel by public_id (preferred) or slug |
create_funnel |
funnels:write |
Create a blank funnel or hydrate a gallery template via template |
update_funnel |
funnels:write |
Update top-level config and replace screens. Sets theme / theme_v2 styling, tracking pixels, A/B config, autoresponder, notification emails, honeypot, hidden fields, allowed origins, and a full ordered screens array (id-diff upsert) |
set_funnel_document |
funnels:write |
Build a complete, styled multi-step funnel - screens, blocks, branching, theme - in one call from a builder document. See Build in one call |
publish_funnel |
funnels:publish |
Publish or unpublish a funnel |
delete_funnel |
funnels:write |
Soft-delete (recoverable) |
get_funnel_analytics |
funnels:analytics |
Funnel analytics summary |
list_funnel_sessions |
funnels:analytics |
Recent sessions for a funnel |
add_screen |
funnels:write |
Add a screen to a funnel |
add_block |
funnels:write |
Add a block to a funnel screen |
set_logic |
funnels:write |
Attach an AND/OR DSL logic rule to a block |
set_score |
funnels:write |
Attach a per-block score map (bucket → points) |
set_pixel |
funnels:write |
Set browser-side pixel IDs (GA4 / GTM / Meta / TikTok / LinkedIn / Pinterest / Snap / Bing / Reddit / Twitter) |
set_capi_token |
funnels:write |
Configure server-side CAPI credentials for a vendor (meta / tiktok / linkedin / pinterest) |
Links
Branded short links and QR codes. Available on every plan.
| Tool | Ability | Description |
|---|---|---|
list_links |
links:read |
List short links for the current team |
get_link |
links:read |
Fetch one short link by id or slug |
create_link |
links:write |
Create a new short link |
update_link |
links:write |
Update an existing short link |
delete_link |
links:write |
Soft-delete a short link |
Bio pages
A Bio page is a single public link-in-bio profile (handle, avatar, headline, bio) listing many ordered blocks. It is not a form, survey, funnel, or single link - use these tools, never create_form / create_survey / create_funnel / create_link. Requires a plan that includes Bio Pages.
| Tool | Ability | Description |
|---|---|---|
list_bio_pages |
bio:read |
List link-in-bio profile pages for the current team |
get_bio_page |
bio:read |
Fetch one page by id or handle, including its blocks |
create_bio_page |
bio:write |
Create a new profile page (a single public page listing many blocks) |
update_bio_page |
bio:write |
Update the page profile and publish state |
set_bio_document |
bio:write |
Build or restyle an entire bio page from a builder document (all block types + theme), replacing the page's blocks in one call |
set_bio_pixel |
bio:write |
Set one browser-side tracking pixel ID on a page (GA4 / GTM / Meta / TikTok) |
add_bio_block |
bio:write |
Append or insert one content block (link, header, text, social, embed, image, form, …) onto a page |
reorder_bio_blocks |
bio:write |
Reorder a page's blocks by id |
delete_bio_block |
bio:write |
Remove a single block (cascades its managed short link / files) |
delete_bio_page |
bio:write |
Delete a page; disabled immediately, hard delete queued |
Automations
Per-form automation rules with steps that fire on submission events. Available on every plan. Use list_automations with a form's public_id; the team-wide formspring://team/automations resource lists automations across forms, surveys, and funnels.
| Tool | Ability | Description |
|---|---|---|
list_automations |
automations:read |
List automations for a form (form_id = form public_id) |
get_automation |
automations:read |
Get a single automation with its steps |
create_automation |
automations:write |
Create a new automation |
update_automation |
automations:write |
Update top-level fields (steps via dedicated tools) |
enable_automation |
automations:write |
Enable an automation |
disable_automation |
automations:write |
Disable an automation |
delete_automation |
automations:write |
Permanent delete (with steps + runs) |
run_automation |
automations:run |
Manually trigger an automation |
list_automation_runs |
automations:read |
List recent runs |
get_automation_run |
automations:read |
Get one run with per-step outputs |
replay_automation_run |
automations:run |
Replay a previous run |
Billing (read-only)
| Tool | Ability | Description |
|---|---|---|
get_team |
billing:read |
Current team summary |
get_plan |
billing:read |
Plan key, features, limits |
get_usage |
billing:read |
Current period: submissions, storage, deliveries |
get_subscription_state |
billing:read |
active / on_trial / on_grace_period / past_due / canceled |
AI Insights
| Tool | Ability | Description |
|---|---|---|
get_ai_insights |
insights:read |
Insights payload (or { locked: true }) |
regenerate_ai_insights |
insights:write |
Trigger regen; locked 5 min between calls |
Tokens (self-management)
| Tool | Ability | Description |
|---|---|---|
list_tokens |
tokens:read |
Your own tokens |
create_token |
tokens:write |
Mint a token; abilities ⊆ caller's |
revoke_token |
tokens:write |
Revoke (refuses on the active token) |
Integration reference
| Tool | Ability | Description |
|---|---|---|
get_framework_integration_catalog |
forms:read |
Returns a maximum-breadth matrix of stacks (React, Next.js, Laravel, WordPress, mobile, serverless, …): each row includes a short copy-paste snippet (placeholder FORMSPRING_ENDPOINT → your https://…/f/{public_id}), notes (CORS, hosted vs legacy payloads, etc.), docs_url into this site's /docs/…, and optional recipe_slug when a long-form recipe exists. Supports optional category (spa, ssr, static, mobile, backend, cms, edge) and pagination page / per_page (max 100 per page). Deep guides remain on the docs site; MCP returns the compact matrix. |
Example call
get_framework_integration_catalog {
"category": "ssr",
"page": 1,
"per_page": 25
}
Example call
list_submissions {
form_id: "r2EdO-orF-3S",
folder: "spam",
limit: 25
}
returns
{
"submissions": [
{
"id": "01HFXX0X9R7KZJVN9VS6TG2C5T",
"status": "spam",
"spam_reason": "akismet",
"ai_moderation_score": 87,
"payload": { "email": "spam@bad.com", "message": "..." },
"created_at": "2026-05-07T16:09:10Z"
}
]
}