Skip to main content
Read Only is where the Generate Token sheet starts, and it is the right level for a client that only reads. Move to Read & Write when an agent has to change data, and to Full Access only for DROP and TRUNCATE, which nothing below it can reach. The plaintext is shown once at creation and never again; what persists is a salted SHA-256 hash in the login keychain.

Permission levels

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. 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 names which tools sit on which scope.

Require authentication

Settings > Integrations > 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. 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.

Connection allowlist

A token grants access to all connections or to a named set. A call that targets a connection outside the set is refused with -33007 before any other check runs, and aggregate reads such as search_query_history and list_recent_tabs filter their results to the allowlist whether or not you passed a connection id.

Combining with external access

The effective permission is the lower of the token’s scope and the connection’s External Clients level.

Creating a token

Pairing is the usual route: see Pairing. To mint one by hand, open Settings > Integrations > Authentication, click Generate Token, and pick a name, permission level, connection allowlist and expiry. The plaintext is shown once.

Expiry

Optional, and worth setting for anything with write access. The sheet offers 30, 60 and 90 days, a custom date, or Never. An expired token stops authenticating: requests get -33008 with HTTP 401 and WWW-Authenticate: Bearer error="invalid_token", error_description="token expired".

Rotating a token

Mint the replacement before you retire the old one; two tokens for one client are fine, and pairing the same client twice does exactly this. Point the client at the new token, confirm it works, then revoke the old one. Revoking first cuts the client off mid-call, because revocation takes effect immediately.

Revocation

The token list in Settings > Integrations > Authentication shows prefix, name, permission level, allowlist, last use, and expiry. Each row offers:
  • Revoke: marks the token inactive. It stays in the list and cannot be reactivated.
  • Delete…: removes the row entirely.
Revoking cancels every request that token has in flight and clears the connection approvals the user had granted it, so a re-issued token has to ask again. The next call gets -33009 with HTTP 401. Disconnect in the Connected Clients list revokes that client’s token. It is not a soft disconnect: the client has to pair again or be given a new token.

The stdio bridge token

Every server start mints a token named __stdio_bridge__ and writes it into the handshake file for the bundled bridge. It is Read & Write, so an agent going through the bridge can read and write but cannot call confirm_destructive_operation. It expires after an hour and is rotated 15 minutes before that, deleted when the server stops, and any stale copy is removed the next time the store loads. It is hidden from the Settings token list, though its name can appear in the activity log. For a narrower scope, skip the bridge and connect over HTTP with a token you mint.

Stored fields

The plaintext is tp_ followed by 32 base64url-encoded random bytes. Tokens live in the login keychain under the com.TablePro service; a pre-existing mcp-tokens.json is migrated in on first load and deleted.

Activity log

Every authentication, tool call, resource read, and query is recorded in ~/Library/Application Support/TablePro/mcp-audit.db with the token id, never the plaintext. Open it with Settings > Integrations > View Activity…. Statement text is not stored. A query.executed row carries sqlDigest, the SHA-256 of the statement, alongside its duration and row count, which is enough to match a row against a statement you already hold. Error text that is stored is redacted and truncated first. Entries are chained: each row’s hash covers the previous one, so a row cannot be removed or edited without breaking the chain. Entries older than 90 days are pruned when the store opens.

Rate limits

Request limits are keyed by token id, or by client address for an anonymous caller, and subscriptions/listen is exempt. Auth failures count against both the client address and the token, so one misbehaving client cannot lock out another on the same loopback address, and a successful auth clears the bucket. 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.

What a token cannot do

Statements that reach the filesystem or run server-side code are refused before they reach the driver, on every tool. The reachable surface is the tool catalog, the resources, and the prompts. Nothing outside those lists is exposed.