Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion customization/general-settings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Older servers have neither: MySQL before 5.7.8, MariaDB before 10.1.1. A stateme

## Command line tool

**Install** writes a `tablepro` command to `/usr/local/bin` that opens database URLs in the app. When it cannot write there, the section prints the command to run in Terminal yourself. See [Terminal](/integrations/terminal).
Shows whether `/usr/local/bin/tablepro` links to this copy of the app, with the Terminal line that links or removes it. The command opens database URLs in the app. See [Terminal](/integrations/terminal).

## Trusted links

Expand Down
1 change: 0 additions & 1 deletion customization/settings.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,6 @@ What a fresh install ships with, so one glance down this column says what you ch
| MCP | Maximum row limit | 10,000 |
| MCP | Query timeout | 30 seconds |
| MCP | Log MCP queries in history | On |
| MCP | Require authentication | On |
| MCP | Approval | Ask Once for Each Connection |
| MCP | Allow apps to list connections hidden from AI | Off |
| Sync | Sync this Mac with iCloud | Off |
Expand Down
2 changes: 1 addition & 1 deletion developers/mcp-protocol.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -274,7 +274,7 @@ Present the form, then repeat the **same** call with the answer and the state ec

A call that carries `inputResponses` or `requestState` is never cached, whatever the method's normal hint says.

An accepted form stands in for TablePro's own dialog only on a `fullAccess` token. On a `readOnly` or `readWrite` token, and on the anonymous loopback principal, Safe Mode still puts its dialog on the Mac afterwards, so a write is confirmed twice: once in your interface, once in TablePro's. Ask for `fullAccess` at [pairing](/developers/pairing) if the second prompt is not what you want.
An accepted form stands in for TablePro's own dialog only on a `fullAccess` token. On a `readOnly` or `readWrite` token, Safe Mode still puts its dialog on the Mac afterwards, so a write is confirmed twice: once in your interface, once in TablePro's. Ask for `fullAccess` at [pairing](/developers/pairing) if the second prompt is not what you want.

## Errors

Expand Down
8 changes: 6 additions & 2 deletions developers/pairing.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ sequenceDiagram
E->>E: verifier = randomBytes(32).base64url
E->>E: challenge = base64url(SHA-256(verifier))
E->>T: open tablepro://integrations/pair<br/>?client=…&challenge=…&redirect=…&response_mode=query&state=…
T->>M: lazy-start server
T->>M: start server (refused while MCP is off)
T->>U: Approval sheet (client, destination, scopes, connections, expiry)
U->>T: Approve
T->>T: mint token, hold pending exchange<br/>{ code, plaintext, challenge }, 5 min
Expand Down Expand Up @@ -157,7 +157,8 @@ The sheet names the client and counts down the five minutes the request is good
the link asked for, movable in either direction), **Allowed Connections** (all, or a checked subset),
and **Expiration** (never, 1, 7, 30 or 90 days). A link that asks for `connections:display` adds
**List connections hidden from AI**, off until the user ticks it. The link's parameters are a
request, not a grant.
request, not a grant. **Deny** is the default button: Return and Escape both deny, and **Approve**
takes a click. The sheet does not take focus from another app; TablePro's Dock icon bounces instead.

Approving mints the token, holds the plaintext against a one-time code for 5 minutes, and opens the
redirect. Pairing again mints a second token rather than replacing the first, so an extension that
Expand All @@ -175,6 +176,9 @@ re-pairs should stop using its old one. Revoke either under

## Errors

With **Enable MCP Server** off, the pair link stops before the approval sheet with an alert that
names **Settings > MCP**. No redirect is opened, so the extension sees no answer.

A failed verification burns the code, so retrying with a guessed verifier is not an option: start a
new pair request.

Expand Down
17 changes: 6 additions & 11 deletions developers/tokens.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,22 +14,17 @@ description: Token model, scopes, connection allowlists, expiry, revocation, and

| Level | Scopes | What it can do |
|-------|--------|----------------|
| Anonymous loopback | `tools:read`, `resources:read` | Read schema and run `SELECT`. |
| **Read Only** | `tools:read`, `resources:read` | The same, under an issued token. |
| **Read Only** | `tools:read`, `resources:read` | Read schema and run `SELECT`. |
| **Read & Write** | plus `tools:write` | `INSERT`, `UPDATE`, `DELETE`, connect and disconnect, switch database or schema, open and focus tabs. |
| **Full Access** | plus `admin` | Also `confirm_destructive_operation`, the only tool that runs `DROP` or `TRUNCATE`. |

