Skip to main content
Glama

Publish a form

publish_form

Call this after validate_definition passes, to put the form live on Formhaus Cloud: without form_id it creates a new form, with form_id it publishes a new version of that form.

Instructions

Call this after validate_definition passes, to put the form live on Formhaus Cloud: without form_id it creates a new form, with form_id it publishes a new version of that form. Returns form_id, version, endpoint (POST URL for submissions), hosted_url, embed_snippet, react_snippet, dashboard_url and warnings. Without an account key (fh_live_...) it also returns claim_url and expires_at, and on the first call without any key agent_key (fh_agent_...) and agent_key_notice. Call it when the user needs a working form (contact, waitlist, signup, survey, feedback) without writing a backend. A new version keeps form_id, endpoint and links.

Minimal valid definition: {"id":"waitlist","title":"Join the waitlist","submit":{"label":"Join"},"fields":[{"key":"email","type":"email","label":"Email","validation":{"required":true}}]}

Rules:

  • Top level needs id, title and submit {"label": "..."}.

  • Each field needs key, type and label; a hidden field needs no label. Use "fields" for one step, or "steps" (each with id, title and fields) for several, never both.

  • Types: text, email, phone, number, textarea, select, multiselect, radio, checkbox, switch, date, datetime. password, file, autocomplete, optionsFrom and custom types are refused.

  • select, multiselect and radio need "options": [{"value": "a", "label": "A"}].

  • "validation": {"required": true, "minLength": 2, "maxLength": 200, "min": 0, "max": 10, "pattern": "^[a-z]+$"}.

  • At most 32 KB and 100 fields.

  • JSON Schema: https://formhaus.dev/schema/form-definition.json

Keys: an agent key only reaches the forms it created, at most 3 unclaimed per key. Never put agent_key in browser code or in git. This server reads FORMHAUS_API_KEY from its own environment, so it cannot save the key: add it to the env of the formhaus MCP server in the MCP client config and restart the server. Unclaimed forms expire after 7 days, accept 100 submissions and ignore redirect_url. Give claim_url to the user. When an error ends with "Ask the user to upgrade at ", give that URL to the user. On error, fix every listed path and call again.

Tool call template

Replace each placeholder with a value matching the input schema. Only required parameters are included; add optional parameters as needed.

{
  "id": 1,
  "jsonrpc": "2.0",
  "method": "tools/call",
  "params": {
    "arguments": {
      "definition": "<definition>"
    },
    "name": "publish_form"
  }
}

Input Schema

NameRequiredDescriptionDefault
emailNoOnly for a new form published without an account key: the user's email. Formhaus emails them claim_url (at most one email per address per hour, no form content). Ignored with a warning otherwise.
form_idNoThe 10-character form_id of an existing form, from publish_form or list_forms, to publish a new version of it. Requires an account key (fh_live_...) of the form's account or the agent key (fh_agent_...) that created the form. Omit to create a new form.
definitionYesFormhaus form definition as a JSON object or a JSON string. JSON Schema: https://formhaus.dev/schema/form-definition.json. Top level: id, title, submit { label }, and fields (one step) or steps [{ id, title, fields }]. Field: { key, type, label, validation?, options?, show?, showAny? }. Rules go inside "validation": { required, minLength, maxLength, min, max, pattern, matchField }. Condition: { field, eq | neq | in | notIn | contains | notContains | notEmpty | gt | gte | lt | lte } with exactly one operator, on a field of the same or an earlier step. Optional: lang, messages and labels catalogs, and i18n objects that map texts to translation keys.
redirect_urlNohttp(s) URL the hosted page and embed open after a successful submission instead of the success message. Empty string removes it. Ignored with a warning for unclaimed forms.
success_messageNoText shown after a successful submission on the hosted page and embed. Up to 500 characters.

Output Schema

NameRequiredDescriptionDefault
errorNoMachine-readable error code or message when the call failed.
noticeNo
form_idNo
messageNo

Schema Changelog

