Connects Claude to SeaTable bases with read, write, search, and query tools. Handles rows and data operations but intentionally skips schema management (no creating tables or columns), keeping the surface area safe for agent use. SeaTable Cloud users get a hosted endpoint at mcp.seatable.com with no local install. Self-hosted instances run via npx with stdio transport. Also ships managed mode for multi-tenant deployments with OAuth 2.0 support and per-token rate limiting. All writes validate against table schemas and strip read-only columns like formulas and auto-numbers. Responses include system fields like _id and timestamps. Reach for this when you need Claude to query, filter, and manipulate structured data in SeaTable without giving it the keys to alter your database structure.
Public tool metadata for what this MCP can expose to an agent.
list_tablesList tables in the SeaTable baseList tables in the SeaTable base
No parameter schema in public metadata yet.
list_rowsList rows from a table with pagination (defaults: page=1, page_size=100). Use find_rows for filtering/sorting or query_sql for SQL queries.4 paramsList rows from a table with pagination (defaults: page=1, page_size=100). Use find_rows for filtering/sorting or query_sql for SQL queries.
pageintegerviewstringtablestringpage_sizeintegerget_rowGet a row by ID from a table2 paramsGet a row by ID from a table
tablestringrow_idstringadd_rowAdd a new row to a table. Link and file/image columns cannot be set here — use link_rows and upload_file instead.2 paramsAdd a new row to a table. Link and file/image columns cannot be set here — use link_rows and upload_file instead.
rowobjecttablestringappend_rowsBatch insert rows. Rejects unknown columns. Link and file/image columns cannot be set here — use link_rows and upload_file instead.2 paramsBatch insert rows. Rejects unknown columns. Link and file/image columns cannot be set here — use link_rows and upload_file instead.
rowsarraytablestringupdate_rowsBatch update rows. Rejects unknown columns. Link and file/image columns cannot be modified here — use link_rows/unlink_rows and upload_file instead.2 paramsBatch update rows. Rejects unknown columns. Link and file/image columns cannot be modified here — use link_rows/unlink_rows and upload_file instead.
tablestringupdatesarraydelete_rowsDelete one or more rows from a table by their IDs.2 paramsDelete one or more rows from a table by their IDs.
tablestringrow_idsarrayfind_rowsFind rows using a predicate DSL. Filtering is performed client-side. where format: {"eq":{"field":"Name","value":"foo"}} or shorthand {"Name":"foo"}. Operators: eq, ne, in, gt, gte, lt, lte, contains, starts_with, ends_with, is_null. Combine with {"and":[...]} or {"or":[...]}....6 paramsFind rows using a predicate DSL. Filtering is performed client-side. where format: {"eq":{"field":"Name","value":"foo"}} or shorthand {"Name":"foo"}. Operators: eq, ne, in, gt, gte, lt, lte, contains, starts_with, ends_with, is_null. Combine with {"and":[...]} or {"or":[...]}....
pageintegertablestringwherevalueorder_bystringdirectionstringasc · descdefault: ascpage_sizeintegersearch_rowsSearch rows with a filter object2 paramsSearch rows with a filter object
queryobjecttablestringupsert_rowsBatch upsert rows by matching on one or more key columns. If a match exists, update it; otherwise insert a new row. Rejects unknown columns. Link and file/image columns cannot be set here — use link_rows/unlink_rows and upload_file instead.3 paramsBatch upsert rows by matching on one or more key columns. If a match exists, update it; otherwise insert a new row. Rejects unknown columns. Link and file/image columns cannot be set here — use link_rows/unlink_rows and upload_file instead.
rowsarraytablestringkey_columnsarraylink_rowsCreate links between rows via the dedicated links endpoint. This is the ONLY way to create links — link columns cannot be written via add_row or update_rows.3 paramsCreate links between rows via the dedicated links endpoint. This is the ONLY way to create links — link columns cannot be written via add_row or update_rows.
pairsarraytablestringlink_columnstringunlink_rowsRemove links between rows via the dedicated links endpoint. This is the ONLY way to remove links — link columns cannot be modified via update_rows.3 paramsRemove links between rows via the dedicated links endpoint. This is the ONLY way to remove links — link columns cannot be modified via update_rows.
pairsarraytablestringlink_columnstringget_schemaReturns the normalized schema for the baseReturns the normalized schema for the base
No parameter schema in public metadata yet.
query_sqlExecute raw SQL queries against SeaTable. Supports SELECT, INSERT, UPDATE, DELETE. Use ? placeholders for parameters to prevent SQL injection.2 paramsExecute raw SQL queries against SeaTable. Supports SELECT, INSERT, UPDATE, DELETE. Use ? placeholders for parameters to prevent SQL injection.
sqlstringparametersarraylist_collaboratorsList users who have access to this base. Returns email (internal user ID) and display name. Use the email values when writing to collaborator columns.List users who have access to this base. Returns email (internal user ID) and display name. Use the email values when writing to collaborator columns.
No parameter schema in public metadata yet.
upload_fileUpload a file or image to a row. Accepts base64-encoded file data and attaches it to the specified file or image column. By default appends to existing files; set replace=true to overwrite.6 paramsUpload a file or image to a row. Accepts base64-encoded file data and attaches it to the specified file or image column. By default appends to existing files; set replace=true to overwrite.
tablestringcolumnstringrow_idstringreplacebooleanfile_datastringfile_namestringadd_select_optionsAdd new options to a single-select or multi-select column. Use this before writing rows with option values that do not exist yet.3 paramsAdd new options to a single-select or multi-select column. Use this before writing rows with option values that do not exist yet.
tablestringcolumnstringoptionsarrayping_seatableHealth check that verifies connectivity and auth to SeaTableHealth check that verifies connectivity and auth to SeaTable
No parameter schema in public metadata yet.
The official Model Context Protocol (MCP) server for SeaTable, built and maintained by SeaTable GmbH. It lets AI agents interact with data in your bases — reading, writing, searching, linking, and querying rows through a focused set of tools. The server intentionally focuses on data operations, not schema management (creating/deleting tables or columns), keeping the tool set lean and safe for autonomous agent use.
The fastest way to get started depends on your setup:
mcp.seatable.com, no installation needednpx in your IDEIf you use SeaTable Cloud, there is a hosted MCP server ready to use — no installation required. Configure your MCP client with the Streamable HTTP endpoint:
Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"seatable": {
"type": "streamable-http",
"url": "https://mcp.seatable.com/mcp",
"headers": {
"Authorization": "Bearer your-api-token"
}
}
}
}
Cursor / VSCode — add to your MCP settings (JSON):
{
"mcp.servers": {
"seatable": {
"type": "streamable-http",
"url": "https://mcp.seatable.com/mcp",
"headers": {
"Authorization": "Bearer your-api-token"
}
}
}
}
ChatGPT and other OAuth-compatible clients — use the built-in OAuth flow. In ChatGPT's developer mode, configure:
https://mcp.seatable.com/mcphttps://mcp.seatable.com/authorizehttps://mcp.seatable.com/tokenYou will be prompted to enter your SeaTable API token during the authorization step.
For self-hosted SeaTable instances, run the MCP server locally via npx. Your IDE starts and manages the process automatically.
Claude Desktop — add to claude_desktop_config.json:
{
"mcpServers": {
"seatable": {
"command": "npx",
"args": ["-y", "@seatable/mcp-seatable"],
"env": {
"SEATABLE_SERVER_URL": "https://your-seatable-server.com",
"SEATABLE_API_TOKEN": "your-api-token"
}
}
}
}
Cursor / VSCode — add to your MCP settings (JSON):
{
"mcp.servers": {
"seatable": {
"command": "npx",
"args": ["-y", "@seatable/mcp-seatable"],
"env": {
"SEATABLE_SERVER_URL": "https://your-seatable-server.com",
"SEATABLE_API_TOKEN": "your-api-token"
}
}
}
}
If you need to run your own server instance — for example on your own infrastructure, with multi-base support, or in multi-tenant mode — use one of the options below.
Run a local HTTP server with Streamable HTTP transport:
PORT=3001 npx -y @seatable/mcp-seatable --sse
# Health check
curl http://localhost:3001/health
# MCP endpoint: POST/GET/DELETE http://localhost:3001/mcp
Serve multiple bases from a single process:
SEATABLE_SERVER_URL=https://your-seatable-server.com \
SEATABLE_BASES='[{"base_name":"CRM","api_token":"token_abc"},{"base_name":"Projects","api_token":"token_def"}]' \
npx -y @seatable/mcp-seatable
Each tool automatically gets a base parameter. Use list_bases to see available bases.
For hosting an MCP endpoint where each client authenticates with their own SeaTable API token:
SEATABLE_MODE=managed \
SEATABLE_SERVER_URL=https://your-seatable-server.com \
PORT=3000 npx -y @seatable/mcp-seatable --sse
Clients pass their API token via Authorization: Bearer <token> on session initialization. The server validates the token against SeaTable and applies rate limits (60 req/min per token, 120/min per IP, 20 concurrent connections per token).
OAuth support: Managed mode also exposes OAuth 2.0 endpoints (/authorize and /token), enabling OAuth-compatible clients like ChatGPT to connect. During the OAuth flow, the user enters their SeaTable API token, which is then used as the access token — no external OAuth provider required.
OAuth endpoints follow the MCP specification (RFC 8414 metadata discovery, PKCE, dynamic client registration):
| Endpoint | Path |
|---|---|
| Metadata Discovery | /.well-known/oauth-authorization-server |
| Authorization | /authorize |
| Token | /token |
| Client Registration | /register |
Client ID and secret are not validated — dynamic client registration generates one automatically.
docker run -d --name seatable-mcp \
-p 3000:3000 \
-e SEATABLE_SERVER_URL=https://your-seatable-server.com \
-e SEATABLE_API_TOKEN=your-api-token \
seatable/seatable-mcp:latest
# Health check
curl http://localhost:3000/health
The security characteristics differ significantly between transport modes:
| stdio (default) | Selfhosted HTTP | Managed HTTP | |
|---|---|---|---|
| Network exposure | None (local process) | TCP port, no auth | TCP port, Bearer auth |
| Authentication | Not needed (local) | None | Bearer token or OAuth 2.0, validated against SeaTable |
| Rate limiting | None | None | Per-token, per-IP, global |
| Connection limits | N/A | None | 20 concurrent sessions per token |
| Data scope | All configured bases | All configured bases | One base per client token |
⚠️ Warning: Selfhosted HTTP mode (
--sse/--http) has no authentication. Anyone who can reach the port gets full access to all configured bases, including write and delete operations. Only run it in trusted networks (localhost, Docker-internal) or behind a reverse proxy that handles authentication. For untrusted networks, use managed mode instead.
SeaTable's own API gateway enforces rate limits per base (default: 500 requests/minute per base_uuid) and per organization (monthly quota). These limits apply regardless of whether requests come from the MCP server, the web UI, or direct API calls. The MCP server does not duplicate these limits — instead, it retries automatically with exponential backoff when SeaTable returns 429 Too Many Requests.
In managed mode, the MCP server adds its own rate limits to protect the server process itself (not the SeaTable backend): 60 req/min per token, 120/min per IP, 30/min for new session creation, and 20 concurrent connections per token.
All tool inputs are validated with Zod schemas before execution. Write tools (add_row, append_rows, update_rows, upsert_rows) additionally validate row data against the table schema — unknown columns are rejected, and read-only columns (formula, auto-number, creator, etc.) are stripped with a note in the response.
Tool schemas are published with additionalProperties: true to remain compatible with MCP clients that may attach internal fields (e.g. _meta). Unexpected fields are ignored by the server — they do not cause errors but are not processed either. This is a deliberate trade-off: stricter validation would improve error messages for typos but risk breaking compatibility with MCP clients.
Row responses include all columns and SeaTable system fields (_id, _mtime, _ctime, _creator, _last_modifier). System fields are not filtered — _id is required for updates and deletes, timestamps are useful for sorting and freshness checks, and creator/modifier fields can be resolved to display names via list_collaborators.
The server caches base metadata (table/column definitions) for 60 seconds to avoid redundant API calls during write operations. Schema-reading tools (get_schema, list_tables) always bypass the cache and return fresh data. If a cached schema becomes stale (e.g. a column was renamed), the SeaTable API will reject the write and the AI agent can call get_schema to refresh.
Required:
SEATABLE_SERVER_URL — Your SeaTable server URLAuthentication (one of these is required in selfhosted mode):
SEATABLE_API_TOKEN — Single-base API tokenSEATABLE_BASES — Multi-base: JSON array (e.g. '[{"base_name":"CRM","api_token":"..."}]')Optional:
SEATABLE_MODE — selfhosted (default) or managed (multi-tenant HTTP with per-client auth)SEATABLE_MOCK=true — Enable mock mode for offline testingCORS_ALLOWED_ORIGINS — Comma-separated list of allowed origins for CORS (HTTP mode only, disabled if unset)METRICS_PORT — Prometheus metrics port (default: 9090, HTTP mode only)In HTTP mode, the server exposes Prometheus metrics on a separate port (default 9090):
curl http://localhost:9090/metrics
Available metrics:
| Metric | Type | Description |
|---|---|---|
mcp_tool_calls_total{tool, status} | Counter | Tool calls by name and result (success/error) |
mcp_tool_calls_by_tool_total{tool} | Counter | Total calls per tool (regardless of outcome) |
mcp_tool_duration_seconds{tool} | Histogram | Tool execution time |
mcp_http_requests_total{method, status} | Counter | HTTP requests by method and status code |
mcp_rate_limit_exceeded_total{type} | Counter | Rate limit rejections (global/per_ip/per_token) |
mcp_auth_validations_total{result} | Counter | Auth validations (success/failure/cache_hit) |
mcp_active_sessions | Gauge | Currently active HTTP sessions |
mcp_active_connections | Gauge | Currently active connections |
seatable_api_requests_total{operation, status} | Counter | SeaTable API calls by operation |
seatable_api_duration_seconds{operation} | Histogram | SeaTable API latency |
Plus standard Node.js metrics (memory, CPU, event loop) via prom-client.
The metrics server only starts in HTTP mode (not stdio) and binds to 0.0.0.0 — in Docker, expose the port only within your internal network.
list_tables — Get all tables with metadataget_schema — Get complete database structurelist_bases — List available bases (multi-base mode only)list_collaborators — List users with access to the base (for collaborator columns)list_rows — Paginated row listing (use query_sql for filtering/sorting)get_row — Retrieve specific row by IDfind_rows — Client-side filtering with DSLsearch_rows — Search via SQL WHERE clausesquery_sql — Execute SQL queries with parameterized inputsadd_row — Add single new rowappend_rows — Batch insert rowsupdate_rows — Batch update rowsupsert_rows — Insert or update rows by key columnsdelete_rows — Remove rows by IDupload_file — Upload a file or image to a row (base64-encoded)download_file — Read file content from a file or image column (text files and PDFs as text, binary files as download link, max 1 MB)link_rows — Create relationships between rowsunlink_rows — Remove relationships between rowsget_row_activities — Get change history of a row (who changed what, when, old/new values)create_snapshot — Create a snapshot of the current base (10 min cooldown)add_select_options — Add new options to single-select or multi-select columnsping_seatable — Health check with latency monitoringSeaTable bases can contain many different column types. The following table shows which types can be written via the API and what format to use.
| Column Type | Writable | Value Format |
|---|---|---|
| Text | Yes | "string" |
| Long Text | Yes | "Markdown string" |
| Number (incl. percent, currency) | Yes | 123.45 |
| Checkbox | Yes | true / false |
| Date | Yes | "YYYY-MM-DD" or "YYYY-MM-DD HH:mm" |
| Duration | Yes | "h:mm" or "h:mm:ss" |
| Single Select | Yes | "option name" |
| Multiple Select | Yes | ["option a", "option b"] |
| Yes | "user@example.com" | |
| URL | Yes | "https://..." |
| Rating | Yes | 4 (integer) |
| Geolocation | Yes | {"lat": 52.52, "lng": 13.40} |
| Collaborator | Yes | ["0b995819003140ed8e9efe05e817b000@auth.local"] — use list_collaborators to get user IDs |
| Link | Yes | Use link_rows / unlink_rows tools |
| Image / File | Yes | Use upload_file to upload (base64), download_file to read content |
| Formula / Link Formula | No | Read-only, computed by SeaTable |
| Creator / Created Time / Modified Time | No | Read-only, set automatically |
| Auto Number | No | Read-only, set automatically |
| Button / Digital Signature | No | Not accessible via API |
// List all tables
{ "tool": "list_tables", "args": {} }
// Get rows with pagination
{ "tool": "list_rows", "args": { "table": "Tasks", "page_size": 10 } }
// Add rows
{ "tool": "append_rows", "args": { "table": "Tasks", "rows": [{ "Title": "New Task", "Status": "Todo" }] } }
// SQL query
{ "tool": "query_sql", "args": { "sql": "SELECT Status, COUNT(*) as count FROM Tasks GROUP BY Status" } }
import { createMcpServer } from '@seatable/mcp-seatable'
const server = await createMcpServer({
serverUrl: 'https://your-seatable-server.com',
apiToken: 'your-api-token',
})
SEATABLE_MOCK=true npm run dev
In-memory tables and rows for demos and tests without a live SeaTable instance.
git clone https://github.com/seatable/seatable-mcp
cd seatable-mcp
npm install
cp .env.example .env # Configure your SeaTable settings
npm run dev # Start in watch mode
npm run dev — Start server in watch mode (tsx)npm run build — Compile TypeScriptnpm run start — Run compiled servernpm test — Run tests (vitest)npm run lint — Lint codenpm run typecheck — TypeScript type checknode scripts/mcp-call.cjs ping_seatable '{}'
node scripts/mcp-call.cjs list_tables '{}'
node scripts/mcp-call.cjs list_rows '{"table": "Tasks", "page_size": 5}'
| Issue | Solution |
|---|---|
Invalid API token | Check SEATABLE_API_TOKEN |
Base not found | Check API token permissions |
Connection timeout | Check SEATABLE_SERVER_URL and network access |
Permission denied | Ensure API token has required base permissions |
You don't have permission to perform this operation on this base. | API token is read-only or row limit exceeded |
Asset quota exceeded. | Storage quota reached — delete files or upgrade plan |
too many requests | Rate-limited by SeaTable — requests are automatically retried with backoff (3 attempts) |
MIT
SEATABLE_SERVER_URLURL of your SeaTable server (e.g. https://cloud.seatable.io)
SEATABLE_API_TOKENAPI token for a single SeaTable base
com.mcparmory/google-search
io.github.pipeworx-io/brave-search
marcopesani/mcp-server-serper
brave/brave-search-mcp-server
com.mcparmory/google-search-console
acamolese/google-search-console-mcp