# Make a Cube form > How you, an agent, make a form for your person on Cube. There are two ways; pick by what you can do right now. - **You are connected to Cube's owner MCP server** (`https://ui.usecube.io/mcp/owner`, signed in as your person): write the form as JSON (below) and call `create_form`. It is published at once and you get the link to share and the HTML to put it on their own site. Done. - **You are not:** write the form as JSON and give your person `https://ui.usecube.io/forms/new#spec=` followed by that JSON, URL-encoded. The link opens the form in their browser; they look it over, sign in if they need to, and press Publish themselves. You cannot press it for them, so don't offer to. In the second case, also tell your person in one line that next time you can publish for them if they connect you to Cube once; they sign in in their browser and press Allow: - Claude Code: `claude mcp add --transport http cube https://ui.usecube.io/mcp/owner`, then `/mcp` and Authenticate. - Claude (claude.ai or the desktop app): Settings, Connectors, Add custom connector, URL `https://ui.usecube.io/mcp/owner`. - ChatGPT (where custom connectors are on), Cursor or any other MCP client: the MCP URL `https://ui.usecube.io/mcp/owner`. A Cube form is one link: people fill the page, and agents fill it without opening it. Once your person publishes it, the form is at `https://ui.usecube.io/f/` and its answers are theirs. ## 1. Write the form ```json { "title": "Pottery workshop RSVP", "description": "Saturday, 10am to noon. Clay and tools are provided.", "fields": [ { "type": "short_text", "label": "Your name", "required": true }, { "type": "email", "label": "Email", "required": true }, { "type": "single_select", "label": "Have you done pottery before?", "required": true, "options": [ "Never", "A few times", "Often" ] }, { "type": "long_text", "label": "Anything we should know?" } ] } ``` - `title`: the form's name, up to 200 characters. - `description` (optional): one line under the title for the people filling it in, up to 2,000 characters. - `fields`: the questions in order, at most 200. Each has: - `type`: one of the types below. - `label`: the question as the person reads it, up to 500 characters. - `required` (optional): `true` if it must be answered. Default `false`. - `help` (optional): a line under the question. - `description` (optional): one sentence telling an agent what to put, for agents that fill the form in later. Default: the label. - its type's settings (below), each optional. Anything else is ignored, and a question whose type isn't listed is left out. Each answer's key is made from its label. ## Question types | `type` | In the builder | What it is, and its settings (default) | | --- | --- | --- | | `short_text` | Short answer | `maxLength`: the most characters, up to 1,000 (200) | | `long_text` | Long answer | `maxLength`: the most characters, up to 10,000 (5000) | | `number` | Number | `min`: the smallest allowed; `max`: the largest allowed; `integer`: true for whole numbers only | | `money` | Amount | An amount and its currency. `currencies`: the currencies offered, three-letter codes like ["USD", "EUR"] (every one unless you say); `defaultCurrency`: the one picked first, like "EUR" ("USD") | | `repeat` | Work history | Each entry is employer, title, start, end, current. `item`: what one entry is called ("entry"); `fields`: the questions in one entry, written like the form's own (no group inside a group) ([{"type":"short_text","name":"employer","label":"Employer","required":true,"description":"The company."},{"type":"short_text","name":"title","label":"Title","required":true,"description":"The job title."},{"type":"date","precision":"month","name":"start","label":"Start","required":true,"description":"When they started."},{"type":"date","precision":"month","name":"end","label":"End","required":true,"skipIf":"current","description":"When they left; leave it out when current is true."},{"type":"checkbox","name":"current","label":"I work here now","description":"True for the job they hold now."}]) | | `single_select` | Multiple choice | `options`: the choices, up to 100 (["Option 1"]) | | `multi_select` | Checkboxes | `options`: the choices, up to 100 (["Option 1"]) | | `multi_select_other` | Checkboxes with Other | Checkboxes, and a line after "Other" for their own answer. `options`: the choices, up to 100 (["Option 1"]) | | `yes_no` | Yes / no | None | | `checkbox` | Consent | One box to tick. A required one is a consent: only the person ticks it. `link`: {"text", "href"}: a link under the box, like the terms it agrees to | | `demographic` | Self-identification | A voluntary question (gender, ethnicity...); "I don't wish to answer" is always added. `options`: the choices, up to 100 (["Option 1"]) | | `email` | Email | None | | `phone` | Phone number | `defaultCountry`: the country shown first, a two-letter code like "GB" ("US") | | `url` | Link | `site`: "linkedin" or "github" to ask for that profile | | `location` | City | None | | `address` | Address | None | | `date` | Date | `precision`: "month" for a year and month only, "day" for a whole date (the default) | | `slot` | Time slot | `timeZone`: an IANA time zone like "Europe/London" ("America/Los_Angeles"); `zoneName`: that zone in words, like "London time" ("Pacific Time"); `weekdays`: the days offered, 0 = Sunday to 6 = Saturday ([1,2,3,4,5]); `times`: the start times offered, "HH:MM" in 24 hours, up to 48 (["09:00","10:00","11:00","13:00","14:00","15:00","16:00"]); `daysAhead`: how many days ahead it offers, 1 to 90 (14) | | `file` | File upload | .pdf, .doc, .docx, .png, .jpg, .webp, .gif, up to 10 MB; the person attaches it on the page. `accept`: the kinds of file it takes, each an extension or a MIME type, like [".pdf", "application/msword"]: .pdf .doc .docx .png .jpg .webp .gif (all of them unless you say) ([{"mime":"application/pdf","ext":".pdf","words":"a PDF"},{"mime":"application/msword","ext":".doc","words":"a Word (.doc) file"},{"mime":"application/vnd.openxmlformats-officedocument.wordprocessingml.document","ext":".docx","words":"a Word file"},{"mime":"image/png","ext":".png","words":"a PNG"},{"mime":"image/jpeg","ext":".jpg","words":"a JPEG"},{"mime":"image/webp","ext":".webp","words":"a WebP"},{"mime":"image/gif","ext":".gif","words":"a GIF"}]); `maxBytes`: the largest file in bytes, up to 10,000,000 (10000000) | | `rating` | Rating (NPS) | Net Promoter Score, 0 to 10. `low`: the words for 0 ("Not at all likely"); `high`: the words for 10 ("Extremely likely") | | `scale` | Linear scale | `min`: 0 or 1 (1); `max`: the top, up to 10 (5); `low`: the words for the bottom ("Not at all"); `high`: the words for the top ("Very much") | ## 2. Give your person the link **Any agent, even a chat assistant that can only write text:** the link is `https://ui.usecube.io/forms/new#spec=` followed by the form's JSON, URL-encoded (JavaScript's `encodeURIComponent`). If you can run code: `"https://ui.usecube.io/forms/new#spec=" + encodeURIComponent(JSON.stringify(form))`. Give it to your person as it is, in one piece. The form above is: https://ui.usecube.io/forms/new#spec=%7B%22title%22%3A%22Pottery%20workshop%20RSVP%22%2C%22description%22%3A%22Saturday%2C%2010am%20to%20noon.%20Clay%20and%20tools%20are%20provided.%22%2C%22fields%22%3A%5B%7B%22type%22%3A%22short_text%22%2C%22label%22%3A%22Your%20name%22%2C%22required%22%3Atrue%7D%2C%7B%22type%22%3A%22email%22%2C%22label%22%3A%22Email%22%2C%22required%22%3Atrue%7D%2C%7B%22type%22%3A%22single_select%22%2C%22label%22%3A%22Have%20you%20done%20pottery%20before%3F%22%2C%22required%22%3Atrue%2C%22options%22%3A%5B%22Never%22%2C%22A%20few%20times%22%2C%22Often%22%5D%7D%2C%7B%22type%22%3A%22long_text%22%2C%22label%22%3A%22Anything%20we%20should%20know%3F%22%7D%5D%7D Opening it puts the form in Cube's builder: your person checks the questions, changes anything they like, signs in if asked, and presses Publish. The part after `#` never reaches a server. Keep the link under 64,000 characters. **With the Cube MCP connector** (`https://ui.usecube.io/mcp`): call `draft_form` with `title`, `description` and `fields`. It checks the form the way the builder will and returns the same link (`url`), what it fixed (`fixed`) and the settings it filled in (`defaults`). **Signed in as your person** (the owner's MCP server, `https://ui.usecube.io/mcp/owner`: in Claude Code, `claude mcp add --transport http cube https://ui.usecube.io/mcp/owner`, then `/mcp` and Authenticate): call `create_form` with the same `title`, `description` and `fields`. It publishes the form at once and returns its link (`url`), the HTML to put it on their own site (`embed`: in the page, or a button that opens a popup) and where its answers arrive (`answers_url`); `list_answers` then reads what comes in. Without that sign-in you can't publish a form yourself. Tell your person to open the link, check the form and press Publish; the form's Share tab then has its link and the code to embed it on their site.