|
| 1 | +--- |
| 2 | +name: airtable-cli |
| 3 | +description: >- |
| 4 | + Lists bases, reads and writes records, manages tables and fields, filters and |
| 5 | + searches data in Airtable via the `airtable-mcp` CLI. Use when the task |
| 6 | + involves Airtable data or the user mentions airtable-mcp, bases, tables, |
| 7 | + records, or fields. |
| 8 | +--- |
| 9 | + |
| 10 | +# airtable-mcp |
| 11 | + |
| 12 | +## Self-discovery |
| 13 | + |
| 14 | +Tools are fetched from the MCP server at runtime, so the CLI never has a hardcoded command list. Discover what's available: |
| 15 | + |
| 16 | +```sh |
| 17 | +airtable-mcp tools # human-readable list |
| 18 | +airtable-mcp tools --json # machine-parseable list |
| 19 | +airtable-mcp <tool> --help # show flags and descriptions for a tool |
| 20 | +``` |
| 21 | + |
| 22 | +Run `airtable-mcp tools` before assuming a tool exists. Tool names, arguments, and output shapes can change between server releases without a CLI update. |
| 23 | + |
| 24 | +## Install |
| 25 | + |
| 26 | +```sh |
| 27 | +npm install -g @airtable/mcp-cli |
| 28 | +``` |
| 29 | + |
| 30 | +## Auth |
| 31 | + |
| 32 | +The CLI needs an Airtable personal access token (PAT). Two paths: |
| 33 | + |
| 34 | +**Environment variable (preferred for scripts/agents):** |
| 35 | + |
| 36 | +```sh |
| 37 | +export AIRTABLE_TOKEN=pat_xxx |
| 38 | +``` |
| 39 | + |
| 40 | +**Interactive configure (stores token in `~/.airtable/cli.json` with 0600 permissions):** |
| 41 | + |
| 42 | +```sh |
| 43 | +airtable-mcp configure |
| 44 | +``` |
| 45 | + |
| 46 | +Create tokens at https://airtable.com/create/tokens. Ensure the token has the scopes required by the tools being called. |
| 47 | + |
| 48 | +`AIRTABLE_TOKEN` takes precedence over saved profiles when no `--profile` flag is set. Never log or echo tokens. |
| 49 | + |
| 50 | +## Quick reference |
| 51 | + |
| 52 | +| Task | Command | |
| 53 | +| ---------------------- | ------------------------------------------------------- | |
| 54 | +| Set up credentials | `airtable-mcp configure` | |
| 55 | +| Add a named profile | `airtable-mcp configure --profile work` | |
| 56 | +| Check auth status | `airtable-mcp whoami` | |
| 57 | +| Remove credentials | `airtable-mcp logout` | |
| 58 | +| Remove all profiles | `airtable-mcp logout --all` | |
| 59 | +| List available tools | `airtable-mcp tools` | |
| 60 | +| Run a tool | `airtable-mcp <tool> --flagName value` | |
| 61 | +| Get tool help | `airtable-mcp <tool> --help` | |
| 62 | +| Pass args via stdin | `echo '{"key":"val"}' \| airtable-mcp <tool> --input -` | |
| 63 | +| Bypass tool cache | `airtable-mcp <tool> --refresh` | |
| 64 | +| Suppress status msgs | `airtable-mcp <tool> -q` | |
| 65 | +| Raw text output | `airtable-mcp <tool> --output raw` | |
| 66 | +| Use a specific profile | `airtable-mcp <tool> --profile work` | |
| 67 | + |
| 68 | +Tool names use hyphens on the CLI (`list-records`) but underscores in MCP (`list_records`). The CLI translates automatically. |
| 69 | + |
| 70 | +## Workflow |
| 71 | + |
| 72 | +1. **Auth** — set `AIRTABLE_TOKEN` or run `airtable-mcp configure` |
| 73 | +2. **Discover** — run `airtable-mcp tools` to see available tools |
| 74 | +3. **Inspect** — run `airtable-mcp <tool> --help` for flags and descriptions |
| 75 | +4. **Check access** — in `tools --json` output, check the `access` field: `read-only`, `write`, or `destructive`. Confirm with the user before running `destructive` tools. |
| 76 | +5. **Execute** — run `airtable-mcp <tool> --flagName value` |
| 77 | + |
| 78 | +## Output & automation |
| 79 | + |
| 80 | +- Default output is formatted JSON to stdout. Status messages go to stderr. |
| 81 | +- `--json` on `tools` gives a JSON array of `{name, title, access}`. |
| 82 | +- `-q` / `--quiet` suppresses stderr status messages (cache warnings, etc). |
| 83 | +- `--output raw` returns the raw server response text instead of parsed JSON. |
| 84 | +- `--input -` reads tool arguments as a JSON object from stdin, bypassing flag parsing. |
| 85 | +- Exit codes: `0` success, `1` error (auth, tool failure, not found), `2` usage error (bad flags, bad input). |
| 86 | + |
| 87 | +## Common tasks |
| 88 | + |
| 89 | +**Find a base and list its tables:** |
| 90 | + |
| 91 | +```sh |
| 92 | +airtable-mcp search-bases --searchQuery "Project Tracker" -q |
| 93 | +airtable-mcp list-tables-for-base --baseId appK9MtBqFw3o5jGN -q |
| 94 | +``` |
| 95 | + |
| 96 | +**List records with specific fields:** |
| 97 | + |
| 98 | +```sh |
| 99 | +airtable-mcp list-records-for-table \ |
| 100 | + --baseId appK9MtBqFw3o5jGN --tableId tblL4GpTfEz8byRsW \ |
| 101 | + --fieldIds '["Name","Status"]' --pageSize 10 -q |
| 102 | +``` |
| 103 | + |
| 104 | +**Filter records** — filters use structured JSON, not formula strings. Wrap conditions in an `operands` array; the top-level `operator` defaults to `and` if omitted: |
| 105 | + |
| 106 | +```sh |
| 107 | +airtable-mcp list-records-for-table \ |
| 108 | + --baseId appK9MtBqFw3o5jGN --tableId tblL4GpTfEz8byRsW \ |
| 109 | + --filters '{"operator":"and","operands":[{"operator":"=","operands":["Status","Done"]}]}' -q |
| 110 | +``` |
| 111 | + |
| 112 | +For select fields, filter by choice ID (from `get-table-schema`), not the display name. The `airtable-filters` skill covers compound filters, date filters, and operator-by-field-type details. |
| 113 | + |
| 114 | +**Search records** — use `search-records` for free-text/fuzzy queries on large tables. Use `list-records-for-table` with `--filters` when filtering by exact field values: |
| 115 | + |
| 116 | +```sh |
| 117 | +airtable-mcp search-records \ |
| 118 | + --baseId appK9MtBqFw3o5jGN --table tblL4GpTfEz8byRsW \ |
| 119 | + --query "acme" --fields '["Name","Notes"]' -q |
| 120 | +``` |
| 121 | + |
| 122 | +Pass `--fields ALL_SEARCHABLE_FIELDS` to search across every indexed field. Date, rating, checkbox, and button fields are not searchable. |
| 123 | + |
| 124 | +**Update records** — complex args are easier via `--input -`: |
| 125 | + |
| 126 | +```sh |
| 127 | +echo '{"baseId":"appK9MtBqFw3o5jGN","tableId":"tblL4GpTfEz8byRsW","records":[{"id":"recVnR3xPq8sD2yLk","fields":{"fld8WsrpLHHevsnW8":"Done"}}]}' \ |
| 128 | + | airtable-mcp update-records-for-table --input - -q |
| 129 | +``` |
| 130 | + |
| 131 | +Select field values are returned as objects (`{"id":"sel...","name":"Done"}`) but must be written as plain strings (`"Done"`). Record field keys in create/update currently require field IDs (`fldXXX`) — use `get-table-schema` to resolve names to IDs before writing. Note that `fieldIds`, `sort`, and `filters` accept both names and IDs. |
| 132 | + |
| 133 | +## Gotchas |
| 134 | + |
| 135 | +| Problem | Cause | Fix | |
| 136 | +| -------------------------------------------- | ------------------------------------------------------------------ | ------------------------------------------------------------------------ | |
| 137 | +| `Unknown tool: X` | Tool name doesn't exist on the server or cache is stale | Run `airtable-mcp tools --refresh` to refresh, then retry | |
| 138 | +| `Authentication failed` | Token expired, revoked, or wrong | Run `airtable-mcp configure` or check `AIRTABLE_TOKEN` | |
| 139 | +| `Access denied` | Token missing required scopes | Add scopes at https://airtable.com/create/tokens | |
| 140 | +| `Connection timed out` | Server unreachable (10s timeout) | Check network; CLI falls back to stale cache if available | |
| 141 | +| Boolean flags take no value | `--dryRun true` passes `"true"` as next arg | Use `--dryRun` alone (booleans are presence-based) | |
| 142 | +| Array/object args fail | Value isn't valid JSON | Pass as JSON string: `--fieldMappings '{"a":"b"}'` | |
| 143 | +| Filter rejected at top level | Single condition passed without `operands` wrapper | Wrap in `{"operands":[...]}` (`operator` defaults to `and`) | |
| 144 | +| Sort key is `fieldId` not `field` | `--sort '[{"field":"Name"}]'` silently ignored | Use `{"fieldId":"Name","direction":"asc"}` — accepts field IDs or names | |
| 145 | +| Select filter returns no matches | Filtering by display name instead of choice ID | Run `get-table-schema` first to get `sel...` choice IDs | |
| 146 | +| `INVALID_RECORDS` on batch write | Batch limit is 10 records per request (default; varies by account) | Split into chunks of ≤10 and check `<tool> --help` for the current limit | |
| 147 | +| Permission error on `list-records-for-table` | User has interface-only access to the base | Use `list-records-for-page` / `get-record-for-page` instead | |
| 148 | +| Endpoints restricted | CLI only allows HTTPS on `*.airtable.com` | Cannot point at arbitrary servers (security constraint) | |
0 commit comments