NimbleBrainInc/mcp-airtable
If you are the rightful owner of mcp-airtable and would like to certify it and/or have it hosted online, please leave a comment on the right or send an email to henry@mcphub.com.
MCP server for managing Airtable bases, tables, records, and views programmatically.
Airtable MCP Server
MCP server for managing Airtable bases, tables, records, and views. Perform CRUD operations, search with formulas, and manage your Airtable data programmatically.
Features
- Base Management: List and explore accessible bases
- Schema Access: Get table structures and field definitions
- Record Operations: Create, read, update, and delete records
- Advanced Search: Filter records using Airtable formulas
- Bulk Operations: Create or update up to 10 records at once
- View Management: List and work with table views
- Pagination: Handle large datasets with offset-based pagination
- Flexible Filtering: Sort and filter records with powerful queries
Setup
Prerequisites
- Airtable account
- Access token with appropriate scopes
Environment Variables
AIRTABLE_ACCESS_TOKEN
(required): Your Airtable personal access token
How to create an access token:
- Go to airtable.com/create/tokens
- Click "Create new token"
- Give your token a name (e.g., "MCP Server Access")
- Add the required scopes:
data.records:read
- Read recordsdata.records:write
- Create, update, delete recordsschema.bases:read
- Read base schemas
- Add access to specific bases or select "All current and future bases"
- Click "Create token" and copy it immediately
- Store it securely as
AIRTABLE_ACCESS_TOKEN
Available Tools
Base Management Tools
list_bases
List all accessible Airtable bases.
Example:
bases = await list_bases()
Response includes:
- Base IDs
- Base names
- Permission levels
get_base_schema
Get complete schema for a base including tables and fields.
Parameters:
base_id
(string, required): Base ID (e.g., 'appXXXXXXXXXXXXXX')
Example:
schema = await get_base_schema(base_id="appAbc123")
Response includes:
- Table IDs and names
- Field definitions with types
- View information
Record Listing & Search Tools
list_records
List records from a table with advanced filtering and sorting.
Parameters:
base_id
(string, required): Base IDtable_id_or_name
(string, required): Table ID or namefields
(list, optional): Specific fields to returnfilter_by_formula
(string, optional): Airtable formula filtermax_records
(int, optional): Maximum records to returnpage_size
(int, optional): Records per page (max: 100)sort
(list, optional): Sort configurationview
(string, optional): View name or IDoffset
(string, optional): Pagination offset
Example:
# List all records
records = await list_records(
base_id="appAbc123",
table_id_or_name="Contacts"
)
# List with filters and sorting
records = await list_records(
base_id="appAbc123",
table_id_or_name="Contacts",
fields=["Name", "Email", "Status"],
filter_by_formula="{Status} = 'Active'",
sort=[{"field": "Name", "direction": "asc"}],
max_records=50
)
# Pagination
page1 = await list_records(
base_id="appAbc123",
table_id_or_name="Contacts",
page_size=100
)
# Use offset from page1 response for next page
page2 = await list_records(
base_id="appAbc123",
table_id_or_name="Contacts",
page_size=100,
offset=page1["offset"]
)
search_records
Search records using Airtable formula filters.
Parameters:
base_id
(string, required): Base IDtable_id_or_name
(string, required): Table ID or nameformula
(string, required): Airtable formulafields
(list, optional): Fields to returnsort
(list, optional): Sort configurationmax_records
(int, optional): Maximum records
Example:
# Search with complex formula
results = await search_records(
base_id="appAbc123",
table_id_or_name="Contacts",
formula="AND({Status} = 'Active', {Age} > 25, FIND('gmail', {Email}))",
fields=["Name", "Email", "Age"],
sort=[{"field": "Age", "direction": "desc"}],
max_records=20
)
get_record
Get a specific record by ID.
Parameters:
base_id
(string, required): Base IDtable_id_or_name
(string, required): Table ID or namerecord_id
(string, required): Record ID (e.g., 'recXXXXXXXXXXXXXX')
Example:
record = await get_record(
base_id="appAbc123",
table_id_or_name="Contacts",
record_id="recDef456"
)
Record Creation & Update Tools
create_record
Create a new record in a table.
Parameters:
base_id
(string, required): Base IDtable_id_or_name
(string, required): Table ID or namefields
(dict, required): Field names and values
Example:
new_record = await create_record(
base_id="appAbc123",
table_id_or_name="Contacts",
fields={
"Name": "John Doe",
"Email": "john@example.com",
"Age": 30,
"Status": "Active"
}
)
update_record
Update an existing record.
Parameters:
base_id
(string, required): Base IDtable_id_or_name
(string, required): Table ID or namerecord_id
(string, required): Record IDfields
(dict, required): Fields to updatereplace_all
(bool, optional): If True, replace all fields (PUT). If False, merge (PATCH). Default: False
Example:
# Partial update (merge fields)
updated = await update_record(
base_id="appAbc123",
table_id_or_name="Contacts",
record_id="recDef456",
fields={
"Status": "Inactive",
"Notes": "Updated status"
},
replace_all=False
)
# Complete replacement
replaced = await update_record(
base_id="appAbc123",
table_id_or_name="Contacts",
record_id="recDef456",
fields={
"Name": "Jane Smith",
"Email": "jane@example.com",
"Age": 28
},
replace_all=True
)
delete_record
Delete a record from a table.
Parameters:
base_id
(string, required): Base IDtable_id_or_name
(string, required): Table ID or namerecord_id
(string, required): Record ID
Example:
result = await delete_record(
base_id="appAbc123",
table_id_or_name="Contacts",
record_id="recDef456"
)
Bulk Operations Tools
bulk_create_records
Create multiple records at once (up to 10 per request).
Parameters:
base_id
(string, required): Base IDtable_id_or_name
(string, required): Table ID or namerecords
(list, required): List of record objects with fields (max: 10)
Example:
results = await bulk_create_records(
base_id="appAbc123",
table_id_or_name="Contacts",
records=[
{"Name": "Alice", "Email": "alice@example.com", "Age": 25},
{"Name": "Bob", "Email": "bob@example.com", "Age": 30},
{"Name": "Charlie", "Email": "charlie@example.com", "Age": 35}
]
)
bulk_update_records
Update multiple records at once (up to 10 per request).
Parameters:
base_id
(string, required): Base IDtable_id_or_name
(string, required): Table ID or namerecords
(list, required): List with 'id' and 'fields' (max: 10)replace_all
(bool, optional): Replace all fields or merge. Default: False
Example:
results = await bulk_update_records(
base_id="appAbc123",
table_id_or_name="Contacts",
records=[
{
"id": "recDef456",
"fields": {"Status": "Active"}
},
{
"id": "recGhi789",
"fields": {"Status": "Inactive"}
}
],
replace_all=False
)
Schema & View Tools
get_table_fields
Get field definitions for a specific table.
Parameters:
base_id
(string, required): Base IDtable_id_or_name
(string, required): Table ID or name
Example:
fields = await get_table_fields(
base_id="appAbc123",
table_id_or_name="Contacts"
)
Response includes:
- Field IDs
- Field names
- Field types
- Field options
list_views
List all views in a table.
Parameters:
base_id
(string, required): Base IDtable_id_or_name
(string, required): Table ID or name
Example:
views = await list_views(
base_id="appAbc123",
table_id_or_name="Contacts"
)
Response includes:
- View IDs
- View names
- View types (grid, form, calendar, etc.)
Airtable Formula Syntax
Airtable uses a formula language similar to Excel for filtering and calculations.
Basic Operators
- Comparison:
=
,!=
,>
,<
,>=
,<=
- Logical:
AND()
,OR()
,NOT()
- Text:
FIND()
,SEARCH()
,LEFT()
,RIGHT()
,MID()
,LEN()
- Math:
+
,-
,*
,/
,MOD()
,ROUND()
- Date:
TODAY()
,NOW()
,DATEADD()
,DATEDIF()
,IS_AFTER()
,IS_BEFORE()
Formula Examples
Filter by single condition:
"{Status} = 'Active'"
Filter by multiple conditions:
"AND({Status} = 'Active', {Age} > 25)"
Filter with OR:
"OR({Status} = 'Active', {Status} = 'Pending')"
Text search:
"FIND('gmail', {Email})" # Contains gmail
Date filters:
"IS_AFTER({Created}, '2024-01-01')"
Complex formula:
"AND(
OR({Status} = 'Active', {Status} = 'Pending'),
{Age} >= 18,
FIND('@company.com', {Email})
)"
Empty/not empty:
"{Email} != ''" # Email is not empty
"{Phone} = ''" # Phone is empty
Sorting Records
Sort by one or more fields:
# Single field
sort=[{"field": "Name", "direction": "asc"}]
# Multiple fields
sort=[
{"field": "Status", "direction": "desc"},
{"field": "Name", "direction": "asc"}
]
Directions: asc
(ascending) or desc
(descending)
Field Types
Airtable supports various field types:
Basic Types
- Single line text: Short text strings
- Long text: Multi-line text
- Number: Integers or decimals
- Checkbox: Boolean true/false
- Date: Date values
- Phone number: Phone numbers
- Email: Email addresses
- URL: Website URLs
Selection Types
- Single select: Choose one option
- Multiple select: Choose multiple options
- Collaborator: Airtable users
Advanced Types
- Attachment: Files and images
- Link to another record: Relationships
- Lookup: Values from linked records
- Rollup: Aggregations from linked records
- Formula: Calculated values
- Count: Count of linked records
- Rating: Star ratings
- Barcode: Barcode scanner
- Button: Action buttons
Pagination
Airtable returns up to 100 records per request. Use pagination for more:
all_records = []
offset = None
while True:
response = await list_records(
base_id="appAbc123",
table_id_or_name="Contacts",
page_size=100,
offset=offset
)
all_records.extend(response["records"])
# Check if there are more pages
if "offset" in response:
offset = response["offset"]
else:
break # No more records
Rate Limits
Airtable enforces rate limits:
- 5 requests per second per base
- Applies to all API operations on a specific base
- Exceeding limits returns HTTP 429 error
Best practices:
- Implement exponential backoff for retries
- Use bulk operations when possible (10 records per request)
- Cache frequently accessed data
- Batch multiple operations together
ID Formats
Base ID
- Format:
app
+ 14 alphanumeric characters - Example:
appAbc123Def456Gh
Table ID
- Can use table ID or URL-encoded table name
- Table ID format:
tbl
+ alphanumeric - Example:
tblXyz789
orContacts
Record ID
- Format:
rec
+ 14 alphanumeric characters - Example:
recDef456Ghi789Jk
View ID
- Format:
viw
+ alphanumeric - Example:
viwMno012Pqr345St
Working with Attachments
Upload attachments as URLs:
await create_record(
base_id="appAbc123",
table_id_or_name="Documents",
fields={
"Name": "My Document",
"Files": [
{"url": "https://example.com/file1.pdf"},
{"url": "https://example.com/image.jpg"}
]
}
)
Error Handling
Common error codes:
- 401 Unauthorized: Invalid or missing access token
- 403 Forbidden: Insufficient permissions
- 404 Not Found: Base, table, or record doesn't exist
- 422 Unprocessable: Invalid field values or formula syntax
- 429 Too Many Requests: Rate limit exceeded
- 503 Service Unavailable: Airtable service issue
Error response format:
{
"error": {
"type": "INVALID_REQUEST_UNKNOWN",
"message": "Error description"
}
}
Best Practices
- Use bulk operations: Create/update up to 10 records per request
- Cache base schemas: Schemas don't change frequently
- Filter on the server: Use formulas instead of filtering locally
- Limit returned fields: Request only needed fields
- Handle rate limits: Implement retry logic with backoff
- Use views: Leverage Airtable views for pre-filtered data
- Validate data: Check field types before creating/updating
- URL-encode table names: Use proper encoding for table names with spaces
Use Cases
- CRM Integration: Sync customer data with Airtable
- Project Management: Track tasks and milestones
- Content Management: Manage blog posts and media
- Inventory Tracking: Monitor stock levels and orders
- Event Management: Coordinate attendees and schedules
- Form Processing: Store and manage form submissions
- Data Migration: Import/export data programmatically
- Automation: Build workflows with Airtable as data store
API Documentation
For detailed information:
Security Notes
- Never commit tokens: Store access tokens securely
- Scope permissions: Grant minimum required access
- Rotate tokens: Regularly update access tokens
- Use HTTPS: All API calls use HTTPS
- Audit access: Review token usage regularly
- Revoke unused tokens: Delete tokens no longer needed