@hackspaces/airtable-connect-mcp
v0.2.2
Published
Read-only, PII-redacting MCP server for the Airtable Web API
Downloads
392
Maintainers
Readme
airtable-connect-mcp
A read-only MCP server for the Airtable Web
API that redacts personal data by default. It also gives the model a
reliable search path: structured, column-based filters compiled into correct
Airtable formula, so it never hand-writes finicky filterByFormula.
Install
Install from npm (Node >= 18.18):
npm install -g @hackspaces/airtable-connect-mcpThis server is installed and run with node, not npx.
Configure
Create a Personal Access Token at https://airtable.com/create/tokens with scopes
data.records:read and schema.bases:read, and link the base(s) you want
to read. A token only sees the bases linked to it.
Two ways to supply the token:
- Bring-your-own (per call): pass it as
_airtableAuthin the tool arguments ({ "token": "pat..." }). In the gateway this is theX-Airtable-Tokenheader. Wins over the env token; lets each user reach their own bases with no central linking. - Shared fallback (env):
AIRTABLE_ACCESS_TOKEN, used when a call brings no token of its own.
AIRTABLE_ACCESS_TOKEN=pat... \
node "$(npm root -g)/@hackspaces/airtable-connect-mcp/dist/index.js"Register with any MCP client by pointing node at the installed entrypoint:
{
"mcpServers": {
"airtable": {
"command": "node",
"args": ["<entrypoint>/@hackspaces/airtable-connect-mcp/dist/index.js"],
"env": { "AIRTABLE_ACCESS_TOKEN": "pat..." }
}
}
}Tools (read-only)
| Tool | Purpose |
|------|---------|
| airtable_list_bases | List the bases this token can access |
| airtable_get_base_schema | Tables and fields (id, name, type, enum choices) |
| airtable_list_records | List records, paginated by cursor |
| airtable_get_record | Get one record by id |
| airtable_search_records | Search with structured filters and/or free text |
Workflow: list bases, get the base schema to learn columns and enum choices, then search. If a base is not reachable, the tool tells you to ask the team to add it to the token, with the base id.
Search
Pass structured filters rather than raw formula:
{
"baseId": "app...", "table": "Tasks",
"filters": [{ "field": "Status", "operator": "eq", "value": "Open" }],
"match": "all",
"query": "design", "queryFields": ["Name", "Notes"]
}Operators: eq, neq, gt, gte, lt, lte, contains, notContains, isEmpty,
isNotEmpty. For enum (single/multi select) columns use the exact choice values
from airtable_get_base_schema. A raw filterByFormula escape hatch exists for
power use. Long filters are sent via POST, so they never hit a URL length limit.
Pagination
List and search return up to pageSize records (max 100) and a next cursor
when more exist. Pass next back as offset to fetch the following page. Omit
maxRecords to page through freely.
PII protection
Airtable columns are user-defined, so column names cannot be trusted. Redaction runs three layers, on by default:
- Value patterns: emails and SSN-shaped values are masked in any field, whatever the column is called (even buried in free text).
- Name heuristics: columns that look personal (name, email, phone, address, asurite, ...) are redacted whole.
- Config: extra field names to redact, and an allow list to keep, in
config/pii-redaction.json.
Opt-out: set AIRTABLE_MCP_ALLOW_PII=true to disable redaction. Use only in
trusted contexts.
Development
npm run dev # run from source (stdio)
npm test # unit tests
npm run build # compile to dist/
npm run demo # dev harness against a live baseVersioning
Single-sourced from the root VERSION file; scripts/sync-version.sh
propagates it into package.json. See CHANGELOG.md.
