> ## Documentation Index
> Fetch the complete documentation index at: https://ngquct-docs-fix-500-query-results.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# MCP Tools

> The 46 tools TablePro's MCP server exposes, with arguments, defaults, result shapes, and scope requirements

If a dedicated tool covers the job, it beats hand-written SQL. It quotes identifiers for the engine in front of it, applies the user's row limits, and runs on connections where raw execution is refused. All 46 publish a JSON Schema for input and output, so a client can validate both sides without reading this page. For the wire format, headers and error codes see [MCP Protocol](/external-api/mcp-protocol).

## How to read this page

In the tables below, required arguments come first and optional ones follow in parentheses. Unless a row says otherwise:

* `connection_id` is a connection UUID from `list_connections`.
* `database` and `schema` default to whatever the connection is currently browsing. Passing them targets somewhere else **without moving the app's selection**.
* An unknown argument is rejected with `-32602`. There is no silent ignoring.
* The result comes back twice: as JSON text in `content[0]`, and as a typed object in `structuredContent`. Read `structuredContent`.
* Timestamps are ISO 8601, error text is redacted, and "a result set" means `columns[]`, `rows[][]`, `row_count`, `rows_affected`, `execution_time_ms`, `is_truncated`, plus `status_message`, `database` and `schema` when they apply.

Row limits default to the server's **Default row limit** setting (500) and are capped by **Maximum row limit** (10,000). Timeouts default to **Query timeout** (30 seconds) and are capped at 300. Both live in **Settings > Integrations**.

## Tool index

