update_view_group_levels
Set grouping on an Airtable view: replace existing group levels or append new ones below them. Pass an empty array to clear all grouping.
Instructions
Set grouping on a view. Default mode replaces all existing group levels — pass an empty array with operation="replace" to clear grouping. Use operation="append" to add new group levels below the existing ones without rewriting them.
Input Schema
| Name | Required | Description | Default |
|---|---|---|---|
| appId | Yes | The Airtable base/application ID | |
| viewId | Yes | The view ID (e.g. "viwXXX") | |
| groupLevels | Yes | Array of group levels. Empty array [] clears grouping when operation="replace". | |
| operation | No | How the given groupLevels interact with existing ones. "replace" (default) overwrites; "append" adds the provided levels after the existing group stack. | |
| debug | No | When true, include raw Airtable response in output for diagnostics |
Implementation Reference
- The main tool handler for 'update_view_group_levels'. Validates inputs (appId, viewId, groupLevels, operation), handles the 'append' operation by reading current group levels from the view via getView(), merges them, then calls client.updateGroupLevels(). Returns a summary with viewId, operation, and groupCount.
async update_view_group_levels({ appId, viewId, groupLevels, operation, debug }) { let effectiveLevels = groupLevels; if (operation === 'append') { const current = await client.getView(appId, viewId); const existing = Array.isArray(current.groupLevels) ? current.groupLevels : []; effectiveLevels = [...existing, ...(Array.isArray(groupLevels) ? groupLevels : [])]; } const result = await client.updateGroupLevels(appId, viewId, effectiveLevels); return ok( { updated: true, viewId, operation: operation || 'replace', groupCount: effectiveLevels.length }, result, debug, ); }, - The client-level method updateGroupLevels() that sends the actual HTTP request to Airtable's internal API endpoint /v0.3/view/{viewId}/updateGroupLevels. Generates group-level IDs (glv-prefixed), sets order (default 'ascending'), forces emptyGroupState to 'hidden' (the API rejects 'visible').
async updateGroupLevels(appId, viewId, groupLevels) { assertAirtableId(appId, 'appId'); assertAirtableId(viewId, 'viewId'); const url = `https://airtable.com/v0.3/view/${viewId}/updateGroupLevels`; const levels = groupLevels.map(g => ({ id: g.id || ('glv' + this._genRandomId()), columnId: g.columnId, order: g.order || 'ascending', emptyGroupState: 'hidden', // API only accepts "hidden"; "visible" causes INVALID_REQUEST })); const payload = { groupLevels: levels }; const res = await this.auth.postForm(url, this._mutationParams(payload, appId), appId); if (!res.ok) { const errBody = await res.text().catch(() => ''); throw new Error(`updateGroupLevels failed (${res.status}): ${errBody}`); } return res.json(); } - The MCP tool input schema definition for 'update_view_group_levels' — defines the expected properties (appId, viewId, groupLevels array, operation enum, debug). Annotated as non-destructive, idempotent. Describes the replace/append modes and notes that the Airtable API only accepts emptyGroupState='hidden'.
{ name: 'update_view_group_levels', description: 'Set grouping on a view. Default mode replaces all existing group levels — pass an empty array with operation="replace" to clear grouping. Use operation="append" to add new group levels below the existing ones without rewriting them.', 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 view ID (e.g. "viwXXX")' }, groupLevels: { type: 'array', items: { type: 'object', properties: { columnId: { type: 'string', description: 'Field ID to group by' }, order: { type: 'string', description: '"ascending" or "descending". Default: "ascending"' }, emptyGroupState: { type: 'string', description: '"hidden" only — the Airtable API rejects "visible" with INVALID_REQUEST. Omit this field or pass "hidden". Default: "hidden".' }, }, required: ['columnId'], }, description: 'Array of group levels. Empty array [] clears grouping when operation="replace".', }, operation: { type: 'string', enum: ['replace', 'append'], description: 'How the given groupLevels interact with existing ones. "replace" (default) overwrites; "append" adds the provided levels after the existing group stack.', }, debug: debugProp, }, required: ['appId', 'viewId', 'groupLevels'], }, }, - packages/mcp-server/src/tool-config.js:67-67 (registration)Registration of 'update_view_group_levels' in the TOOL_CATEGORIES map, categorized as 'view-write' (non-destructive view mutation).
update_view_group_levels: 'view-write', - packages/extension/src/mcp/tool-profile.ts:74-74 (registration)Mirror registration of 'update_view_group_levels' in the extension's TOOL_CATEGORIES map (must stay in sync with tool-config.js), also categorized as 'view-write'.
update_view_group_levels: 'view-write',