{
  "markdown": "# SeaTable MCP\n\nThe official Model Context Protocol (MCP) server for [SeaTable](https://seatable.com), 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.\n\n## Quick Start\n\nThe fastest way to get started depends on your setup:\n\n- **SeaTable Cloud** — Use the hosted MCP server at `mcp.seatable.com`, no installation needed\n- **Self-hosted SeaTable** — Run the MCP server locally via `npx` in your IDE\n\n### SeaTable Cloud (hosted MCP server)\n\nIf you use [SeaTable Cloud](https://cloud.seatable.io), there is a hosted MCP server ready to use — no installation required. Configure your MCP client with the Streamable HTTP endpoint:\n\n**Claude Desktop** — add to `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"seatable\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.seatable.com/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer your-api-token\"\n      }\n    }\n  }\n}\n```\n\n**Cursor / VSCode** — add to your MCP settings (JSON):\n\n```json\n{\n  \"mcp.servers\": {\n    \"seatable\": {\n      \"type\": \"streamable-http\",\n      \"url\": \"https://mcp.seatable.com/mcp\",\n      \"headers\": {\n        \"Authorization\": \"Bearer your-api-token\"\n      }\n    }\n  }\n}\n```\n\n**ChatGPT and other OAuth-compatible clients** — use the built-in OAuth flow. In ChatGPT's developer mode, configure:\n\n- **Server URL:** `https://mcp.seatable.com/mcp`\n- **Auth type:** OAuth\n- **Authorization URL:** `https://mcp.seatable.com/authorize`\n- **Token URL:** `https://mcp.seatable.com/token`\n\nYou will be prompted to enter your SeaTable API token during the authorization step.\n\n### Self-hosted SeaTable\n\nFor self-hosted SeaTable instances, run the MCP server locally via `npx`. Your IDE starts and manages the process automatically.\n\n**Claude Desktop** — add to `claude_desktop_config.json`:\n\n```json\n{\n  \"mcpServers\": {\n    \"seatable\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@seatable/mcp-seatable\"],\n      \"env\": {\n        \"SEATABLE_SERVER_URL\": \"https://your-seatable-server.com\",\n        \"SEATABLE_API_TOKEN\": \"your-api-token\"\n      }\n    }\n  }\n}\n```\n\n**Cursor / VSCode** — add to your MCP settings (JSON):\n\n```json\n{\n  \"mcp.servers\": {\n    \"seatable\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@seatable/mcp-seatable\"],\n      \"env\": {\n        \"SEATABLE_SERVER_URL\": \"https://your-seatable-server.com\",\n        \"SEATABLE_API_TOKEN\": \"your-api-token\"\n      }\n    }\n  }\n}\n```\n\n## Deployment Options\n\nIf 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.\n\n### HTTP Server (Network Access)\n\nRun a local HTTP server with Streamable HTTP transport:\n\n```bash\nPORT=3001 npx -y @seatable/mcp-seatable --sse\n\n# Health check\ncurl http://localhost:3001/health\n\n# MCP endpoint: POST/GET/DELETE http://localhost:3001/mcp\n```\n\n### Multi-Base (Selfhosted)\n\nServe multiple bases from a single process:\n\n```bash\nSEATABLE_SERVER_URL=https://your-seatable-server.com \\\nSEATABLE_BASES='[{\"base_name\":\"CRM\",\"api_token\":\"token_abc\"},{\"base_name\":\"Projects\",\"api_token\":\"token_def\"}]' \\\nnpx -y @seatable/mcp-seatable\n```\n\nEach tool automatically gets a `base` parameter. Use `list_bases` to see available bases.\n\n### Managed Mode (Multi-Tenant HTTP)\n\nFor hosting an MCP endpoint where each client authenticates with their own SeaTable API token:\n\n```bash\nSEATABLE_MODE=managed \\\nSEATABLE_SERVER_URL=https://your-seatable-server.com \\\nSEATABLE_TOKEN_SECRET=$(openssl rand -hex 32) \\\nPORT=3000 npx -y @seatable/mcp-seatable --sse\n```\n\n`SEATABLE_TOKEN_SECRET` is **required** in managed mode. It seals the OAuth tokens the server issues, so the underlying SeaTable API token never has to be handed to a client. Keep it stable across restarts — changing it invalidates every issued access and refresh token and forces all clients to re-authorize.\n\nClients pass their credential via `Authorization: Bearer <token>` — on session initialization **and on every subsequent request**, including `GET` and `DELETE`. The `mcp-session-id` header is a routing value only; it is never accepted on its own. Each request is re-validated and must resolve to the same identity that created the session, otherwise the server answers `401` (missing/invalid credential) or `403` (valid credential, wrong session). Rate limits apply as before (60 req/min per token, 120/min per IP, 20 concurrent connections per token).\n\n**OAuth support:** Managed mode also exposes OAuth 2.0 endpoints (`/authorize` and `/token`), enabling OAuth-compatible clients like ChatGPT to connect — no external OAuth provider required. During the flow the user enters their SeaTable API token; the server seals it into its own short-lived access token (1 h) and a rotating refresh token (14 d). The raw SeaTable API token is never returned to a client.\n\nClients must register at `/register` first: the returned `client_id` carries the client's name and its `redirect_uris`, and the server accepts a callback only if it is one the client registered (loopback callbacks may vary the port, per RFC 8252). PKCE with `S256` is mandatory, and every authorization code is bound to the client, the exact callback and the challenge.\n\n**Where a code may be delivered.** With open dynamic registration, \"registered client\" is not a trust statement — anyone can register. What matters is whether the code leaves the user's machine:\n\n| Callback | Behaviour |\n|---|---|\n| Loopback (`http://127.0.0.1:…`, `localhost`, `[::1]`) | allowed, no extra step — the code stays on the user's machine |\n| Private-use scheme (`cursor://`, `vscode://`, `com.example.app:/…`) | allowed, no extra step — handed to a local application |\n| `https` on a host in `SEATABLE_OAUTH_TRUSTED_REDIRECT_HOSTS` | allowed, no extra step |\n| `https` on any other host | allowed **after** the user confirms the destination on a separate page |\n| Remote plaintext `http`, `javascript:`, `data:`, `file:`, `blob:` | rejected |\n\nThe confirmation cannot be skipped from the entry link: it is read from the form body only, and a POST auto-submitted by a foreign page is refused via `Sec-Fetch-Site`. The trusted-host list therefore removes friction — it is not a gate, and leaving it unset breaks nothing.\n\nThe consent screen leads with the destination the authorization will be sent to. The application's name is shown as **self-reported**, because with open registration it is chosen by whoever registered the client and cannot be verified.\n\nThe OAuth endpoints are rate limited per IP (30/min overall, 10/min for token submissions), so `/authorize` cannot be used as an unthrottled oracle for testing SeaTable API tokens.\n\nOAuth endpoints follow the MCP specification (RFC 8414 metadata discovery, PKCE, dynamic client registration):\n\n| Endpoint | Path |\n|---|---|\n| Metadata Discovery | `/.well-known/oauth-authorization-server` |\n| Authorization | `/authorize` |\n| Token | `/token` |\n| Client Registration | `/register` |\n\nClient ID and secret are not validated — dynamic client registration generates one automatically.\n\n### Docker\n\n```bash\ndocker run -d --name seatable-mcp \\\n  -p 3000:3000 \\\n  -e SEATABLE_SERVER_URL=https://your-seatable-server.com \\\n  -e SEATABLE_API_TOKEN=your-api-token \\\n  seatable/seatable-mcp:latest\n\n# Health check\ncurl http://localhost:3000/health\n```\n\n### Security Model\n\nThe security characteristics differ significantly between transport modes:\n\n| | stdio (default) | Selfhosted HTTP | Managed HTTP |\n|---|---|---|---|\n| **Network exposure** | None (local process) | TCP port, **no auth** | TCP port, Bearer auth |\n| **Authentication** | Not needed (local) | None | Bearer token or OAuth 2.0, validated against SeaTable |\n| **Rate limiting** | None | None | Per-token, per-IP, global |\n| **Connection limits** | N/A | None | 20 concurrent sessions per token |\n| **Data scope** | All configured bases | All configured bases | One base per client token |\n\n> **⚠️ 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.\n\n### Rate Limiting\n\nSeaTable'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`.\n\nIn **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.\n\n### Input Validation\n\nAll 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.\n\nTool 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.\n\n### Row Responses\n\nRow 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`.\n\n### Caching\n\nThe 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.\n\n## Environment Variables\n\nRequired:\n\n- `SEATABLE_SERVER_URL` — Your SeaTable server URL\n\nAuthentication (one of these is required in selfhosted mode):\n\n- `SEATABLE_API_TOKEN` — Single-base API token\n- `SEATABLE_BASES` — Multi-base: JSON array (e.g. `'[{\"base_name\":\"CRM\",\"api_token\":\"...\"}]'`)\n\nOptional:\n\n- `SEATABLE_MODE` — `selfhosted` (default) or `managed` (multi-tenant HTTP with per-client auth)\n- `SEATABLE_TOKEN_SECRET` — **required in managed mode**, min. 32 chars. Seals issued OAuth tokens and client registrations; must be stable across restarts (`openssl rand -hex 32`)\n- `SEATABLE_ACCESS_TOKEN_TTL` — lifetime of an issued access token in seconds (default `3600`, range `30`–`2592000`). Lower narrows the window after a SeaTable token is revoked; higher spares users a re-prompt if their client renews badly. The refresh token is never issued shorter-lived than the access token.\n- `SEATABLE_MOCK=true` — Enable mock mode for offline testing\n- `CORS_ALLOWED_ORIGINS` — Comma-separated list of allowed origins for CORS (HTTP mode only, disabled if unset)\n- `METRICS_PORT` — Prometheus metrics port (default: `9090`, HTTP mode only)\n\n## Monitoring\n\nIn HTTP mode, the server exposes Prometheus metrics on a separate port (default `9090`):\n\n```bash\ncurl http://localhost:9090/metrics\n```\n\nAvailable metrics:\n\n| Metric | Type | Description |\n|---|---|---|\n| `mcp_tool_calls_total{tool, status}` | Counter | Tool calls by name and result (success/error) |\n| `mcp_tool_calls_by_tool_total{tool}` | Counter | Total calls per tool (regardless of outcome) |\n| `mcp_tool_duration_seconds{tool}` | Histogram | Tool execution time |\n| `mcp_http_requests_total{method, status}` | Counter | HTTP requests by method and status code |\n| `mcp_rate_limit_exceeded_total{type}` | Counter | Rate limit rejections (global/per_ip/per_token) |\n| `mcp_auth_validations_total{result}` | Counter | Auth validations (success/failure/cache_hit) |\n| `mcp_active_sessions` | Gauge | Currently active HTTP sessions |\n| `mcp_active_connections` | Gauge | Currently active connections |\n| `seatable_api_requests_total{operation, status}` | Counter | SeaTable API calls by operation |\n| `seatable_api_duration_seconds{operation}` | Histogram | SeaTable API latency |\n\nPlus standard Node.js metrics (memory, CPU, event loop) via `prom-client`.\n\nThe 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.\n\n## MCP Tools\n\n### Schema Introspection\n\n- **`list_tables`** — Get all tables with metadata\n- **`get_schema`** — Get complete database structure\n- **`list_bases`** — List available bases (multi-base mode only)\n- **`list_collaborators`** — List users with access to the base (for collaborator columns)\n\n### Reading Data\n\n- **`list_rows`** — Paginated row listing (use query_sql for filtering/sorting)\n- **`get_row`** — Retrieve specific row by ID\n- **`find_rows`** — Client-side filtering with DSL\n- **`search_rows`** — Search via SQL WHERE clauses\n- **`query_sql`** — Execute SQL queries with parameterized inputs\n\n### Writing Data\n\n- **`add_row`** — Add single new row\n- **`append_rows`** — Batch insert rows\n- **`update_rows`** — Batch update rows\n- **`upsert_rows`** — Insert or update rows by key columns\n- **`delete_rows`** — Remove rows by ID\n\n### Files\n\n- **`upload_file`** — Upload a file or image to a row (base64-encoded)\n- **`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)\n\n### Linking\n\n- **`link_rows`** — Create relationships between rows\n- **`unlink_rows`** — Remove relationships between rows\n\n### Utilities\n\n- **`get_row_activities`** — Get change history of a row (who changed what, when, old/new values)\n- **`create_snapshot`** — Create a snapshot of the current base (10 min cooldown)\n- **`add_select_options`** — Add new options to single-select or multi-select columns (existing options are skipped, no duplicates)\n- **`ping_seatable`** — Health check with latency monitoring\n\n## Supported Column Types\n\nSeaTable bases can contain many different column types. The following table shows which types can be written via the API and what format to use.\n\n| Column Type | Writable | Value Format |\n|---|---|---|\n| Text | Yes | `\"string\"` |\n| Long Text | Yes | `\"Markdown string\"` |\n| Number (incl. percent, currency) | Yes | `123.45` |\n| Checkbox | Yes | `true` / `false` |\n| Date | Yes | `\"YYYY-MM-DD\"` or `\"YYYY-MM-DD HH:mm\"` |\n| Duration | Yes | `\"h:mm\"` or `\"h:mm:ss\"` |\n| Single Select | Yes | `\"option name\"` |\n| Multiple Select | Yes | `[\"option a\", \"option b\"]` |\n| Email | Yes | `\"user@example.com\"` |\n| URL | Yes | `\"https://...\"` |\n| Rating | Yes | `4` (integer) |\n| Geolocation | Yes | `{\"lat\": 52.52, \"lng\": 13.40}` |\n| Collaborator | Yes | `[\"0b995819003140ed8e9efe05e817b000@auth.local\"]` — use `list_collaborators` to get user IDs |\n| Link | Yes | Use `link_rows` / `unlink_rows` tools |\n| Image / File | Yes | Use `upload_file` to upload (base64), `download_file` to read content |\n| Formula / Link Formula | No | Read-only, computed by SeaTable |\n| Creator / Created Time / Modified Time | No | Read-only, set automatically |\n| Auto Number | No | Read-only, set automatically |\n| Button / Digital Signature | No | Not accessible via API |\n\n## Tool Examples\n\n```json\n// List all tables\n{ \"tool\": \"list_tables\", \"args\": {} }\n\n// Get rows with pagination\n{ \"tool\": \"list_rows\", \"args\": { \"table\": \"Tasks\", \"page_size\": 10 } }\n\n// Add rows\n{ \"tool\": \"append_rows\", \"args\": { \"table\": \"Tasks\", \"rows\": [{ \"Title\": \"New Task\", \"Status\": \"Todo\" }] } }\n\n// SQL query\n{ \"tool\": \"query_sql\", \"args\": { \"sql\": \"SELECT Status, COUNT(*) as count FROM Tasks GROUP BY Status\" } }\n```\n\n## Programmatic Usage\n\n```typescript\nimport { createMcpServer } from '@seatable/mcp-seatable'\n\nconst server = await createMcpServer({\n  serverUrl: 'https://your-seatable-server.com',\n  apiToken: 'your-api-token',\n})\n```\n\n## Mock Mode\n\n```bash\nSEATABLE_MOCK=true npm run dev\n```\n\nIn-memory tables and rows for demos and tests without a live SeaTable instance.\n\n## Development\n\n### Prerequisites\n\n- Node.js >= 20\n\n### Setup\n\n```bash\ngit clone https://github.com/seatable/seatable-mcp\ncd seatable-mcp\nnpm install\ncp .env.example .env   # Configure your SeaTable settings\nnpm run dev             # Start in watch mode\n```\n\n### Scripts\n\n- `npm run dev` — Start server in watch mode (tsx)\n- `npm run build` — Compile TypeScript\n- `npm run start` — Run compiled server\n- `npm test` — Run tests (vitest)\n- `npm run lint` — Lint code\n- `npm run typecheck` — TypeScript type check\n\n### Testing Tools\n\n```bash\nnode scripts/mcp-call.cjs ping_seatable '{}'\nnode scripts/mcp-call.cjs list_tables '{}'\nnode scripts/mcp-call.cjs list_rows '{\"table\": \"Tasks\", \"page_size\": 5}'\n```\n\n## Troubleshooting\n\n| Issue | Solution |\n|---|---|\n| `Invalid API token` | Check `SEATABLE_API_TOKEN` |\n| `Base not found` | Check API token permissions |\n| `Connection timeout` | Check `SEATABLE_SERVER_URL` and network access |\n| `Permission denied` | Ensure API token has required base permissions |\n| `You don't have permission to perform this operation on this base.` | API token is read-only or row limit exceeded |\n| `Asset quota exceeded.` | Storage quota reached — delete files or upgrade plan |\n| `too many requests` | Rate-limited by SeaTable — requests are automatically retried with backoff (3 attempts) |\n\n## License\n\nMIT\n",
  "bytes": 18186,
  "sha": "29be65e4aa12c9f3c9965a2e547ac9a7c5325d72a076d8f3486e38ac090cc708",
  "repo_slug": "seatable/seatable-mcp",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_seatable_seatable_adf65709/readme"
}