Skip to content

MCP — using a base from an LLM client

Every base exposes a Model Context Protocol server, so an LLM client can list tables, query features and edit records through tools.

POST https://{SERVER}/api/v0/bases/{baseId}/mcp

One endpoint per base — the base is the security boundary, and a session only ever sees the tables in the base it connected to.

If you want a chat UI in your own app rather than a desktop client, @imaps/ai-chat is a React component, web component or map widget that takes this endpoint as one of its MCP servers.

The transport is stateless HTTP: each request is independent, and only POST is accepted (a GET for the notification stream gets a clean 405, which clients handle by simply not using one). Authenticate the same way you would any data request — an ims_… API key or an app token as a Bearer header.

{
"mcpServers": {
"sync-server": {
"type": "http",
"url": "https://sync.example.com/api/v0/bases/appXXXXXXXX/mcp",
"headers": { "Authorization": "Bearer ims_…" }
}
}
}

Read tools are always available:

Tool What it does
list_tables Every table configured for the base
get_table_schema Field names, types and aliases for one table
query_features Query with where, bbox, outFields, limit, offset, orderByFields
get_table_geojson The whole cached FeatureCollection for a table
get_sync_runs Recent sync history — timestamps, status, record counts
trigger_sync Enqueue a sync of the base, or one table. Rate-limited to 4/hour

Write tools — create_features, update_feature, delete_feature — are only advertised to callers who actually hold write access to the base, and the underlying REST handlers re-enforce that regardless. A read-only key never sees them in the tool list. They work on Airtable and NocoDB bases; HTTP and TSIP bases refuse.

URI Contents
tables://{baseId} The base’s table list
table://{baseId}/{tableName} One table’s schema and data

A write made through a model is attributed to the human driving it, not to an anonymous robot. The MCP layer signs an actor header identifying the session’s real caller and passes it to the internal API, so the activity log and the realtime feed show { "kind": "mcp", "via": { "kind": "user", … } }.

Tool calls reach the API over loopback, never via the client-supplied Host header — the model cannot be talked into making the server call an arbitrary host.

  • where clauses are capped at 2,000 characters.
  • get_table_geojson returns the entire table; on a large one, prefer query_features with a limit so you don’t spend the context window on rows nobody asked for.
  • The data comes from the cache, so it’s as fresh as the last sync (or the last edit). Ask for get_sync_runs if freshness matters, and trigger_sync if it isn’t fresh enough.