Skip to content

MCP

PerSQL is an MCP server. An agent that speaks the Model Context Protocol — Claude Code, Claude Desktop, Cursor, your own — gets your databases as tools: list them, read a schema and the notes on it, look at a few rows, run SQL, add a note, take a backup. The tools act as you; the agent can write, so read the tool list and give a key only to an agent you would let at your own terminal.

The server is https://api.persql.com/mcp: JSON-RPC over POST, one request or a batch per call, answered as JSON; a notification answers 202 with no body. It opens no stream. Send a developer key as a bearer token.

{
"mcpServers": {
  "persql": {
    "type": "http",
    "url": "https://api.persql.com/mcp",
    "headers": { "Authorization": "Bearer persql_..." }
  }
}
}

A client that only runs a local command gets the same server through the CLI, which relays each line to the HTTP server with the key it holds:

{
"mcpServers": {
  "persql": {
    "command": "npx",
    "args": ["-y", "@persql/cli", "mcp"],
    "env": { "PERSQL_KEY": "persql_..." }
  }
}
}

persql mcp --config prints both, and the hosted one below. After persql login, PERSQL_KEY may be left out and the saved sign-in is used.

A client that cannot hold a key — a connector added at claude.ai or in another hosted agent — signs in through your browser instead. Give it https://api.persql.com/mcp and nothing else: the server answers its first call with 401 and WWW-Authenticate: Bearer resource_metadata=…, the client reads https://api.persql.com/.well-known/oauth-protected-resource/mcp and https://api.persql.com/.well-known/oauth-authorization-server, registers itself (RFC 7591, no secret, PKCE required), and sends you to https://console.persql.com/consent, where the console names the client and asks once. Allow, and the client holds a token that acts as you, scoped databases offline_access; with offline_access it refreshes on its own and outlives the browser session it was granted in.

The client is listed under Connected agents on your Account page; removing it there revokes every token it holds at once. GET /agents and DELETE /agents/:clientId do the same from the API.

ToolTakesDoes
list_databasesList the person's databases: id, name, how many tables, size in bytes, when last changed.
create_database, nameMake a new, empty database with the given name. Returns its id.
describe_database, databaseThe schema of a database — every table with its columns, types and keys, the indexes, the foreign keys, the views — and the person's notes about what the tables and columns mean. Read the notes before writing SQL.
sample_table, database, table, limitA table's row count, its columns, and a few rows to see what the data looks like.
query, database, sql, paramsRun one SQL statement. A SELECT returns its columns and rows (the first 1000; page with LIMIT and OFFSET or a WHERE on rowid for more). INSERT, UPDATE, DELETE, CREATE, ALTER and DROP run as written and return the rows written, so take a backup first when a change is hard to undo. Use ? placeholders and pass values in params.
list_notes, databaseThe person's notes on a database: what a table is for, what a column means.
add_note, database, about, textAdd a note about a table or a column, for the person and every later reader. `about` is a table name, or table.column.
list_backups, databaseThe backups of a database, newest first, with their kind and standing.
take_backup, database, labelTake a backup of a database before a change that is hard to undo. The backup is written in the background; the person can restore or download it.

A database argument is the database’s id, or its name when only one database has it. Every tool answers JSON as text; a failure is an isError result with the sentence, never a broken connection.

The protocol version is 2025-06-18. initialize, ping, tools/list and tools/call are served; resources and prompts are not.