| Group                                           | Tools                                                                                                                                                                                                                                                      |
| ----------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| [Connections](#connections)                     | `list_connections` `connect` `disconnect` `get_connection_status` `switch_database` `switch_schema`                                                                                                                                                        |
| [Schema discovery](#schema-discovery)           | `list_databases` `list_schemas` `list_tables` `describe_table` `get_table_ddl` `search_schema` `list_indexes` `list_foreign_keys` `list_triggers` `get_view_definition` `list_routines` `list_partitions` `get_table_statistics` `get_database_statistics` |
| [Reading data](#reading-data)                   | `browse_table` `count_rows` `execute_query` `explain_query` `export_data` `quote_identifiers`                                                                                                                                                              |
| [Writing data](#writing-data)                   | `insert_rows` `confirm_destructive_operation` `transaction_control`                                                                                                                                                                                        |
| [Databases and objects](#databases-and-objects) | `describe_create_database_options` `create_database` `drop_database_object` `list_maintenance_operations` `run_maintenance`                                                                                                                                |
| [Server administration](#server-administration) | `get_server_dashboard` `stop_server_session` `list_principals` `list_grants` `list_session_contexts`                                                                                                                                                       |
| [The user's workspace](#the-users-workspace)    | `list_favorite_tables` `list_recent_tables` `list_recent_tabs` `focus_query_tab` `open_connection_window` `open_table_tab` `search_query_history`                                                                                                          |

## Scopes and gates

Fourteen tools need `tools:write`: `connect`, `disconnect`, `switch_database`, `switch_schema`, `insert_rows`, `confirm_destructive_operation`, `transaction_control`, `create_database`, `drop_database_object`, `run_maintenance`, `stop_server_session`, `focus_query_tab`, `open_connection_window`, `open_table_tab`. The other 32 need `tools:read`, `execute_query` among them until the statement writes.

Past the scope, a call clears three more gates:

1. **Connection allowlist.** A token limited to named connections gets `-33007` for anything else.
2. **Connection policy.** **External Clients** set to **Blocked** hides the connection: `list_connections` omits it and any tool that names it is refused. An AI policy of **Never** does the same. **Ask Each Time** shows an approval dialog on the first call that touches the connection, and the answer is remembered for that token until it is revoked.
3. **Safe Mode.** A write goes through the connection's Safe Mode, which may ask the user to confirm it or to authenticate. See [Approvals](/external-api/mcp-protocol#approvals-and-input-required).

`confirm_destructive_operation` needs `admin` as well, so it takes a Full Access token, and **Read Only** refuses it outright whatever the token carries. No token skips the user's approval.

Statements that read or write files, or that run server-side code, are refused on every tool. So is more than one statement in a single call.

## Connections

| Tool                    | Arguments                   | Returns                                                                                                                                                                                                   |
| ----------------------- | --------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `list_connections`      | none                        | `connections[]` with `id`, `name`, `type`, `host`, `port`, `database`, `is_connected`, `ai_policy`, `external_access`, `safe_mode`                                                                        |
| `connect`               | `connection_id`             | `status` (`connected`), `connection_id`, `current_database`, plus `current_schema` and `server_version` when known. Returns once the driver is up                                                         |
| `disconnect`            | `connection_id`             | `status` (`disconnected`), `connection_id`                                                                                                                                                                |
| `get_connection_status` | `connection_id`             | `status` (`connected`, `connecting`, `disconnected`, `error`), `connection_id`, `current_database`, plus `current_schema`, `server_version`, `connected_at`, `last_active_at` and `error` when they apply |
| `switch_database`       | `connection_id`, `database` | `status` (`switched`), `connection_id`, `current_database`                                                                                                                                                |
| `switch_schema`         | `connection_id`, `schema`   | `status` (`switched`), `connection_id`, `current_schema`                                                                                                                                                  |

`list_connections` omits connections blocked for external clients, connections whose AI policy is **Never**, and connections outside the token's allowlist. Its `database` is the session's browsed database when connected, the saved default otherwise.

The two `switch_` tools move what the user sees in TablePro. To run one statement elsewhere, pass `database` or `schema` to that tool instead.

## Schema discovery

| Tool                      | Arguments                                                    | Returns                                                                                                                                                                                              |
| ------------------------- | ------------------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `list_databases`          | `connection_id`                                              | `databases[]`, sorted                                                                                                                                                                                |
| `list_schemas`            | `connection_id` (`database`)                                 | `schemas[]`, `database`                                                                                                                                                                              |
| `list_tables`             | `connection_id` (`database`, `schema`, `include_row_counts`) | `tables[]` (`name`, `type`, `schema`, `comment`, `row_count`), `database`, `schema`, `row_counts_included`, `row_counts_are_approximate`                                                             |
| `describe_table`          | `connection_id`, `table` (`database`, `schema`)              | `table`, `database`, `schema`, `columns[]`, `indexes[]`, `foreign_keys[]`, `ddl`, `approximate_row_count`                                                                                            |
| `get_table_ddl`           | `connection_id`, `table` (`database`, `schema`)              | `table`, `schema`, `ddl`                                                                                                                                                                             |
| `search_schema`           | `connection_id`, `term` (`limit`, `database`, `schema`)      | `term`, `matches[]` (`kind` is `table` or `column`, plus `name`, `table`, `schema`, `object_type`, `data_type`), `is_truncated`. Table matches first                                                 |
| `list_indexes`            | `connection_id` (`table`, `database`, `schema`)              | `database`, `schema`, `tables[]` of `{ table, indexes[] }`. Tables with no index are left out                                                                                                        |
| `list_foreign_keys`       | `connection_id` (`table`, `database`, `schema`)              | `database`, `schema`, `tables[]` of `{ table, foreign_keys[] }`                                                                                                                                      |
| `list_triggers`           | `connection_id`, `table` (`database`, `schema`)              | `table`, `triggers[]` (`name`, `timing`, `event`, `statement`, `is_enabled`), sorted by name                                                                                                         |
| `get_view_definition`     | `connection_id`, `view` (`database`, `schema`)               | `view`, `schema`, `definition`                                                                                                                                                                       |
| `list_routines`           | `connection_id` (`kind`, `database`, `schema`)               | `routines[]` (`name`, `kind`, `schema`, `qualified_name`, `signature`)                                                                                                                               |
| `list_partitions`         | `connection_id`, `table` (`database`, `schema`)              | `table`, `partitions[]`, shaped like `list_tables` entries                                                                                                                                           |
| `get_table_statistics`    | `connection_id`, `table` (`database`, `schema`)              | `table` plus whatever the engine records: `data_size_bytes`, `index_size_bytes`, `total_size_bytes`, `average_row_length`, `row_count`, `comment`, `engine`, `collation`, `created_at`, `updated_at` |
| `get_database_statistics` | `connection_id` (`database`)                                 | `databases[]` (`name`, `table_count`, `size_bytes`, `is_system_database`), sorted by name                                                                                                            |

`describe_table` is the one call to make before writing SQL against an unfamiliar table. A column always carries `name`, `data_type`, `is_nullable` and `is_primary_key`, and picks up `is_generated`, `default_value`, `extra`, `comment` and `allowed_values` where the engine reports them; indexes and foreign keys work the same way.

`include_row_counts` defaults to `false`. Counts come from engine statistics rather than `COUNT(*)`, and are fetched one table at a time, so `list_tables` skips them when the schema holds more than 200 objects.

`search_schema` locates a column without describing every table; its `limit` runs 1 to 500, default 50. `list_routines` takes `kind` as `procedure` or `function`, omitted for both.

## Reading data

| Tool                | Arguments                                                                                                                    | Returns                                                                                                                                        |
| ------------------- | ---------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------- |
| `browse_table`      | `connection_id`, `table` (`columns`, `filters`, `logic`, `sort`, `limit`, `offset`, `timeout_seconds`, `database`, `schema`) | A result set                                                                                                                                   |
| `count_rows`        | `connection_id`, `table` (`exact`, `filters`, `logic`, `database`, `schema`)                                                 | `table`, `row_count`, `is_approximate`, `filter_count`                                                                                         |
| `execute_query`     | `connection_id`, `query` (`max_rows`, `timeout_seconds`, `database`, `schema`)                                               | A result set                                                                                                                                   |
| `explain_query`     | `connection_id`, `query` (`analyze`, `variant`, `timeout_seconds`, `database`, `schema`)                                     | `statement` as actually sent, `execution_time_ms`, `columns[]`, `rows[][]`, and where available `plan_text`, `plan` and `available_variants[]` |
| `export_data`       | `connection_id`, `format` (`query` **or** `tables`, `sql_table`, `output_path`, `max_rows`, `database`, `schema`)            | `format`, `rows_exported`, `is_truncated`, `path` when a file was written, and `exports[]` (`label`, `row_count`, `is_truncated`, `data`)      |
| `quote_identifiers` | `connection_id` and at least one of `identifiers`, `literals` (`database`, `schema`)                                         | `identifiers[]` as `{ input, quoted }` and `literals[]` as `{ input, escaped }`, in the order supplied                                         |

### `browse_table`

A filter is `{ column, operator, value, second_value, case_sensitive }`. `column` and `operator` are required, `second_value` is the upper bound for `BETWEEN`, and `case_sensitive` defaults to whatever the operator normally does. `logic` is `and` (default) or `or`. The operator list is TablePro's own filter vocabulary, published in the tool's input schema as an `enum`; read it from `tools/list` rather than hardcoding it. Raw SQL filters are not available over MCP.

A sort entry is `{ column, direction }`, `direction` being `ascending` (default) or `descending`, and entries apply in the order given. `offset` defaults to 0.

### `count_rows`

Without filters this returns the engine's fast estimate unless `exact` is set. With filters it always counts for real, because an estimate cannot answer a filtered question.

### `execute_query`

One statement, 100 KB at most. `DROP` and `TRUNCATE` are refused here; use `confirm_destructive_operation`. When the request carries a `progressToken`, the tool emits progress at 0.0 (resolving), 0.3 (executing) and 1.0 (done).

### `explain_query`

Pass the query with no `EXPLAIN` prefix, and with no `variant` to see what this engine offers in `available_variants[]`. `analyze: true` runs the statement for real, so an analyzed write needs `tools:write` and Safe Mode approval.

### `export_data`

Formats are `csv`, `json` and `sql`; pass exactly one of `query` or `tables[]`. Without `output_path` the text comes back inline in each export entry. With it, the file lands in the user's Downloads folder and never overwrites, so a name that is taken gets `-1`, `-2` and so on; the path must stay inside Downloads, end in the format's extension, and not name a hidden file. SQL output uses the connection's own quoting and literal rules, so exporting a query needs `sql_table` to name the target table.

## Writing data

| Tool                            | Arguments                                                          | Returns                                                  |
| ------------------------------- | ------------------------------------------------------------------ | -------------------------------------------------------- |
| `insert_rows`                   | `connection_id`, `table`, `columns`, `rows` (`database`, `schema`) | `table`, `rows_submitted`, `rows_affected`               |
| `confirm_destructive_operation` | `connection_id`, `query` (`timeout_seconds`, `database`, `schema`) | A result set                                             |
| `transaction_control`           | `connection_id`, `action` (`database`, `schema`)                   | `status`, the action that completed, and `connection_id` |

`insert_rows` binds parameters, so values are never spliced into SQL text. Each row is an array with one value per column, and a call carries at most 1,000 rows.

`confirm_destructive_operation` runs one `DROP`, `TRUNCATE` or `ALTER … DROP`. Anything that is not destructive is rejected; use `execute_query` for those. The user approves it first, through your elicitation prompt if your client supports elicitation, otherwise through TablePro's own dialog on their Mac.

`transaction_control` takes `action` as `begin`, `commit` or `rollback`. The transaction stays open across calls until it is committed or rolled back, and it runs on the same session as the user's own tabs. Leave nothing open.

## Databases and objects

| Tool                               | Arguments                                                               | Returns                                                                   |
| ---------------------------------- | ----------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| `describe_create_database_options` | `connection_id`                                                         | `is_supported`, `fields[]` (`key`, `label`, `default_value`, `options[]`) |
| `create_database`                  | `connection_id`, `name` (`options`)                                     | `status` (`created`), `database`                                          |
| `drop_database_object`             | `connection_id`, `kind`, `name`                                         | `status` (`dropped`) and `database` or `schema`                           |
| `list_maintenance_operations`      | `connection_id`                                                         | `operations[]` and `is_supported`                                         |
| `run_maintenance`                  | `connection_id`, `operation` (`table`, `options`, `database`, `schema`) | `operation`, `statements[]`, `results[]`, one result set per statement    |

`create_database` takes `options` as a flat object of string values drawn from `describe_create_database_options`, and asks the user before it runs. `drop_database_object` takes `kind` as `database` or `schema`, deletes everything inside, cannot be undone, and is approved first.

`run_maintenance` takes an `operation` name from `list_maintenance_operations` (`VACUUM`, `ANALYZE`, `OPTIMIZE` and whatever else the engine supports) and omits `table` for the whole database. TablePro generates the statements and runs them in order, asking for approval before each one.

<Info>
  `describe_create_database_options`, `list_maintenance_operations` and `list_session_contexts` answer `is_supported: false` on an engine that has no such concept rather than failing, and `list_partitions` answers with an empty list. Everything else that an engine cannot do comes back as an `unsupported` tool error.
</Info>

## Server administration

| Tool                    | Arguments                              | Returns                                                                                                                                                                   |
| ----------------------- | -------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `get_server_dashboard`  | `connection_id` (`panels`)             | The requested panels: `sessions`, `metrics`, `slow_queries`                                                                                                               |
| `stop_server_session`   | `connection_id`, `process_id` (`mode`) | The result set the engine produced                                                                                                                                        |
| `list_principals`       | `connection_id`                        | `principals[]` (`name`, `host`, `is_role`, `can_login`, `member_of[]`, `connection_limit`, `comment`, and `attributes[]` of `{ key, label, is_enabled }`), sorted by name |
| `list_grants`           | `connection_id`, `principal` (`host`)  | `principal`, `grants[]` (`privilege`, `scope`, `is_grantable`). `scope` is a dotted path, `*` for a server-wide grant                                                     |
| `list_session_contexts` | `connection_id`                        | `is_supported`, `contexts[]` (`id`, `label`, `value`, `options[]`)                                                                                                        |

`get_server_dashboard` reads the live panels TablePro shows, and runs on PostgreSQL, MySQL, SQL Server, ClickHouse, DuckDB and SQLite. Name the panels in `panels[]` or omit it for all three. A session carries `id` (the process id `stop_server_session` takes), `user`, `database`, `state`, `duration_seconds`, `query`, `can_kill` and `can_cancel`; a metric carries `id`, `label`, `value`, `unit`; a slow query carries `duration`, `query`, `user`, `database`.

`stop_server_session` takes `mode` as `cancel` (default) to stop the running query or `kill` to end the session. The user always approves this one, whatever Safe Mode says.

`list_session_contexts` reports session-level contexts the engine exposes, such as a Snowflake warehouse or role, with the value the session currently holds.

## The user's workspace

These read and drive the TablePro app itself, and none of them bypasses the connection allowlist or a blocked connection.

| Tool                     | Arguments                                                      | Returns                                                                                                                                                                                                    |
| ------------------------ | -------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `list_favorite_tables`   | `connection_id`                                                | `favorites[]` (`name`, `database`, `schema`), sorted                                                                                                                                                       |
| `list_recent_tables`     | `connection_id`                                                | `recent_tables[]` (`name`, `database`, `schema`, `is_view`, `opened_at` as Unix epoch seconds), newest first                                                                                               |
| `list_recent_tabs`       | (`connection_id`, `limit`)                                     | `tabs[]` (`connection_id`, `connection_name`, `tab_id`, `tab_type`, `display_title`, `is_active`, plus `table_name`, `database_name`, `schema_name` and `window_id` when known)                            |
| `focus_query_tab`        | `tab_id`                                                       | `status` (`focused`), `tab_id`, `connection_id`, `window_id`                                                                                                                                               |
| `open_connection_window` | `connection_id`                                                | `status` (`opened`), `connection_id`, `tab_id`, `window_id`, `is_connected`                                                                                                                                |
| `open_table_tab`         | `connection_id`, `table_name` (`database_name`, `schema_name`) | `status` (`opened`), `connection_id`, `table_name`, `tab_id`, `window_id`                                                                                                                                  |
| `search_query_history`   | `query` (`connection_id`, `limit`, `since`, `until`)           | `entries[]` carrying `id`, `query`, the connection and database it ran on, `source`, `statement_type`, `executed_at`, `execution_time_ms`, `row_count`, `was_successful` and `error_message`, newest first |

Starred tables are a good hint at what matters in a database. `list_recent_tabs` covers every readable connection when `connection_id` is omitted, its `limit` runs 1 to 500, default 20, and `tab_type` is one of `query`, `table`, `createTable`, `erDiagram`, `serverDashboard`, `insights`, `usersRoles`.

`open_connection_window` and `open_table_tab` connect first if they have to, and return once the window has a tab or fail after 8 seconds.

`search_query_history` searches the history TablePro keeps on this Mac. Pass `""` to match everything and filter by date alone; `since` and `until` are Unix epoch seconds, and `limit` runs 1 to 500, default 50. Results cover only connections this client may reach, with or without `connection_id`.

## Annotations

Every tool ships MCP annotations so a client can decide what to auto-run:

* `readOnlyHint: true` on the 29 tools that only read. `execute_query` is not one of them.
* `destructiveHint: true` on `confirm_destructive_operation`, `drop_database_object` and `stop_server_session`.
* `idempotentHint: true` where repeating the call is safe.
* `openWorldHint: true` on the 14 that can reach the database server: every write except `switch_database`, `switch_schema` and `focus_query_tab`, plus `execute_query`, `explain_query` and `export_data`.

## Errors

A tool that fails returns a successful JSON-RPC result with `isError: true` and a text body starting with a code: `invalid_argument`, `not_connected`, `not_found`, `denied`, `timeout`, `unsupported`, `query_failed`, `user_cancelled`, `internal_failure`.

Protocol errors, with a JSON-RPC `error` envelope, are reserved for the request itself: a missing scope, an unknown tool, a bad header. The full table is in [MCP Protocol](/external-api/mcp-protocol#errors).
