Airtable FormulaBLOCK
VS Code extension and MCP server for Airtable, formula editor, schema tools, and 60+ automation utilities for bases, views, and fields.
Overview
From the repository's own README, as read at the audited commit. Badges and raw HTML are left out.
Formula, script & automation editor · MCP server (72 tools + `manage_tools`) · Language server · AI skills
VS Code Open VSX npm · MCP npm · LSP MCP Registry
7ca0d8237eaeOBSERVED · 2026-10-08Connect
Built from this server's own package name, version and transport as found in its source — not copied from anyone's documentation, so it cannot drift against a page we do not control. Replace the environment placeholders with a token scoped to the least it needs.
claude mcp add airtable-user-mcp -- npx -y [email protected]
Exposed tools (100)
44 read · 47 write · 9 destructive. Blast radius: 9 tools can delete or overwrite — an agent that can be talked into calling a tool can be talked into calling this one.
| Tool | Risk | Description |
|---|---|---|
action | read | |
airtable-build-table | write | Design and create a complete table structure from plain-language requirements |
airtable-bulk-formula-edit | write | Download all formula fields from a base, edit them offline, then upload changes |
airtable-create-formula | write | Create an Airtable formula from a plain-language description |
airtable-fix-formula | read | Debug and fix an Airtable formula error or unexpected result |
airtable-inspect-base | read | Explore and summarise the schema of an Airtable base |
airtable-manage-select-choices | destructive | Add, remove, or replace choices on a singleSelect or multipleSelects field |
airtable-search-records | read | Search for records in an Airtable table by text, including lookup field values |
airtable-setup-rollup-lookup | write | Create or update a rollup or lookup field with guided field-ID resolution |
airtable-setup-view | write | Configure an Airtable view — filters, sorts, groups, and column order |
airtable-validate-formula | read | Validate an Airtable formula and show its result type |
appId | read | Base ID (appXXX) to validate against |
apply_record_template | write | Apply (instantiate) a record template to create a new record pre-filled with the template\ |
apply_view_sorts | write | Apply sort conditions to a view. Default mode replaces all existing sorts — pass an empty array with operation= |
choices | read | Comma-separated choice names (e.g. |
create_extension | write | Create a new extension (block) in an Airtable base. Returns the block ID needed for installation. Use this to register custom extensions before installing them. |
create_extension_dashboard | write | Create a new extension dashboard page in a base. Extensions are installed onto dashboard pages. |
create_field | write | Create a new field in an Airtable table. Supports all field types including computed fields (formula, rollup, lookup, count) that are not available via the official API. FIELD TYPES (fieldType parameter): Supported names: |
create_formula_field | write | Create a new formula field — shorthand for |
create_record_template | write | Create a new record template for a table. Returns the generated templateId (rtp-prefixed). After creating, use set_record_template_cell to pre-fill field values. |
create_records | write | Create one or more records in a table. Each item supplies cellValuesByColumnId (computed fields are read-only and must be omitted). Returns created record IDs. Per-row isolation: a failing row is reported, not fatal. |
create_table | write | Create a new table in an Airtable base. Returns the generated table ID. The table starts with default fields (Name, Notes, Attachments, Status, etc.) — use list_fields after creation to inspect them. |
create_view | write | Create a new view in an Airtable table. Optionally copy configuration from an existing view. View types: |
create_view_section | write | Create a new sidebar section in a table. Returns the new section ID (vsc-prefixed). Use |
custom | read | User-defined per-tool selection |
delete_record_template | destructive | ⚠️ DESTRUCTIVE — Permanently delete a record template. This cannot be undone. |
delete_records | destructive | Delete one or more records from a table in a single batch call. The returned deleted count equals rowIds.length (optimistic) — already-deleted rows are silently skipped by the server. |
delete_table | destructive | Delete a table from an Airtable base. Requires both tableId AND the expected table name as a safety guard — refuses to delete if the name does not match. Airtable rejects deleting the last remaining table in a base. |
delete_view | destructive | Delete a view from a table. Cannot delete the last remaining view in a table. |
delete_view_section | destructive | Delete a sidebar section. Views inside the section are NOT deleted — Airtable auto-promotes them to ungrouped at the table-level position the section used to occupy. Verified 2026-04-30. |
description | read | What the formula should calculate or produce |
download_base_formulas | read | Download ALL formula fields from a base to local .formula files, organized into per-table subfolders. Field refs are resolved to real field names ({Field Name}, Airtable\ |
download_formula_field | read | Download the formula text of a formula field to a local file. Field refs are resolved to real field names ({Field Name}, Airtable\ |
duplicate_extension | read | Duplicate an installed extension on a dashboard page. |
duplicate_field | read | Duplicate (clone) a field in a table. Optionally also duplicate the cell values. |
duplicate_record_template | read | Duplicate a record template within the same or a different table. Returns the new template ID. |
duplicate_records | read | Duplicate one or more existing records within a table. Creates exact copies of the specified source records in the same table and view. Returns the new record IDs. |
duplicate_view | read | Duplicate an existing view with all its configuration (filters, sorts, field visibility, etc). |
error | read | Error message or symptom (e.g. #ERROR, NaN) |
fieldId | read | Field ID (fldXXX) |
fieldName | write | Name for the new field (or existing fieldId to update) |
fieldType | read | |
formula | read | The formula to fix |
get_base_schema | read | Get the full schema of an Airtable base — all tables, fields (with typeOptions), and views in one call. Use this when you need fields or views; use |
get_table_schema | read | Get the full schema for a single table — all fields (with typeOptions) and views. Use instead of |
get_view | read | Read a view |
goal | read | What to roll up or look up (plain English) |
install_extension | write | Install an extension onto a dashboard page. Requires a block ID (from create_extension) and a page ID (from create_extension_dashboard). |
limit | read | Max records to scan (1–1000, default 100) |
list_fields | read | List fields in a table — returns id, name, and type per field (lightweight by default). Use instead of |
list_record_templates | read | List all record templates for a table. Templates are embedded in the base scaffolding data. If the templates array is empty, pass debug:true and inspect the raw response to locate the templates key — the API path may vary by base. |
list_tables | read | List all tables in a base with their IDs and names — lightweight scaffolding call (no field data). Use this when you only need table IDs/names; use |
list_view_sections | read | List all sidebar sections for a table. Sections are user-organized groupings of views in the Airtable left sidebar (e.g. |
list_views | read | List all views in a specific table with their IDs, names, and types. |
manage_daemon | read | Inspect and control the MCP daemon this server runs in. action= |
manage_tools | read | Control which tools are available. Actions: list_profiles, switch_profile, |
mode | read | |
move_overall_columns | write | Move one or more columns to a new position in the *overall* index (visible + hidden). Sibling of |
move_visible_columns | write | Move columns by visible-only index (index 0 = leftmost shown column, hidden columns not counted). Use when you want to position relative to what the user sees. Use |
my-prompt | read | d |
outputDir | write | Local directory to write .formula files into |
query_records | read | Read records from an Airtable table view. Returns resolved field values including lookup fields. Supports optional client-side text search across all field values — unlike the REST API filterByFormula approach, this search works correctly on lookup fields. Fetch up to 1000 records per call. |
remove_extension | destructive | Remove an installed extension from a dashboard. |
rename_extension | write | Rename an installed extension. |
rename_field | write | Rename a field (column) in an Airtable table. Pre-validates the field exists before mutating. |
rename_record_template | write | Rename an existing record template. |
rename_table | write | Rename a table in an Airtable base. |
rename_view | write | Rename a view. |
rename_view_section | write | Rename a sidebar section. |
reorder_view_fields | read | Reorder the fields (columns) displayed in a view. Accepts a partial map: pass only the field IDs you want to move, e.g. |
requirements | read | What the view should show and how |
search | read | Text to search for (case-insensitive substring match) |
set_calendar_date_columns | write | Set the date-column ranges shown on a Calendar view. Each entry is either { startColumnId } for single-point events or { startColumnId, endColumnId } for range events. The array form lets a single calendar overlay multiple date series at once (e.g. |
set_form_metadata | write | 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 — |
set_form_submission_notification | write | Toggle email-on-submit notifications for a specific user on a form view. Per-user, not per-form (separate from set_form_metadata). |
set_record_template_cell | write | Pre-fill a field value on a record template. CELL OBJECT TYPES (verified via API capture 2026-05-01): Static value (text, number, boolean, single-select choice ID): { |
set_record_template_visible_columns | write | Set which columns are shown (pre-fillable) on a record template. Pass an empty array to show all columns. isPartialSelection:true means only listed columns are shown; false means all are shown. |
set_view_cell_wrap | destructive | Toggle whether long cell values wrap (multi-line) or truncate (single-line with ellipsis). |
set_view_color_config | write | Apply a color config to a view (Kanban / Gallery / Calendar). Currently supports |
set_view_columns | destructive | One-shot view-column reset: hides every column then shows only |
set_view_cover | write | Set the cover-image field and crop/fit mode for Kanban or Gallery views. Pass |
show_or_hide_all_columns | read | Show or hide every column in a view in one call. Use when you want a clean all-visible or all-hidden baseline. Use |
show_or_hide_view_columns | read | Show or hide specific columns in a view without affecting others. Pass field IDs + a visibility flag — every listed ID is set to that state, all other columns are untouched. Use |
sync_base | write | Base-to-base schema + record sync. IMPORTANT: BOTH mode= |
tableId | read | Table ID (tblXXX) for field context |
tableName | read | Name for the new table |
update_extension_state | write | Enable or disable an extension installation. |
update_field_config | write | Update the configuration of any field — computed OR non-computed. Works for formula, rollup, lookup, count, singleSelect, multipleSelects, number, date, text, and all other field types. COMMON typeOptions by fieldType: formula: { formulaText: |
update_field_description | write | Update the description text of a field. |
update_formula_field | write | Update the formula body of an existing formula field — shorthand for |
update_frozen_column_count | write | Set the frozen-column divider position for a grid view. The first N columns from the left are frozen and stay visible during horizontal scroll. |
update_record_template_description | write | Set or update the description text of a record template. |
update_records | write | Update primitive / single-select cells of existing records via cellValuesByColumnId. (Array cells — multi-select, links, attachments — are not set here.) Per-row isolation. |
update_view_description | write | Update the description text of a view. |
update_view_filters | write | Update the filter configuration of a view. Supports AND/OR conjunctions, nested filter groups, and Airtable |
update_view_group_levels | write | Set grouping on a view. Default mode replaces all existing group levels — pass an empty array with operation= |
update_view_row_height | write | Change the row height of a grid view. |
upload_attachment | write | Upload attachments into an attachment cell by URL. Airtable |
validate_formula | read | Validate a formula expression before creating or updating a formula field. Returns whether the formula is valid and what result type it produces (text, number, etc). Use this before create/update to catch errors early. |
viewId | read | View ID (viwXXX) — determines which records are visible |
Trust audit
BLOCKgrade D · trust 61/100 Do not install this without reading the findings. The audit found something that could harm you or your machine.
| Layer | What it checks | Result |
|---|---|---|
| L0 | Provenance & inventory | PASS |
| L1 | Static analysis of the code | FAIL |
| L2 | Instruction surface (what it tells the agent) | PASS |
| L3 | Class-specific surface | WARN |
| L4 | Behavioural (sandbox) | SKIPPED |
What the source does
- Filesystem
- declared (7 observation(s))
- Network
- declared (9 observation(s))
- Shell
- declared (4 observation(s))
- Dependencies
- not all pinned
- Secrets in source
- none-found
Findings (25)
const { stdout } = await exec(const { stdout } = await exec(response = await fetch(`http://127.0.0.1:${port}/mcp`, {const resp = await fetch(`http://127.0.0.1:${status.port}/daemon/session-health`, {const res = await fetch(`http://127.0.0.1:${status.port}/daemon/release-browser`, {const response = await fetch(`http://127.0.0.1:${port}/daemon/health`, {export const ICON_DATA_URI = 'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAIAAAABtCAYAAABp5GmXAAAACXBIWXMAAAlyAAAJcgErz99GAAAAGXRFWHRTb2Z0d2FyZQB3d3cuaW5rc2NhcGUub3Jnm+48GgAADZJJREFUeJztnXuUVNWVh799
airtable-manage-select-choices, delete_record_template, delete_records, delete_table, delete_view, delete_view_section, remove_extension, set_view_cell_wrap, set_view_columns
.vscodeignore
const hash = crypto.createHash('sha1').update(`${salt}-${secret}`, 'ascii').digest('base64')writeFileSync(join(markerDir, 'id_rsa'), 'MARKER-CREDENTIAL-DO-NOT-COPY');
'../../../shared/test-fixtures/process-attribution-cases.json',
const extensionDevelopmentPath = path.resolve(__dirname, '../../');
const vendorPath = path.resolve(__dirname, '../../../src/vendor');
const minifyCmdPath = path.resolve(__dirname, '../../../src/commands/minifyWithLevel.ts');
import type { LsCompletionItem, LsPosition } from '../../types.js';3. VS Code extension via `DaemonManager` — direct HTTP to `http://127.0.0.1:{port}/mcp` with bearer tokenlog('👁️🗨️', 'Hidden Priority Score & Days Open');esbuild, rimraf
@types/adm-zip, terser, @types/archiver, @types/node, @types/vscode, @vscode/test-electron, @vscode/vsce, adm-zip
tsup, typescript, vitest
vscode-languageserver, vscode-languageserver-textdocument, tsup, typescript, vitest
@modelcontextprotocol/sdk, cheerio, dotenv, fetch-cookie, node-fetch, tough-cookie, @ngrok/ngrok, impit
The Airtable MCP server itself — ES modules Node app, **published to npm as `airtable-user-mcp`**. Provides **72 tools** across 16 categories (read, record-read, table-write, table-destructive, field-
- `mcp.authMode` — `browser` (default; headless Chrome mints the cookie, calls go direct-HTTP) / `byo` (cookie-only, no browser; cookie from `~/.airtable-user-mcp/credentials.json` or `AIRTABLE_COOKIE
Gates applied: no_behavioural_pass.
7ca0d8237eaefull audit observations/trust-audit/mcp-server/automations-project__airtable-formula.json · Report an issue / request a re-scanAudit history
Every audit this server has had. A grade with a past is a grade somebody is still checking.
| Date | Source | Verdict | Grade | Score | Change |
|---|---|---|---|---|---|
| 2026-10-08 | 7ca0d8237eae | BLOCK | D | 61 | first audit |
Questions
What is the Airtable Formula MCP server?
VS Code extension and MCP server for Airtable, formula editor, schema tools, and 60+ automation utilities for bases, views, and fields.
What tools does Airtable Formula expose?
100 in total: 44 read-only, 47 that write, and 9 that can delete or overwrite (airtable-manage-select-choices, delete_record_template, delete_records, delete_table, delete_view). Every one is listed on this page with its risk.
Is Airtable Formula safe to connect to an agent?
No — not without reading the findings first. The audit graded it D (61/100) and found 2 critical or high issues in the source. Each one is listed on this page with the file and line it is on. Separately from the audit: 9 of its tools can destroy data, so scope the token you give it to what you actually need.
What credentials does Airtable Formula need?
It reads AIRTABLE_AUTH_MODE, AIRTABLE_MAX_AUTH_QUEUE, AIRTABLE_OTP_SECRET, AIRTABLE_PASSWORD and AIRTABLE_TOTP_SECRET from the environment. Give it a token scoped to the least it needs — an agent that can be talked into calling a tool can be talked into calling it with your credentials.
How does Airtable Formula run?
It speaks stdio and streamable-http, so it runs as a local process your client starts. It is published on npm as @airtable-formula/webview at 2.0.0.
How current is this page?
The grade is for one exact copy of the source (7ca0d8237eae), read on 2026-10-08. The repository is watched and re-audited when it changes.