MCP server
Connect Claude, ChatGPT or Cursor to your forms and let them read, analyse and build.
Chatform runs a Model Context Protocol server at:
https://api.chatform.in/mcpPaste that link into an AI app and sign in, and it can list your forms, read responses, analyse completion rates, author a new form from a description, publish it, and reach the rest of the API when it needs something the named tools do not cover.
It is the same worker, the same keys and the same scopes as /v1. Nothing here can
do anything a key could not already do over HTTP, with one deliberate
subtraction: nothing can delete.
Connect with one link
Most apps need nothing but the URL. They open your browser on a Chatform page that asks Allow Claude to use Chatform? (or Cursor, or ChatGPT), you click Allow, and the app keeps itself signed in from then on. No key to create or paste. The same steps, with copy buttons, are in every form's Integrate tab under AI assistants.
- Open Connectors in Claude's settings.
- Click Add custom connector, name it Chatform and paste
https://api.chatform.in/mcp. - Click Connect, then Allow.
Free Claude plans allow one custom connector. On Team and Enterprise, an owner adds it once under Organization settings and everyone then connects it themselves.
Connecting an organization is an owner or admin decision, the same as creating an API key. Each connection appears under Connected in the AI assistants panel, where Disconnect cuts it off at once.
Use an API key instead
For a server, a script, or a client that cannot open a browser, send a secret key on every request instead. Keys need a plan with API access.
Get a key
MCP needs more than a new key is given by default. A default secret key can read
forms and responses; it cannot publish, read analytics or export, so an assistant
using one fails with insufficient_scope on the first interesting request.
In Settings → API keys, create a secret key with these scopes:
| Scope | Why |
|---|---|
form:read, form:write, form:publish | Read, edit and publish forms, and use templates |
response:read, response:write | Read responses, and submit them |
response:export | Start exports |
session:create, session:write, session:read | Open and drive a conversation through chatform_api_write and chatform_api_read |
analytics:read | Completion rates and per-question funnels |
webhook:read, webhook:write | Inspect and register webhooks |
file:read | Resolve file-upload answers |
ai:generate is deliberately not in that list. It is the one scope that spends
money — a generation bills your plan's AI allowance — and an assistant can author a
form for free by reading list_blocks and calling create_form. Add it only if you
specifically want Chatform's own designer model available to the agent.
GET /api/keys/scopes returns this set as the agent preset if you are building
your own key UI.
This is a secret key, so it belongs on a machine, not in a page. /mcp refuses
publishable (pk_) keys outright — their ceiling excludes reading responses and
analytics, so almost nothing would work anyway. Treat the key like a password: an
assistant that holds it can read every response you have collected.
Install with a key
claude mcp add --transport http chatform https://api.chatform.in/mcp \
--header "Authorization: Bearer $CHATFORM_SECRET_KEY"The tools
Thirty, which is a budget rather than an accident: clients cap how many tools they will load — Cursor at forty — and that ceiling is shared with every other server you have connected.
Getting oriented
| Tool | Scope | |
|---|---|---|
whoami | — | Which org this key is, what it may do, and what it is missing |
Forms
| Tool | Scope | |
|---|---|---|
list_forms | form:read | Your forms, newest first |
get_form | form:read | One form. Defaults to the editable document, which is what to change |
list_blocks | — | Every question type, its config schema and answer contract |
create_form | form:write | Create a form, empty or fully authored |
update_form | form:write | Replace the working document |
list_form_settings | form:read | Every setting by key: colours, fonts, tone, goal, closing, emails, embedding, with current values and plan locks |
update_form_settings | form:write | Change settings by key without touching the questions |
publish_form | form:publish | Make the working document live |
list_templates | form:read | The official template catalogue, or one template's document |
use_template | form:write | Start a draft from a template |
list_form_versions | form:read | Published versions, with the responses behind each, and diffs |
restore_form_version | form:write | Roll the draft back to a published version |
generate_form_with_ai | ai:generate | Draft a document with Chatform's own model — costs money |
Responses
| Tool | Scope | |
|---|---|---|
list_responses | response:read | A page of responses; answers are opt-in |
search_responses | response:read | Find responses containing a piece of text |
get_response | response:read | One response with all its answers |
submit_response | response:write | Record a response — for imports, or answering on someone's behalf |
get_form_analytics | analytics:read | Views, completion rate, per-question funnel, distributions |
export_responses | response:export | Start a CSV or JSON export |
check_export | response:export | Poll an export; once ready it returns the rows inline, a slice at a time |
get_file | file:read | Read a file-upload answer: images and text files come back inline, others as a download link |
create_spreadsheet_feed | response:export | A live CSV URL Sheets or Excel can re-read on a schedule |
Webhooks
| Tool | Scope | |
|---|---|---|
list_webhooks | webhook:read | Registered endpoints and their events |
list_webhook_deliveries | webhook:read | Recent attempts, statuses and errors — for "why is it quiet" |
list_events | — | Every event name a webhook can subscribe to |
create_webhook | webhook:write | Register one. The signing secret is shown once |
replay_webhook_delivery | webhook:write | Re-send one failed delivery |
Everything else
Four tools reach the whole developer API without putting forty more schemas in front of the model:
| Tool | |
|---|---|
chatform_api_search | Find an endpoint by keyword; returns its path and required scope |
chatform_api_details | That endpoint's parameters and response schema |
chatform_api_read | GET any documented endpoint |
chatform_api_write | POST, PUT or PATCH any documented endpoint |
They are bounded by the spec: only the operations published at
https://api.chatform.in/openapi.json are reachable. The dashboard's own /api/*
routes and the respondent /p/* channel are not part of that document and cannot
be called with a key, so an assistant cannot reach them however it asks.
Two areas are reachable only this way, on purpose:
- Driving a live conversation — opening a chat session and exchanging messages
turn by turn, plus session uploads. Fifteen operations, and a niche job for an
assistant:
submit_responserecords answers directly without pretending to be a respondent. If you want named tools for testing a form conversationally, that is a reasonable ask. - Incremental response building — recording answers one at a time, then
completing or abandoning
GET /v1/responses/{id}/nextand its siblings.submit_responsedoes the one-shot version, which is what an import or an agent filling a form actually needs.
Building a form
There is no "generate a form" tool, and that is on purpose — your assistant is
already the model. It reads list_blocks for the question-type contract, writes the
document itself, and calls create_form. Chatform spends nothing on inference, and
you are not paying twice for the same sentence.
Build me a 5-question customer onboarding form, publish it, and show me the completion rate once people start answering.
That runs list_blocks → create_form → publish_form → get_form_analytics.
When editing an existing form, the assistant must read the document first:
update_form replaces the whole draft, so a partial document silently removes
every question missing from it. For a setting ("make it navy", "close it after
200 responses", "sound more professional") use update_form_settings instead:
it changes those keys and nothing else, refuses a value that does not fit with
the reason, and reports a setting your plan does not include without applying it.
What is not here
- Deletes. No tool deletes a form, a response, an answer or a webhook, and
chatform_api_writerefuses theDELETEmethod outright — whatever scopes the key holds. Respondent free text is attacker-controlled input, and an assistant reading it should not be one confused tool call away from destroying data. Delete from the dashboard. - Key and plan management. No key can mint keys or change a plan; see Scopes.
.xlsx. The API exportscsvandjson; the typed workbook is dashboard-only. See Spreadsheets.- Deleting responses in bulk, sending a synthetic webhook test, and moving a form
between workspaces. Each has a dashboard route and no API one yet — tracked in
tooling/check-spec-coverage.ts, which now fails the build if a new dashboard capability appears without either a/v1equivalent or a written reason.
Plan and usage
An app connected with one link works on every plan. On a plan with API access each tool call that reaches an endpoint counts as one API request; on Free, connected apps share an allowance of 1,000 calls a month. A pasted key needs a plan that includes API access. Listing the tools is free, which is why an assistant can connect and show you what it could do before the plan refuses the first call — and the refusal says which plan lifts it.
Per-question analytics needs a plan with advanced analytics. Below that,
get_form_analytics returns the headline numbers and says which sections the plan
withheld, so an assistant will not report an empty funnel as "no data".
Things to know
search_responsesis a substring match, not semantic search, and results are not ranked. Searchingunhappywill not finddissatisfied. To find themes, page throughlist_responseswith answers included and read them.- Results are paginated small — ten rows by default — and long answers are
truncated with a
truncatedflag rather than silently cut. - Exports come back inline.
export_responsesreturns an id; once it is ready,check_exportreturns the CSV or JSON Lines itself, up to 200 KB per call, with anext_offsetto read on. An assistant whose sandbox blocksapi.chatform.innever needs the download link. - Keys pinned to specific forms still are. A restricted key sees 404 for anything outside its list, through MCP as over HTTP.
Troubleshooting
| What you see | What it means |
|---|---|
| Sign-in page says "Ask an admin to connect" | Only an owner or admin can connect an organization |
| The app asks you to sign in again | It was disconnected, or unused for two months |
unauthorized on connect | No key, or the header is not reaching the server |
secret_key_required | You used a pk_ key. /mcp needs sk_ |
secret_key_in_browser | A secret key arrived with an Origin header. /mcp is server-to-server |
insufficient_scope | The key is missing the scope named in the message — mint one with the scopes above |
feature_locked | The plan does not include API access; the message carries the upgrade link |
limit_reached | The monthly request quota is spent; the message says when it resets |
not a documented Chatform endpoint | A passthrough tool was pointed at something outside the developer API |
Every error carries a request_id. Quote it if you contact support.