set_form_metadata
Update form view metadata—such as description, submit confirmation, and redirect URL—in a single call, modifying only specified properties.
Instructions
Update one or more legacy-form-view metadata properties in a single call. Unset properties are not touched. Each property fans out to its own atomic Airtable endpoint.
Supported properties: description — intro text shown above the form afterSubmitMessage — "thank you" text after submission redirectUrl — URL to redirect to after submit refreshAfterSubmit — post-submit behavior (e.g. "REFRESH_BUTTON") shouldAllowRequestCopyOfResponse — boolean: show "send me a copy" toggle to respondents shouldAttributeResponses — boolean: track which user submitted (for signed-in respondents) isAirtableBrandingRemoved — boolean: hide Airtable branding (paid plans only)
Note: "form title" is the view name itself — use rename_view to change it. "Field labels on the form" use a per-field endpoint that has not been captured yet.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| appId | Yes | The Airtable base/application ID | |
| viewId | Yes | The form view ID | |
| description | No | Intro text shown above the form (omit to leave unchanged) | |
| afterSubmitMessage | No | Confirmation text shown after submission | |
| redirectUrl | No | URL to redirect to after submit | |
| refreshAfterSubmit | No | Post-submit behavior (e.g. "REFRESH_BUTTON") | |
| shouldAllowRequestCopyOfResponse | No | Allow respondents to request a copy of their submission | |
| shouldAttributeResponses | No | Track which signed-in user submitted each response | |
| isAirtableBrandingRemoved | No | Hide the Airtable branding on the form (paid plans) | |
| debug | No | When true, include raw Airtable response in output for diagnostics |
Implementation Reference
- The tool handler function for set_form_metadata. Destructures appId, viewId, debug, and ...props (the remaining form metadata properties), calls client.setFormMetadata(), and returns the result.
async set_form_metadata({ appId, viewId, debug, ...props }) { const result = await client.setFormMetadata(appId, viewId, props); return ok(result, result, debug); }, - Tool definition (inputSchema) for set_form_metadata. Defines the tool name, description of supported properties (description, afterSubmitMessage, redirectUrl, refreshAfterSubmit, shouldAllowRequestCopyOfResponse, shouldAttributeResponses, isAirtableBrandingRemoved), and the required params (appId, viewId).
// ── Form metadata (legacy form views only — Interfaces / "builder forms" are out of scope) ── { name: 'set_form_metadata', description: `Update one or more legacy-form-view metadata properties in a single call. Unset properties are not touched. Each property fans out to its own atomic Airtable endpoint. Supported properties: description — intro text shown above the form afterSubmitMessage — "thank you" text after submission redirectUrl — URL to redirect to after submit refreshAfterSubmit — post-submit behavior (e.g. "REFRESH_BUTTON") shouldAllowRequestCopyOfResponse — boolean: show "send me a copy" toggle to respondents shouldAttributeResponses — boolean: track which user submitted (for signed-in respondents) isAirtableBrandingRemoved — boolean: hide Airtable branding (paid plans only) Note: "form title" is the view name itself — use rename_view to change it. "Field labels on the form" use a per-field endpoint that has not been captured yet.`, annotations: { readOnlyHint: false, destructiveHint: false, idempotentHint: true, openWorldHint: false }, inputSchema: { type: 'object', properties: { appId: { type: 'string', description: 'The Airtable base/application ID' }, viewId: { type: 'string', description: 'The form view ID' }, description: { type: 'string', description: 'Intro text shown above the form (omit to leave unchanged)' }, afterSubmitMessage: { type: 'string', description: 'Confirmation text shown after submission' }, redirectUrl: { type: 'string', description: 'URL to redirect to after submit' }, refreshAfterSubmit: { type: 'string', description: 'Post-submit behavior (e.g. "REFRESH_BUTTON")' }, shouldAllowRequestCopyOfResponse: { type: 'boolean', description: 'Allow respondents to request a copy of their submission' }, shouldAttributeResponses: { type: 'boolean', description: 'Track which signed-in user submitted each response' }, isAirtableBrandingRemoved: { type: 'boolean', description: 'Hide the Airtable branding on the form (paid plans)' }, debug: debugProp, }, required: ['appId', 'viewId'], }, }, - The AirtableClient.setFormMetadata() method that fans out each property to its own Airtable internal API endpoint (e.g., updateFormDescription, updateFormAfterSubmitMessage, etc.).
async setFormMetadata(appId, viewId, props = {}) { assertAirtableId(appId, 'appId'); assertAirtableId(viewId, 'viewId'); const ops = []; if (props.description !== undefined) ops.push(['updateFormDescription', { description: props.description }]); if (props.afterSubmitMessage !== undefined) ops.push(['updateFormAfterSubmitMessage', { afterSubmitMessage: props.afterSubmitMessage }]); if (props.redirectUrl !== undefined) ops.push(['updateFormRedirectUrl', { redirectUrl: props.redirectUrl }]); if (props.refreshAfterSubmit !== undefined) ops.push(['updateFormRefreshAfterSubmit', { refreshAfterSubmit: props.refreshAfterSubmit }]); if (props.shouldAllowRequestCopyOfResponse !== undefined) ops.push(['updateFormShouldAllowRequestCopyOfResponse', { shouldAllowRequestCopyOfResponse: !!props.shouldAllowRequestCopyOfResponse }]); if (props.shouldAttributeResponses !== undefined) ops.push(['updateFormShouldAttributeResponses', { shouldAttributeResponses: !!props.shouldAttributeResponses }]); if (props.isAirtableBrandingRemoved !== undefined) ops.push(['updateFormIsAirtableBrandingRemoved', { isAirtableBrandingRemoved: !!props.isAirtableBrandingRemoved }]); if (ops.length === 0) { throw new Error('setFormMetadata requires at least one property to update'); } const applied = {}; for (const [endpoint, payload] of ops) { const url = `https://airtable.com/v0.3/view/${viewId}/${endpoint}`; const res = await this.auth.postForm(url, this._mutationParams(payload, appId), appId); if (!res.ok) { const errBody = await res.text().catch(() => ''); throw new Error(`${endpoint} failed (${res.status}): ${errBody}`); } Object.assign(applied, payload); } return { updated: true, viewId, applied }; } - packages/mcp-server/src/tool-config.js:91-91 (registration)Registration of set_form_metadata in the TOOL_CATEGORIES map, assigning it to the 'form-write' category for profile-based enable/disable control.
set_form_metadata: 'form-write', - packages/extension/src/mcp/tool-profile.ts:94-94 (registration)Duplicate registration in the VS Code extension's TOOL_CATEGORIES map (must mirror the server-side map), also assigning set_form_metadata to 'form-write'.
set_form_metadata: 'form-write',