Skip to main content
The MCP server exposes tools and resources over JSON-RPC. The tools are grouped by category below. Every tool is scope-gated: a request must come with a token whose scope and connection allowlist permit the call.

Transports

The same tool catalog is available over two transports:
  • HTTP: MCP Streamable HTTP at http://127.0.0.1:<port>/mcp (port from the handshake file). POST for JSON-RPC requests, GET for the SSE stream that carries server-initiated notifications. Bearer token in Authorization header.
  • stdio: bundled tablepro-mcp CLI bridges stdio JSON-RPC to localhost HTTP. No token needed because the bridge reuses the in-app handshake.
The server accepts 2025-03-26, 2025-06-18, and 2025-11-25. On initialize it echoes whichever version the client requested. If the client asks for something else, the server returns 2025-11-25. See Versioning.

Scopes and access

Each tool entry below lists its minimum token scope. The effective permission is MIN(token.scope, connection.externalAccess); see Tokens for the full scope table. Two per-connection settings gate every call on top of the token:
  • External access. blocked hides the connection entirely: list_connections omits it, list_recent_tabs filters its tabs, and any tool that targets it returns 403 forbidden. readOnly blocks write SQL: execute_query with a write statement and any confirm_destructive_operation call return 403, even with a readWrite token. The session-state tools disconnect, switch_database, and switch_schema are gated by token scope only.
  • AI policy askEachTime. The first tool call per session that targets the connection shows an in-app approval dialog. TablePro waits up to 30 seconds. Deny returns 403 forbidden with message “User denied MCP access to this connection”; no answer fails the call with a timeout error. An approval covers that connection for the rest of the session.
list_tables, list_schemas, describe_table, get_table_ddl, and execute_query query exactly the database and schema you pass them and leave the app alone: the sidebar’s selected database and every open tab stay where they are, and a tab keeps querying the database and schema it was opened on. switch_database and switch_schema are the only tools that move the app’s selection, which is what they are for.

Connection tools

list_connections

List saved connections. Connections with externalAccess: blocked are silently omitted. Input: none. Output:
Scope: readOnly.

connect

Open a database connection. Input:
Output:
current_schema and server_version are present when known. Scope: readOnly.

disconnect

Close a connection. Input: { "connection_id": "..." } Output: { "status": "disconnected" } on success. Scope: readWrite.

get_connection_status

Return status, active database, server version, connect time, and last-active time for a connection. Input: { "connection_id": "..." } Output:
status is one of connected, connecting, disconnected, error. When error, an error object with a message field is included. Scope: readOnly.

Schema tools

list_databases

Input: { "connection_id": "..." } Output: { "databases": ["app", "analytics"] } (array of database names) Scope: readOnly.

list_schemas

Input: { "connection_id": "...", "database": "app" } (database optional) Output: { "schemas": ["public", "reporting"] } (array of schema names) Scope: readOnly.

list_tables

Input:
Output:
type is one of TABLE, VIEW, MATERIALIZED VIEW, FOREIGN TABLE, or SYSTEM TABLE. When include_row_counts is true and the driver supports it, each entry also includes row_count. Scope: readOnly.

describe_table

Columns, indexes, foreign keys, primary key, DDL. Input:
database and schema are optional. The connection’s current database and schema are used when omitted. Output:
default_value, extra, and comment are present on a column when set. ddl and approximate_row_count are present when the driver supports them. Scope: readOnly.

get_table_ddl

Just the CREATE TABLE statement. Input: same as describe_table (connection_id, table, database, schema). Output: { "ddl": "CREATE TABLE ..." } Scope: readOnly.

Query tools

execute_query

Execute a SQL query. All queries are subject to the connection’s safe mode policy. DROP, TRUNCATE, and ALTER…DROP must use confirm_destructive_operation. Input:
Defaults for max_rows and timeout_seconds come from Settings > Integrations > Server Configuration (default row limit, query timeout). max_rows is clamped to the configured maximum (default 10,000). timeout_seconds is clamped to 1-300. Single-statement queries only. Query size cap is 100 KB. database and schema are optional; when present, the query runs against them. It never changes what’s selected in the app, and omitting them runs against the connection’s currently selected database. Output:
columns is an array of column-name strings. rows is an array of rows, where each row is an array of strings (or null) aligned to the columns order. status_message is added when the driver returns one. Scope:
  • readOnly for SELECT, SHOW, EXPLAIN.
  • readWrite for INSERT, UPDATE, DELETE.
  • DROP, TRUNCATE, ALTER…DROP are rejected. Use confirm_destructive_operation.
