Introducing the Xata MCP server 2.0

Let a coding agent branch your Postgres, work in the copy, and delete it. No sandbox flags, no mock modes, no credentials in the model's context.

By:

Claudiu Dascalescu

Published:

Reading time:

5 min read

An engineer we talked to described their agent setup like this: every tool had to know whether it was running in sandbox mode. A flag threaded through the codebase, mock modes, test doubles that drift from the real thing until the day they matter.

That is a lot of code, and all of it exists to protect one database.

Give the agent its own branch of that database and none of it is necessary. Nothing needs to know it's in test, because everything is. The tools connect to a real Postgres and run real queries against a copy nobody will miss.

Xata is Postgres with copy-on-write branching built in. If production lives somewhere else, on RDS, Aurora, Cloud SQL or your own hardware, you connect it once and Xata replicates from it. Production keeps serving production, and branches come off the copy. You pay for the diffs rather than for a full replica, which is why a branch is cheap enough to create for one agent run and delete on the way out.

The Xata MCP server is how an agent gets one. You add https://api.xata.tech/mcp to Cursor, Claude Code, Codex or whatever you already work in, and sign in through the browser. We shipped a first version in May 2025.

Handing an agent real production data

Two things go wrong quietly when something fast is working unattended: a credential ends up somewhere you did not put it, and a write happens that nobody asked for.

With the MCP the agent never receives a credential. It names the branch it wants, the server resolves the gateway on its own side, and rows come back.

Reads run, writes ask. run_sql is read-only by default, enforced in a read-only batch rather than by the prompt. A write needs write=true and confirm=true, two flags because tool annotations are advisory and a client can be set to approve everything. Forget the second and the model gets a sentence back instead of a result:

The check runs before the gateway is resolved, so a refused write opens no connection and sends nothing at all.

The call tools are split three ways because MCP clients allow and block per tool name: with one general-purpose tool, letting an agent read your Xata account lets it delete things too. Only the destructive one asks for a confirmation, so you can allow reads without allowing deletes.

The agent creates the branch

The agent runs the whole loop itself. It creates the branch, asks for the schema that is actually there rather than the one it inferred from a file, works in it, and deletes it when the run is over.

The branch carries your production data. If you anonymized it on the way into Xata, the branch carries the anonymized version, and that is what the agent sees.

Inside it the agent has a real Postgres to work in. It can read anything, change data, change schema, load a table, and throw all of it away when it's finished. Xata's own task guides are served to the model while it works, so an agent loading data into a branch or migrating one reads how to do it here instead of guessing from training data that predates the API.

Those confirmations are cheap to grant on a branch you already intend to throw away, and not something you would ever wire up against production.

What the agent can see

The sandbox flags are the visible cost. The bigger one is what the agent has to work from.

On a seeded fixture that is rows somebody wrote by hand. The distributions are invented, the edge cases are the ones a person already thought of, and the query that looks fine against ten rows meets a few million with a skew nobody seeded for. Seeding is maintainable right up until it isn't: to stay useful the fixture has to keep matching production's shape, and that is a job nobody owns.

On a branch it is whatever is actually there. The real nulls, the real skew, the handful of rows at the far end that break the assumption the query was written on. It came from production, so it has production's shape, minus the part where breaking it matters.

So the agent can look before it writes, because reading approves nothing and asks nobody. It can check whether the index it is about to suggest would actually get used, or whether the column it wants to put a constraint on holds values that would fail it. Then it can try the thing and find out, and what it breaks is a copy that exists for this run.

Getting there takes one line in whatever client you already work in.

Get started

The server is open to any Xata account, and it's published to the official MCP registry. If you don't have an account yet, the quickstart gets you to a project and a branch, and cloning a production database covers pointing one at the Postgres you already run. Once a branch exists, in Claude Code:

Then start Claude Code, run /mcp, select the xata server and sign in through the browser. Ask your assistant who it's authenticated as. If it comes back with your Xata identity, you're connected. For CI and anything else headless, skip the browser flow and pass a dedicated Xata API key as a header instead:

Codex, on 0.50 or later, is codex mcp add xata --url <https://api.xata.tech/mcp, then codex mcp login xata --scopes mcp-client,offline_access. If the first command opens a browser and reports an OAuth error, ignore it and run the login anyway: the server entry is already saved. The walkthrough below does that end to end.

It's Streamable HTTP, so there's no SSE endpoint and nothing to install locally. Setup for Cursor, VS Code, Claude on web and desktop, ChatGPT, Codex, Zed, Cline, Windsurf, Amp, OpenCode and Antigravity, along with the full tool list and the security notes, is in the docs: xata.io/docs/platform/mcp.

Share

Start your 14-day free trial

Give every agent, CI job, and preview deploy its own Postgres branch with production-like data.

Related Posts