Give Cursor Safe Access to Your Database (MCP Setup)

To give Cursor safe access to your database, connect it through an MCP server with a token that is read-only by default, scoped to one project, and never the database owner password. When you want the agent to write, give it its own restricted key so destructive statements wait for your approval and its changes can be undone. This guide shows the mcp.json for each step, what Cursor does with approvals, and how to recover if an agent has already deleted data.

Cursor details below come from Cursor's own MCP documentation as of November 2026.

#Three ways Cursor can reach a database

ApproachHow it worksRisk
Connection string in .envThe agent runs psql or a script in the terminalIt acts as whoever owns that string, usually the owner. Nothing stops DROP TABLE.
Generic local Postgres MCP serverA stdio server started by Cursor with your connection stringSame role as the string. Read-only only if the server enforces it.
Hosted MCP server with scoped tokensCursor calls a remote server with a token you can limit and revokeThe server decides which tools exist and what role SQL runs as.

The first two are common in tutorials because they are quick. They are also how an agent ends up deleting the data you care about: the model meant to reset a test table, the connection pointed at production, and the role had every right. Safety has to come from the credential, not from the prompt.

#How MCP works in Cursor

Cursor reads MCP servers from two files:

  • .cursor/mcp.json in a project, for tools only that project uses;
  • ~/.cursor/mcp.json in your home folder, for tools available everywhere.

It supports stdio, SSE and Streamable HTTP transports. Remote servers take a url and optional headers. Cursor expands ${env:NAME} in url and headers, so the token can live in an environment variable instead of the file. By default Cursor asks for approval before it runs an MCP tool, and you can expand a call to see its arguments. In Auto-review mode, allowlisted MCP tools run at once and other calls go through Cursor's classifier.

That approval prompt is your last line of defense. The steps below make sure it is not your only one.

#Step 1: a read-only connection

StitchDB runs a remote MCP server at https://stitchdb.com/platform/mcp. Create a personal access token under Access tokens in the dashboard with access Read-only, an expiry, and only the project you are working on. The token starts with sdb_pat_ and is shown once (access tokens).

Put the token in your shell environment, not in the repository:

Terminal
export STITCHDB_TOKEN=sdb_pat_...

Then add the server to .cursor/mcp.json:

JSON
{
  "mcpServers": {
    "stitchdb": {
      "url": "https://stitchdb.com/platform/mcp?project_ref=<project-ref>&read_only=true",
      "headers": { "Authorization": "Bearer ${env:STITCHDB_TOKEN}" }
    }
  }
}

?project_ref= limits the connection to one project and ?read_only=true makes it read-only whatever the token allows (URL options). Remove headers entirely to sign in with OAuth in the browser instead.

On a read-only connection, the tools that change anything are not even listed. execute_sql runs one statement inside a READ ONLY transaction, with a 15-second timeout and at most 1,000 rows. The service_role key, the JWT secret and the database password are never returned by any tool.

This covers most of what you want Cursor to do with a database: read the schema while writing code, write a query, explain an empty result, find a slow endpoint in the logs, list tables without Row Level Security. Try:

  • "Describe the orders table and write the TypeScript type for a row."
  • "Which tables have RLS disabled?"
  • "Why does GET /rest/v1/projects return an empty array for signed-in users?"

#Step 2: writes through an agent key

When the agent needs to change data or the schema, do not switch to a read-write personal token on production. Create an agent key instead, in Studio › AI agents › Agent keys (agent keys). Each key has:

  • A preset: Read-only, App developer (read and write rows of allowed tables) or Migrations (schema changes; drops, column removals and policy changes run only after approval).
  • Allowed and denied tables, for example allow public.*, deny public.payments.
  • Max rows per statement: a statement that changes more rows is rolled back and refused or sent for approval.
  • Its own Postgres role, so the grants are enforced by Postgres itself, whatever SQL the agent sends.

Use it as the MCP token:

JSON
{
  "mcpServers": {
    "stitchdb-agent": {
      "url": "https://stitchdb.com/platform/mcp",
      "headers": { "Authorization": "Bearer ${env:STITCHDB_AGENT_KEY}" }
    }
  }
}

With an agent key, the server offers a smaller set of tools: execute_sql through the query firewall, list_tables, describe_table, get_approval, get_session, undo_session and check_exposure. Each MCP session is an undo session.

#What happens when Cursor tries something destructive

The firewall parses every statement with the real Postgres parser before it runs. Transaction control, SET ROLE, DO blocks, COPY, dynamic SQL and platform schemas are always refused, with a reason the agent can read:

JSON
{ "error": "Table public.payments is denied for this agent key",
  "code": "agent_firewall", "rule": "table_denied", "statement_index": 0 }

Risky statements are not refused but held. DELETE or UPDATE without a real WHERE (including WHERE true and WHERE 1 = 1), changes to more rows than the key allows, DROP, TRUNCATE, RLS and privilege changes return:

JSON
{ "status": "pending_approval", "approval_id": "6d0c…", "reasons": ["unbounded_write"],
  "approve_url": "https://stitchdb.com/dashboard/project/<ref>/agents/approvals/6d0c…" }

You get an e-mail, look at the exact statement in Studio › AI agents › Approvals, and approve or reject it. The agent polls with get_approval. Requests expire after 24 hours (approvals).

So the realistic failure, the agent "cleaning up" a table on the wrong database, turns into a pending request instead of a lost table.

#If Cursor already deleted your data

Work from the most targeted fix to the broadest.

  1. Undo the agent session. If the agent used an agent key, open Studio › AI agents › Sessions & undo, pick the session and choose Undo session…. It shows a dry run first. Rows the agent changed or deleted come back with their old values; dropped tables went to a trash schema and dropped columns kept their values, so those come back too. Rows someone else changed afterwards are skipped as conflicts (undo).
  2. Restore to a point in time. Point-in-time recovery is included on every paid StitchDB plan (7 days on Pro, 14 on Scale, 30 on Enterprise). Free has no backups, so keep your own exports there. On paid plans you can restore into a new branch first, to look before you touch production (backups).
  3. Check what else happened. Undo covers the database only. E-mails sent, HTTP calls made from SQL and queue messages already consumed are not reversed.

Then fix the cause: revoke the credential the agent used, and replace any connection string in .env that the agent could reach with a scoped key. The longer walkthrough is in undo what an AI agent changed.

#A checklist for Cursor and databases

  • Keep production credentials out of the repository and out of .env files the agent reads.
  • Default to a read-only MCP connection scoped to one project.
  • Use a development project or a preview branch for agent writes when you can.
  • Give write access through an agent key with denied tables and a row limit.
  • Leave Cursor's tool approval on for anything that writes.
  • Turn on RLS Guard so every new table the agent creates gets Row Level Security (exposure check).
  • Ask the agent to run check_exposure after it creates tables or policies.

#FAQ

#Can Cursor connect to Postgres directly?

Yes, through an MCP server or by running psql in the terminal with a connection string. An MCP server with scoped, revocable tokens is the safer choice, because the credential decides what the agent can do, not the prompt.

#Where does Cursor store MCP settings?

In .cursor/mcp.json inside a project and ~/.cursor/mcp.json for all projects. Use ${env:NAME} in headers to keep tokens out of the file.

#Does read-only mode stop all writes?

On StitchDB, a ?read_only=true connection hides every tool that changes anything, and execute_sql runs inside a READ ONLY transaction, so Postgres itself refuses writes.

#Can an agent key bypass Row Level Security?

Only if you turn on Bypass Row Level Security for that key. By default it sees only rows your policies allow for its role.

Connect Cursor to Postgres with guardrails: follow the Cursor setup and create a free project.