Safe Mode rules apply on top. A connection in Safe Mode readOnly returns 403 for any write SQL. Streaming progress: pass _meta.progressToken in the request and the server sends notifications/progress events on the SSE channel as the query moves through “Connecting”, “Executing”, “Formatting result”, and “Done”. Clients that don’t include a token get the final response only.

confirm_destructive_operation

Run a DROP, TRUNCATE, or ALTER…DROP after a typed confirmation. Input:
The confirmation phrase is fixed: I understand this is irreversible. Anything else returns JSON-RPC -32602 over HTTP 200 with message Invalid params: confirmation_phrase must be exactly: I understand this is irreversible. Output: same shape as execute_query. Scope: readWrite or fullAccess (both grant the tools:write MCP scope). The connection’s external access must also permit writes; a readOnly connection rejects destructive operations even with a matching token.

export_data

Export query or table data as CSV, JSON, or SQL. Input:
format is one of csv, json, sql. Defaults for max_rows and the query timeout come from Settings > Integrations > Server Configuration, the same as execute_query: omitting max_rows uses the default row limit (500), and any value you pass is clamped to the maximum row limit (default 10,000). Raise those settings to export more rows. Provide either tables or query. Table names accept letters, digits, underscore, and . for schema-qualified names. Pass output_path to write to disk instead of returning data inline; the path must resolve inside the user’s ~/Downloads directory. Anything else fails with JSON-RPC -32602 over HTTP 200 and message Invalid params: output_path must be inside the Downloads directory (/Users/you/Downloads). Output: when output_path is set, returns { "path": "...", "rows_exported": N, "is_truncated": false }. Otherwise returns the export inline. A single export returns { "label": "...", "format": "csv", "row_count": N, "is_truncated": false, "data": "..." }. Multiple exports (multi-table requests) return { "exports": [ { "label": "...", "format": "csv", "row_count": N, "is_truncated": false, "data": "..." }, ... ] }. is_truncated is true when the row limit clipped the result. Scope: readOnly.

switch_database / switch_schema

Input: { "connection_id": "...", "database": "analytics" } or { "connection_id": "...", "schema": "reporting" } Output: { "status": "switched", "current_database": "analytics" } or { "status": "switched", "current_schema": "reporting" } Scope: readWrite (moves the connection’s selected database or schema, which the sidebar follows). These open or focus tabs and windows in the running TablePro app. They require readOnly scope and respect the connection allowlist; tabs from externalAccess: blocked connections are filtered out.

open_connection_window

Open a connection in TablePro and bring its window to front. If the connection is already open, the existing window is focused. Input: { "connection_id": "..." } Output:
Scope: readOnly.

open_table_tab

Open a table tab. Input:
database_name and schema_name are optional. If omitted, the connection’s current database/schema is used. Output:
Scope: readOnly.

focus_query_tab

Bring an existing tab to front. The tab_id comes from list_recent_tabs. Input: { "tab_id": "..." } Output:
If the tab is no longer open, the call returns -32602 invalid params with detail tab not found. Scope: readOnly.

list_recent_tabs

Read the cross-window tab registry. Tabs from connections with externalAccess: blocked are filtered out. Input: { "limit": 20 } (optional, 1-500, default 20). Output:
tab_type is one of query, table, createTable, erDiagram, serverDashboard, usersRoles. table_name, database_name, schema_name, and window_id are present when known. Scope: readOnly.

History tools

search_query_history

Full-text search over the query history database. Input:
connection_id is optional. limit is 1-500, default 50. since and until are optional Unix epoch seconds; both bounds are inclusive. Either may be set on its own. Pass an empty query ("") to skip the full-text filter and only narrow by date or connection. Output:
executed_at is a Unix timestamp in seconds. error_message is included when was_successful is false. Scope: readOnly.

Errors

Tool failures come back as JSON-RPC error envelopes. Codes follow the JSON-RPC spec plus TablePro’s reserved range: Error responses include a message. Example:
A 404 from GET/POST/DELETE /mcp with a stale Mcp-Session-Id returns the JSON-RPC envelope with code: -32001, message: "Session not found". Per the MCP spec, clients MUST treat that response as a signal to start a new initialize handshake before retrying. 401 responses carry a WWW-Authenticate challenge. A missing token returns Bearer realm="TablePro". An unknown or revoked token returns Bearer error="invalid_token". An expired token returns Bearer error="invalid_token", error_description="token expired".