bcharleson/airtable-agent-cli

CLI and MCP server for the Airtable platform — full API coverage for AI agents

★ 3Forks 0TypeScriptGitHub ↗Compare

README

airtable-agent-cli

A full-coverage CLI and MCP server for the Airtable API — built for AI agents and humans alike.

  • 21 commands across bases, tables, fields, records, views, and webhooks
  • MCP server — plug directly into Claude, Cursor, VS Code, or any MCP-compatible AI client
  • Dual interface — every command works as both a CLI tool and an MCP tool from the same codebase
  • Agent-native — rich descriptions, upsert, formula filtering, batch ops, and pagination built in

Installation

npm install -g airtable-agent-cli

Or use without installing:

npx airtable-agent-cli --help

Authentication

Get a Personal Access Token at airtable.com/create/tokens.

Required scopes:

  • schema.bases:read — list bases, tables, fields
  • schema.bases:write — create/update tables and fields
  • data.records:read — read records
  • data.records:write — create, update, delete, upsert records
  • webhook:manage — manage webhooks

Store credentials

airtable login
# or non-interactively:
airtable login --token pat_XXXXXXXXXX

Environment variable

export AIRTABLE_TOKEN=pat_XXXXXXXXXX

Per-command flag

airtable records list --base appXXX --table tblXXX --token pat_XXXXXXXXXX

Commands

Bases

airtable bases list                            # List all accessible bases
airtable bases schema --base appXXX            # Full schema: tables + fields + views

Tables

airtable tables list --base appXXX
airtable tables create --base appXXX --name "Contacts" \
  --fields '[{"name":"Name","type":"singleLineText"}]'
airtable tables update --base appXXX --table tblXXX --name "New Name"

Fields

airtable fields list --base appXXX --table tblXXX
airtable fields create --base appXXX --table tblXXX --name "Email" --type email
airtable fields create --base appXXX --table tblXXX --name "Status" --type singleSelect \
  --options '{"choices":[{"name":"Active"},{"name":"Inactive"}]}'
airtable fields update --base appXXX --table tblXXX --field fldXXX --name "New Name"

Records

# List with filtering, sorting, pagination
airtable records list --base appXXX --table tblXXX
airtable records list --base appXXX --table tblXXX --formula "AND({Status}='Active')"
airtable records list --base appXXX --table tblXXX --select "Name,Email,Status"
airtable records list --base appXXX --table tblXXX --sort "Name:asc,CreatedTime:desc"
airtable records list --base appXXX --table tblXXX --view "Grid view" --max-records 50
airtable records list --base appXXX --table tblXXX --offset "itrXXXXXXXXXXXXXX"

# Get single record
airtable records get --base appXXX --table tblXXX --record recXXX

# Create (single or batch, max 10)
airtable records create --base appXXX --table tblXXX \
  --fields '{"Name":"Alice","Email":"[email protected]"}'
airtable records create --base appXXX --table tblXXX \
  --records '[{"fields":{"Name":"Alice"}},{"fields":{"Name":"Bob"}}]'

# Partial update / PATCH (only provided fields change)
airtable records update --base appXXX --table tblXXX \
  --record recXXX --fields '{"Status":"Done"}'
airtable records update --base appXXX --table tblXXX \
  --records '[{"id":"recAAA","fields":{"Status":"Done"}},{"id":"recBBB","fields":{"Status":"Active"}}]'

# Full replace / PUT (unincluded fields are cleared)
airtable records replace --base appXXX --table tblXXX \
  --record recXXX --fields '{"Name":"Alice","Status":"Active"}'

# Delete (single or comma-separated batch, max 10)
airtable records delete --base appXXX --table tblXXX --record recXXX
airtable records delete --base appXXX --table tblXXX --records "recAAA,recBBB,recCCC"

# Upsert — update if exists, create if not
airtable records upsert --base appXXX --table tblXXX \
  --merge-on "Email" \
  --fields '{"Name":"Alice","Email":"[email protected]","Status":"Active"}'
