·

Airtable MCP With Cursor

Set up Airtable MCP in Cursor so your AI agent can read and update bases and records right from your editor.

Cursor's pitch for Airtable MCP is different from a terminal agent's: the value is generating code artifacts — TypeScript types, config objects, seed scripts — directly from a live Airtable schema, without leaving the editor to cross-reference field names in a browser tab. This topic covers Agent Mode setup, type/config generation, keeping feature flags in sync with requirement status, and where Cursor's implementation falls short of a dedicated CLI agent.

Connecting Airtable MCP to Cursor Agent Mode

Cursor reads MCP server config from .cursor/mcp.json at the project root, or the equivalent global file for servers you want available across all projects:

{
  "mcpServers": {
    "airtable": {
      "command": "npx",
      "args": ["-y", "airtable-mcp-server"],
      "env": {
        "AIRTABLE_API_KEY": "patAbC123dEf456.gh789ij012kl345mn678op901qr234st567uv890wx123yz456ab789cd012"
      }
    }
  }
}

Cursor doesn't consistently resolve ${VAR}-style interpolation in .cursor/mcp.json across all versions — check your installed version's behavior before relying on it, and if in doubt, keep the literal token out of the file entirely by loading it from a gitignored .env and referencing it through a wrapper script instead:

{
  "mcpServers": {
    "airtable": {
      "command": "sh",
      "args": ["-c", "source .env && npx -y airtable-mcp-server"]
    }
  }
}

After saving the config, open Cursor's settings (Cmd/Ctrl+Shift+J) → MCP tab, and confirm the airtable server shows a green status dot with its tool count. Cursor requires switching the chat panel to Agent Mode (not the default Ask/Edit modes) for MCP tool calls to be available at all — this trips up developers who configure the server correctly, then wonder why the agent never seems to use it: Ask mode simply doesn't have tool access.

Once in Agent Mode, verify tool availability directly in a prompt:

List the MCP tools you have access to for Airtable.

Cursor's Agent Mode will enumerate the connected tool set, confirming list_bases, list_records, create_record, etc. are visible before you build a real workflow around them.

Tips
- Confirm you're in Agent Mode, not Ask or Edit mode, before assuming MCP tools aren't working — this is the single most common "it's not connecting" report that turns out to be a mode setting.
- Avoid literal PATs in .cursor/mcp.json if the file is anywhere near being committed; use a wrapper script sourcing a gitignored .env if variable interpolation isn't reliable in your Cursor version.
- Re-check the MCP tab's green/red status dot after any Cursor update — MCP server compatibility has shifted across minor versions more than once.


Generating Types and Config from an Airtable Schema

This is where Cursor genuinely shines relative to a terminal-only client: it can read the schema and immediately write a typed file into your codebase in the same turn, because it has direct filesystem write access alongside the MCP tool call.

Read the schema of the "Requirements" table in base appXXXXXXXXXXXXXX using
Airtable MCP. Generate a TypeScript interface matching its fields, using the
exact field names as keys, and write it to src/types/airtable-requirements.ts.
Map Airtable field types to TS types: single line text/long text -> string,
number -> number, single select -> a string literal union of its choices,
checkbox -> boolean, date -> string (ISO), link to another record -> string[].

A describe_table call feeds Cursor the field metadata, including options.choices for single-select fields, and it generates something like:

// Auto-generated from Airtable schema — Requirements table, base appXXXXXXXXXXXXXX
// Regenerate with: Cursor Agent Mode + Airtable MCP describe_table
export interface RequirementRecord {
  id: string;
  Title: string;
  Description: string;
  Priority: "P0" | "P1" | "P2" | "P3";
  Status: "Backlog" | "In Progress" | "In Review" | "Shipped" | "Blocked";
  Owner: string;
  Epic: string[];
  "Created": string;
  "Shipped Date"?: string;
}

The value here isn't novel — you could hand-write this interface — it's that it stays accurate to the live schema on demand, and doing it via the agent takes 30 seconds versus manually cross-referencing every field's exact type and select options in the Airtable UI.

For a build/CI use case, generate a validation config instead of a type:

Generate a Zod schema matching the Requirements table structure, written to
src/schemas/requirement.schema.ts, so we can validate webhook payloads coming
from Airtable automations before processing them.
import { z } from "zod";

export const RequirementSchema = z.object({
  id: z.string(),
  Title: z.string(),
  Description: z.string(),
  Priority: z.enum(["P0", "P1", "P2", "P3"]),
  Status: z.enum(["Backlog", "In Progress", "In Review", "Shipped", "Blocked"]),
  Owner: z.string(),
  Epic: z.array(z.string()),
  Created: z.string(),
  ShippedDate: z.string().optional(),
});

A real limitation worth naming: this generation is a snapshot, not a live binding. If someone adds a new Status option in the Airtable UI next week, your generated union type silently goes stale until you re-run the generation prompt. There's no MCP-driven watch mode — treat it as a "regenerate on schema change" manual step, and consider a pre-commit or CI check that diffs the generated file against a fresh describe_table pull to catch drift.

Tips
- Re-run schema-derived type/schema generation any time a teammate adds a select option or field in the Airtable UI — there's no automatic sync, and a stale union type fails silently at compile time only if you're lucky enough for TS to catch the mismatch.
- Prefer generating both a TS type and a runtime validator (Zod, Yup) from the same schema call in one prompt — catching drift at runtime (webhook payload validation) covers the gap that compile-time types can't.
- Put the base ID and table name in a comment at the top of every generated file — future you, six months later, needs to know exactly what to re-query.