Anonymous loopback is the floor and cannot be raised: the scope check refuses `tools:write` and `admin` to a caller with no issued token, whatever it asks for.

`connections:display` sits outside the levels. Only [pairing](/developers/pairing#scopes) grants it, and only while **Allow apps to list connections hidden from AI** is on under **Settings > MCP > Connection Access**. The **Generate Token** sheet never does, and an anonymous caller never holds it. It does one thing: lets [`list_connections`](/developers/mcp-tools#listing-for-display) take `purpose: "display"`. A token holding it reads **Lists connections hidden from AI** in the token list.
`connections:display` sits outside the levels. Only [pairing](/developers/pairing#scopes) grants it, and only while **Allow apps to list connections hidden from AI** is on under **Settings > MCP > Connection Access**. The **Generate Token** sheet never does. It does one thing: lets [`list_connections`](/developers/mcp-tools#listing-for-display) take `purpose: "display"`. A token holding it reads **Lists connections hidden from AI** in the token list.

`confirm_destructive_operation` also needs the connection's external access to be **Read & Write**, and no permission level skips the user's approval. [Scopes and gates](/developers/mcp-tools#scopes-and-gates) names which tools sit on which scope.

## Require authentication

**Settings > MCP > Authentication > Require authentication** is on by default. Turning it on for the first time with no tokens yet mints a **Read & Write** token named "Default token" and reveals the plaintext once.
## No token, no access

With the toggle off, a request from your own machine with no `Authorization` header is accepted as the anonymous loopback caller in the table above. Presenting an `Authorization` header still goes through normal token validation, so an invalid token is rejected either way. The server is loopback only, with no remote mode.
A request with no `Authorization` header gets `401` with a `Bearer` challenge, from your own Mac as much as from anywhere else. There is no setting that admits a caller without a token. The server is loopback only, with no remote mode.

## Connection allowlist

Expand Down Expand Up @@ -100,7 +95,7 @@ Every authentication, tool call, resource read, and query is recorded in `~/Libr
| Timestamp | when the call happened |
| Token | the token behind the call, by name and id |
| Category | `auth`, `access`, `admin`, `query`, `tool`, `resource` |
| Action | `auth.success`, `auth.anonymousLoopback`, `auth.failure`, `auth.rateLimited`, `pairing.exchange`, `pairing.redirectRejected`, `token.created`, `token.revoked`, `server.started`, `server.stopped`, `query.executed`, `tool.<name>`, `resource.read` |
| Action | `auth.success`, `auth.failure`, `auth.rateLimited`, `pairing.exchange`, `pairing.redirectRejected`, `token.created`, `token.revoked`, `server.started`, `server.stopped`, `query.executed`, `tool.<name>`, `resource.read` |
| Connection | the connection the call targeted, or `-` |
| Outcome | `success`, `denied`, `error`, `rateLimited` |

Expand All @@ -119,7 +114,7 @@ Entries are chained: each row's hash covers the previous one, so a row cannot be
| Failed pairing exchanges | 5 per 5 minutes |
| Pairing lockout | 15 minutes |

Request limits are keyed by token id, or by client address for an anonymous caller, and `subscriptions/listen` is exempt. Failed auth attempts are counted per client address, and every client on the Mac shares one, so a client that keeps sending a bad token locks the others out too. A malformed `Authorization` header, a scheme other than `Bearer`, and an unknown, expired or revoked token each count. A request with no `Authorization` header gets the `401` challenge and does not count. A successful auth clears the count. Anything over a limit returns `-33010` with HTTP `429` and a `Retry-After` header. Transport limits such as the body cap are on [MCP Protocol](/developers/mcp-protocol#transport-limits).
Request limits are keyed by token id, and `subscriptions/listen` is exempt. Failed auth attempts are counted per client address, and every client on the Mac shares one, so a client that keeps sending a bad token locks the others out too. A malformed `Authorization` header, a scheme other than `Bearer`, and an unknown, expired or revoked token each count. A request with no `Authorization` header gets the `401` challenge and does not count. A successful auth clears the count. Anything over a limit returns `-33010` with HTTP `429` and a `Retry-After` header. Transport limits such as the body cap are on [MCP Protocol](/developers/mcp-protocol#transport-limits).

## What a token cannot do

Expand Down
11 changes: 6 additions & 5 deletions developers/url-scheme.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ Raycast extension with `open()` from `@raycast/api`.
| [`connect/<uuid>/query?sql=…`](#run-a-query) | A query tab with the SQL prefilled, after a confirmation |
| [`import?…`](#import-a-connection) | A review sheet that saves a new connection |
| [`integrations/pair?…`](#start-pairing) | The pairing approval sheet |
| [`integrations/start-mcp`](#lazy-start-the-mcp-server) | Nothing. Starts the MCP server and returns |
| [`integrations/start-mcp`](#start-the-mcp-server) | Nothing. Starts the MCP server and returns |
| [`settings/<pane>`](#open-a-settings-pane) | Settings on that pane, or on the last-used pane |

## Connection IDs are UUIDs
Expand Down Expand Up @@ -85,7 +85,7 @@ tablepro://connect/<connection-uuid>/query?sql=<percent-encoded-sql>
```

A dialog titled **Open Query from Link** appears first, previewing the first 300 characters of the
SQL; **Open Query** opens the tab. Nothing executes, the user runs it from the editor. A tab already
SQL; **Open Query** opens the tab, and Return or Escape cancels. Nothing executes, the user runs it from the editor. A tab already
holding exactly this SQL comes to front instead of a second one opening.

`sql` is required and caps at 51,200 UTF-16 units. Longer than that and the link is dropped.
Expand Down Expand Up @@ -126,14 +126,15 @@ open "tablepro://integrations/pair?client=My%20Launcher&challenge=E9Melhoa2OwvFr

[Pairing](/developers/pairing) has the exchange step and the error codes.

## Lazy-start the MCP server
## Start the MCP server

```text
tablepro://integrations/start-mcp
```

Starts the MCP server if it is not running, then returns. MCP does not have to be enabled in Settings
first. The bundled `tablepro-mcp` CLI uses this to bootstrap on a cold launch.
Starts the MCP server if it is not running, then returns. The bundled `tablepro-mcp` CLI uses this
to bootstrap on a cold launch. With **Enable MCP Server** off in **Settings > MCP**, the start is
refused: no listener, no alert, and a launch made only for this URL quits again.

The server takes the configured port (`23508` by default) and falls back to a kernel-assigned free
port when that one is busy. The **Status** row in **Settings > MCP** shows the port it bound.
Expand Down
12 changes: 7 additions & 5 deletions features/mcp.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,9 @@ This page covers the **Settings > MCP** pane. The protocol itself, the tool cata

Open **Settings > MCP** and turn on **Enable MCP Server**. The **Status** row underneath is how you check it before touching a client config: it reads **Running on port 23508**, or **Stopped**, or the reason it failed.

Leaving the toggle off does not keep the server down. It starts on demand when a client launches the bundled `tablepro-mcp` bridge and when you pair an extension, so turning the toggle off stops the listener but not those paths.
With the toggle off, nothing starts the server. A client that launches the bundled `tablepro-mcp` bridge gets "The TablePro MCP server is turned off" within a second instead of a timeout, and pairing an extension stops at the same message with **Open MCP Settings**.

While it is only answering a client, TablePro stays out of the Dock and the app switcher. It appears in both, with its menu bar, once it has a window on screen, including one a client asked it to open.
While it is only answering a client, TablePro stays out of the Dock and the app switcher. It appears in both, with its menu bar, once it has a window on screen, including one a client asked it to open. A TablePro the bridge launched while the toggle is off quits again.

The default port is **23508**. If it is taken, TablePro asks the kernel for a free one instead. Either way the real port goes to `~/Library/Application Support/TablePro/mcp-handshake.json`, which the bridge reads, so a client config never carries a port.

Expand Down Expand Up @@ -64,6 +64,10 @@ The question always arrives as a dialog on your Mac, never through the client. A
answer it in its own interface could also answer it without asking you, and this is the gate that
decides whether it reaches the connection at all.

The dialog does not take focus from the app you are typing in. TablePro's Dock icon bounces until
you switch to it, **Deny** is the default button, and Return and Escape both deny. **Allow** takes a
click.

Nothing here times out. Whoever sent the request decides how long to wait for you, and an answer
counts whenever you give it.

Expand All @@ -78,9 +82,7 @@ Tokens that hold this grant read **Lists connections hidden from AI** in the tok

## Authentication

**Require authentication** is on by default. Turning it on for the first time with no tokens yet generates a full-access "Default token" and shows the plaintext once, so copy it then. Create, scope, allowlist, expire and revoke tokens in the same section, described in [Tokens](/developers/tokens).

With the toggle off, a caller on your own machine is accepted without a token, but only as a read-only caller: schema reads and `SELECT`. Anything beyond reading needs a token you issued.
Every request needs a token, including one from your own Mac. The bundled bridge mints its own, so a client set up through **Connect a Client…** needs nothing from you; an HTTP client or a launcher needs a token you generate or pair. Create, scope, allowlist, expire and revoke tokens in this section, described in [Tokens](/developers/tokens).

## Activity and connected clients

Expand Down
Binary file removed images/command-line-install-dark.png
Binary file not shown.
Binary file removed images/command-line-install.png
Binary file not shown.
Binary file added images/command-line-link-dark.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added images/command-line-link.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 5 additions & 1 deletion integrations/mcp-clients.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -104,7 +104,7 @@ Click **Connect a Client…** in **Settings > MCP**. The sheet covers Claude Des

## What the config leaves out

TablePro does not have to be open first. Finding no trusted handshake, the bridge runs `open -g tablepro://integrations/start-mcp` and polls for one every 200ms for up to 10 seconds. A TablePro started that way stays out of the Dock, the app switcher and the menu bar until it has a window to show; open the app yourself and it behaves normally for the rest of that run.
TablePro does not have to be open first, but **Enable MCP Server** has to be on. Finding no trusted handshake, the bridge runs `open -g tablepro://integrations/start-mcp` and polls for one every 200ms for up to 10 seconds. With the toggle off, TablePro refuses the start and the bridge exits with that error at once. A TablePro started that way stays out of the Dock, the app switcher and the menu bar until it has a window to show; open the app yourself and it behaves normally for the rest of that run.

The token is not yours to manage either. Each server start mints one named `__stdio_bridge__`, writes it into the handshake file, and rotates it 15 minutes before its one-hour expiry. It is **Read & Write**, so an agent on the bridge can read and write but cannot call `confirm_destructive_operation`.

Expand Down Expand Up @@ -153,6 +153,10 @@ Clients see the full [tool catalog](/developers/mcp-tools), the [resources](/dev

The bridge writes its failure to stderr and as a JSON-RPC error, so the message in the client names the layer that refused.

### The TablePro MCP server is turned off

**Enable MCP Server** is off in **Settings > MCP**. Turn it on, then relaunch the client.

### TablePro is not running

The bridge could not launch the app, or got no trusted handshake within 10 seconds. Open TablePro and check that **Settings > MCP** shows the server running; if it does, toggle **Enable MCP Server** off and on, then relaunch the client.
Expand Down
4 changes: 2 additions & 2 deletions integrations/raycast.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ It defaults to `/Applications/TablePro.app`, so change it only for a build that

## Pair

Run **Pair with TablePro**. An approval sheet opens in TablePro where you pick the scope (read-only
Turn on **Enable MCP Server** in **Settings > MCP** first; with it off, pairing stops at an error. Then run **Pair with TablePro**. An approval sheet opens in TablePro where you pick the scope (read-only
to start), the connections the token may reach, and an optional expiry. Approving sends a one-time
code back to Raycast, which exchanges it for a token over localhost. [Pairing](/developers/pairing)
documents the protocol.
Expand Down Expand Up @@ -74,6 +74,6 @@ under Raycast's [privacy policy](https://www.raycast.com/privacy).
| Symptom | What to do |
|---|---|
| Paired, but the connection list is empty | TablePro omits every connection the token cannot reach. Either the allowlist you approved left it out, or its **External Clients** level is **Blocked**. Re-pair with the connection selected, or raise the level in the [connection form's Options tab](/connections/connection-form#options). |
| Commands hang on a running TablePro | The MCP server is stopped. The extension opens `tablepro://integrations/start-mcp` and retries on its own; give it a moment. |
| Commands hang on a running TablePro | The MCP server is stopped. Turn on **Enable MCP Server** in **Settings > MCP**; the extension retries on its own. |
| `401` | The token was revoked or has expired. Run **Pair with TablePro** again. |
| `403` and other MCP errors | See [MCP client troubleshooting](/integrations/mcp-clients#when-it-does-not-work). |
Loading
Loading