Changes observed during successful MCP inspections.

  1. Changed1 schema field changedv0.13.4
    • changedInput schema / properties / definition / description
      Previous value: -"Formhaus form definition as a JSON object or a JSON string. JSON Schema: https://formhaus.dev/schema/form-definition.json. Top level: id, title, submit { label }, and fields (one step) or steps [{ id, title, fields }]. Field: { key, type, label, validation?, options?, show?, showAny? }. Rules go inside \"validation\": { required, minLength, maxLength, min, max, pattern, matchField }. Condition: { field, eq | neq | in | notIn | notEmpty | gt | gte | lt | lte } with exactly one operator, on a field of the same or an earlier step. Optional: lang, messages and labels catalogs, and i18n objects that map texts to translation keys."New value: +"Formhaus form definition as a JSON object or a JSON string. JSON Schema: https://formhaus.dev/schema/form-definition.json. Top level: id, title, submit { label }, and fields (one step) or steps [{ id, title, fields }]. Field: { key, type, label, validation?, options?, show?, showAny? }. Rules go inside \"validation\": { required, minLength, maxLength, min, max, pattern, matchField }. Condition: { field, eq | neq | in | notIn | contains | notContains | notEmpty | gt | gte | lt | lte } with exactly one operator, on a field of the same or an earlier step. Optional: lang, messages and labels catalogs, and i18n objects that map texts to translation keys."
  2. Changed4 schema fields changedv0.13.3
    • changedInput schema / properties / email / description
      Previous value: -"Only without an API key: the user email that receives the claim link."New value: +"Only for a new form published without an account key: the user's email. Formhaus emails them claim_url (at most one email per address per hour, no form content). Ignored with a warning otherwise."
    • changedInput schema / properties / form_id / description
      Previous value: -"Publish a new version of this existing form. Requires FORMHAUS_API_KEY."New value: +"The 10-character form_id of an existing form, from publish_form or list_forms, to publish a new version of it. Requires an account key (fh_live_...) of the form's account or the agent key (fh_agent_...) that created the form. Omit to create a new form."
    • changedInput schema / properties / redirect_url / description
      Previous value: -"http(s) URL to open after a successful submission instead of the success message. Empty string removes it."New value: +"http(s) URL the hosted page and embed open after a successful submission instead of the success message. Empty string removes it. Ignored with a warning for unclaimed forms."
    • changedInput schema / properties / success_message / description
      Previous value: -"Text shown after a successful submission on the hosted page and embed."New value: +"Text shown after a successful submission on the hosted page and embed. Up to 500 characters."
  3. First observedv0.13.1

TDQS

A4.8/5.0
Behavior5/5

Does the description disclose side effects, auth requirements, rate limits, or destructive behavior?

The description adds substantial behavioral context beyond the annotations: returned fields, unclaimed-form limits, claim URLs, expiration, API-key handling, warnings, and environment configuration constraints. The write-oriented behavior aligns with readOnlyHint=false and openWorldHint=true.

Agents need to know what a tool does to the world before calling it. Descriptions should go beyond structured annotations to explain consequences.

Conciseness4/5

Is the description appropriately sized, front-loaded, and free of redundancy?

The description is front-loaded with the core call condition and create/version distinction, then moves into returns, key behavior, and definition rules. It is long and dense, but most content is operationally useful for a complex publishing tool; only minor tightening would improve it.

Shorter descriptions cost fewer tokens and are easier for agents to parse. Every sentence should earn its place.

Completeness5/5

Given the tool's complexity, does the description cover enough for an agent to succeed on first attempt?

Given the write operation, open-world annotations, rich input schema, and output schema, the description is complete enough to call correctly. It covers prerequisites, key requirements, return expectations, unclaimed-form behavior, errors, and definition constraints.

Complex tools with many parameters or behaviors need more documentation. Simple tools need less. This dimension scales expectations accordingly.

Parameters4/5

Does the description clarify parameter syntax, constraints, interactions, or defaults beyond what the schema provides?

Schema description coverage is already 100%, so baseline is 3, but the description adds meaningful authoring semantics for the definition parameter: minimal valid shape, field and step rules, allowed and refused types, validation constraints, size limits, and condition syntax. It also clarifies form_id create-versus-version behavior beyond the schema.

Input schemas describe structure but not intent. Descriptions should explain non-obvious parameter relationships and valid value ranges.

Purpose5/5

Does the description clearly state what the tool does and how it differs from similar tools?

The description states a specific verb and resource: publishing a form live, with explicit distinction between creating a new form (no form_id) and publishing a new version of an existing form (with form_id). It also distinguishes this from validate_definition by saying to call it after validation passes.

Agents choose between tools based on descriptions. A clear purpose with a specific verb and resource helps agents select the right tool.

Usage Guidelines5/5

Does the description explain when to use this tool, when not to, or what alternatives exist?

It gives explicit usage guidance: call after validate_definition passes, and call when the user needs a working form such as contact, waitlist, signup, survey or feedback without a backend. The create-versus-version behavior is also clearly conditioned on form_id.

Agents often have multiple tools that could apply. Explicit usage guidance like "use X instead of Y when Z" prevents misuse.