Keeping Feature Flags and Requirement Status in Sync from Cursor

A common pattern for teams that manage feature flags in code (a flags.json, a LaunchDarkly-style config, or a simple enum) but track the decision to ship a feature in Airtable: use Cursor to keep the two in sync in both directions, right where the flag code lives.

Reading the flag state from code and reflecting it into Airtable:

Read src/config/feature-flags.ts. For each flag currently set to enabled: true,
find the matching requirement record in Airtable (match by flag key against
the "Flag Key" field in Requirements) and set its Status to "Shipped" if it's
not already. For flags set to enabled: false, leave Status as-is — a disabled
flag doesn't necessarily mean the requirement isn't done, just not rolled out yet.
// src/config/feature-flags.ts
export const featureFlags = {
  csvExport: { enabled: true, rolloutPercent: 100 },
  bulkOwnerReassign: { enabled: false, rolloutPercent: 0 },
  darkModeV2: { enabled: true, rolloutPercent: 50 },
};

Cursor resolves csvExport and darkModeV2 to their Airtable records via filterByFormula: {Flag Key} = "csvExport", then writes the status update. The reverse direction — generating flag scaffolding from a newly-approved requirement — is where Cursor's code-plus-data access combines well:

Find all requirements in Airtable with Status = "Approved" and Feature Flag
Needed = true (checkbox field) that don't yet have an entry in
src/config/feature-flags.ts. For each, add a new flag entry using the
requirement's "Flag Key" field as the object key, enabled: false,
rolloutPercent: 0, and add a comment above it with the requirement's Title
and a link back to the Airtable record.
// REQ-501: Add bulk export scheduling — https://airtable.com/appXXXXXXXXXXXXXX/tblYYYYYYYYYYYYYY/recZZZZZZZZZZZZZZ
scheduledExport: { enabled: false, rolloutPercent: 0 },

This pattern — Airtable as the record of decision, code as the record of execution, an agent keeping the gap between them small — is more valuable than either full read or full write access alone, and it's specifically well-suited to Cursor because the diff shows up right in your working tree where you'd review it as a normal code change, rather than as an opaque database mutation you have to go verify in a browser.

Tips
- Build the record link (https://airtable.com/{base}/{table}/{record}) into generated code comments — it turns an abstract flag key into a one-click path back to the requirement's full context.
- Run flag-sync prompts as a reviewable diff, not an auto-commit — treat the generated code change exactly like any other Cursor suggestion you'd read before accepting.
- Keep the direction of truth explicit in your prompt every time (code drives Airtable status vs. Airtable drives new flag scaffolding) — conflating both directions in one loose prompt is how a flag gets flipped based on stale requirement data.


Known Limitations and Workarounds for Airtable MCP in Cursor

Cursor's combination of filesystem access and MCP tool calls is powerful but has real edges specific to this pairing:

  • No persistent "current base/table" context across separate chat sessions. Starting a new Cursor chat means re-establishing which base and table you're working with — unlike a long-running terminal session, Cursor's chat history reset (new conversation, or context compaction on a long one) drops the implicit context, and you'll re-run list_bases/describe_table more often than feels necessary. Workaround: keep a short docs/airtable-context.md file in the repo with the base ID, key table names, and field-type notes, and reference it explicitly ("see docs/airtable-context.md for base/table IDs") at the start of new sessions.
  • Agent Mode's tool-call approval prompts interrupt bulk operations more aggressively than a terminal client's permission model. Depending on your configured auto-approve rules, each update_records call in a loop may trigger an individual approval dialog, which is fine for a handful of records and tedious for a 200-record batch. Workaround: configure an explicit auto-approve rule scoped to the Airtable MCP server for read tools, and keep manual approval only on write tools — Cursor's settings allow per-tool auto-approve patterns.
  • Generated code artifacts (types, schemas) have no built-in drift detection. As noted above, there's no watch mode; staleness is silent until something breaks. Workaround: a CI step that re-runs describe_table (via a small script hitting the Airtable API directly, not through Cursor) and diffs against the committed generated file, failing the build on mismatch.
  • Collaborator and attachment field writes carry the same shape gotchas as other clients (object shape for collaborator fields, hosted-URL-only for attachments) — Cursor doesn't add any extra guardrail here beyond what the underlying MCP server provides.
  • Rate-limit backoff is not automatic inside Agent Mode's tool loop. A 429 surfaces as a tool error in the chat; Cursor doesn't pause-and-retry on its own. For any bulk operation exceeding roughly 25 records, explicitly instruct backoff behavior in the prompt, same as you would with OpenCode.

Tips
- Maintain a docs/airtable-context.md reference file with base/table IDs and field notes — it saves a redundant schema-discovery round trip at the start of every new Cursor chat session.
- Configure per-tool auto-approve for Airtable MCP read operations in Cursor's settings, but leave writes on manual approval — it cuts approval fatigue without giving up your safety check on mutations.
- Add a CI drift check for any generated type/schema file sourced from Airtable — catching a stale union type in a PR review is much cheaper than catching it in production.


Tips

Tips
- Remember Agent Mode is a prerequisite for MCP tool access at all in Cursor — it's the first thing to check whenever a configured server "isn't doing anything."
- Lean into Cursor's real advantage — generating typed code artifacts and keeping them near the code that consumes them — rather than using it as a general-purpose Airtable query tool where a terminal agent might be more efficient.
- Keep write operations explicit and reviewable as code diffs where possible (flag files, generated schemas) rather than as opaque direct Airtable mutations, since that's the workflow Cursor's IDE-centric design is actually built for.