airtable records upsert --base appXXX --table tblXXX \
  --merge-on "Email,ExternalId" \
  --records '[{"fields":{"Email":"[email protected]","Name":"Alice"}},{"fields":{"Email":"[email protected]","Name":"Bob"}}]'

Views

airtable views list --base appXXX             # Enterprise only

Webhooks

airtable webhooks list --base appXXX
airtable webhooks create --base appXXX \
  --notify-url "https://example.com/hook" \
  --data-types "tableData"
airtable webhooks create --base appXXX \
  --notify-url "https://example.com/hook" \
  --data-types "tableData,tableFields,tableMetadata" \
  --record-scope tblXXX
airtable webhooks refresh --base appXXX --webhook achXXX
airtable webhooks payloads --base appXXX --webhook achXXX
airtable webhooks delete --base appXXX --webhook achXXX

Output Formats

# Compact JSON (default — pipe-friendly)
airtable records list --base appXXX --table tblXXX

# Pretty-printed JSON
airtable records list --base appXXX --table tblXXX --pretty

# Select specific output fields
airtable records list --base appXXX --table tblXXX --fields id,fields

# Quiet — exit codes only (0 = success, 1 = error)
airtable records delete --base appXXX --table tblXXX --record recXXX --quiet

MCP Server (AI Agent Integration)

Run as an MCP server so AI assistants can call Airtable directly:

airtable mcp

Claude Desktop / Cursor / VS Code

Add to your MCP config (~/.claude/config.json, .cursor/mcp.json, etc.):

{
  "mcpServers": {
    "airtable": {
      "command": "npx",
      "args": ["airtable-agent-cli", "mcp"],
      "env": {
        "AIRTABLE_TOKEN": "pat_XXXXXXXXXX"
      }
    }
  }
}

If installed globally:

{
  "mcpServers": {
    "airtable": {
      "command": "airtable",
      "args": ["mcp"],
      "env": {
        "AIRTABLE_TOKEN": "pat_XXXXXXXXXX"
      }
    }
  }
}

Available MCP Tools

All 21 CLI commands are exposed as MCP tools with the same names:

Tool Description
bases_list List all accessible bases
bases_schema Get full base schema (tables, fields, views)
tables_list List tables in a base
tables_create Create a new table
tables_update Update table name/description
fields_list List fields in a table
fields_create Create a new field
fields_update Update field name/description
records_list List records with filtering, sorting, pagination
records_get Get a single record by ID
records_create Create one or more records
records_update Partially update records (PATCH)
records_replace Fully replace records (PUT)
records_delete Delete one or more records
records_upsert Upsert records by merge fields
views_list List views in a base
webhooks_list List webhooks
webhooks_create Create a webhook
webhooks_delete Delete a webhook
webhooks_refresh Refresh webhook expiration
webhooks_payloads Fetch webhook payloads

Scripting & Piping

# Get all active contacts
airtable records list --base appXXX --table tblXXX \
  --formula "{Status}='Active'" | jq '.records[].fields'

# Export record IDs
airtable records list --base appXXX --table tblXXX \
  --fields id | jq -r '.[].id'

# Pipe bases list into jq
airtable bases list | jq '.bases[] | {id, name}'

Architecture

This tool follows a dual CLI/MCP pattern:

  • A single CommandDefinition[] array powers both the Commander.js CLI and the MCP server
  • Zod schemas are the source of truth for validation, help text, and MCP input schemas
  • Every command works identically whether called from the terminal or by an AI agent
CommandDefinition {
  name        →  MCP tool name ("records_list")
  group       →  CLI group ("records")
  subcommand  →  CLI subcommand ("list")
  inputSchema →  Zod schema → CLI validation + MCP input schema
  handler     →  Async function called by both CLI and MCP
}

License

MIT

Contributors

bcharleson

Issues