A production connection string
Real data, and every table, every tenant, and every column that comes with it. One vague prompt away from a DELETE without a WHERE.
ZenStack Studio turns your Postgres, MySQL, or SQLite database into an MCP server that scopes Claude Code, Cursor, or any agent to the models, operations, and users you choose — so it works on real data without seeing all of it.
The MCP server is free on localhost.
you — which shipped orders are over $1,000 this month?
→ zenstack-studio · order.findMany { where: { status: "shipped", total: { gt: 1000 } } }
| idtext | customer.nametext | totaldecimal |
|---|---|---|
| ord_8f21 | Dana Whitfield | $1,240.00 |
| ord_8f23 | Priya Raman | $2,905.00 |
| ord_8f37 | Sam Okafor | $1,012.75 |
Three orders, $5,157.75 in total. The largest is Priya Raman's on Feb 20.
The problem
Your authorization — which tenant a row belongs to, what a support user may change, which fields are private — lives in your application. A connection string goes straight past it. So every option is a trade between access and safety.
Real data, and every table, every tenant, and every column that comes with it. One vague prompt away from a DELETE without a WHERE.
Nothing gets written, but nothing is hidden either. Ask about one customer and the agent can read all of them, PII included.
Safe, and useless for the question you actually have. The bug is in production, in one customer’s data, and the agent is looking at seed rows.
The difference
Studio’s MCP server does not speak to the agent as a database role. It speaks as your application schema — the models you expose, the operations you allow, and the access policies you already wrote — so the agent gets real data without getting all of it.
| Aspect | Connection-string MCP servers | ZenStack Studio MCP |
|---|---|---|
| What the agent can see | Everything the database role can reach | Only the models you expose |
| What it can change | Read-only or everything, for the whole database | Read, insert, update, delete — set per model |
| Whose data it acts on | Every tenant at once | One user, under your access policies |
| How it queries | Hand-written SQL against guessed column names | Prisma-style queries, type-checked against your schema |
| Where credentials live | In the MCP config on every machine | In the proxy you run; clients hold a signed access key |
Control
Per model
Turn read, insert, update, and delete on or off for each model. A model with nothing enabled is removed from the schema the agent sees, so it cannot ask about a table it does not know exists. A forbidden operation is rejected before it reaches your database.
Per user
An access key names the user the agent acts as. Every query then runs under your ZenStack access policies: rows that user cannot read do not come back, fields they cannot see are left out, writes they are not allowed to make are rejected.
Per query
The agent writes Prisma-style queries — findMany, create, groupBy — which it already knows from countless open-source projects. Each one is type-checked against your schema first, so a misspelled field comes back as an error to fix, not a failed query to retry.
The per-user rules are ZenStack access policies declared in your schema — the same ones Studio’s table and query editors enforce when you view the data as a user. One set of rules for people and agents.
What it makes possible
Hand Claude Code the ticket and a key for that customer. It reads their real orders and settings — and cannot wander into anyone else’s.
Issue one key per end user and put an assistant in your product that answers from live data, scoped to whoever is asking. No second authorization layer to build.
Let a support or ops teammate point their agent at the database with read access to the models they need and no way to touch the rest.
How it works
The server gives the agent exactly three tools and tells it to use them in order: read the schema, check the operation, then run it.
1. schema
Your schema, minus the models the agent may not touch, with the operations each remaining model allows.
2. check
Validates the model, the operation, and the permission, and type-checks the arguments against your schema.
3. execute
Runs the operation through your proxy. Permissions are enforced again here, so skipping check skips nothing.
Connect
Paste this instead. Enable the MCP server on a project in Studio and it hands you the configuration with the URL and an access key filled in. Your database credentials stay in the proxy and never touch the agent’s config.
Your proxy is reachable from the internet. The client talks to Studio’s MCP endpoint directly.
{ "mcpServers": { "zenstack": { "url": "https://studio.zenstack.dev/api/mcp/<your-routing-token>", "headers": { "Authorization": "Bearer <access-key>" } } }}Access keys are standard HS256 JWTs signed with your project’s MCP secret key, so your backend can mint one per user with any JWT library. The claim names the user your access policies read; { type: 'superUser' } bypasses them.
With authentication on, the server verifies the signature on every request and refuses one without a valid key.
import crypto from 'node:crypto' const secret = '<your MCP secret key>'const header = Buffer.from(JSON.stringify({ alg: 'HS256', typ: 'JWT' })).toString('base64url') // The user the agent acts as. { type: 'superUser' } bypasses access policies.const payload = Buffer.from( JSON.stringify({ type: 'user', data: { userId: '<user-id>' } })).toString('base64url') const signature = crypto .createHmac('sha256', Buffer.from(secret, 'hex')) .update(`${header}.${payload}`) .digest('base64url') const accessKey = `${header}.${payload}.${signature}`It is as safe as the access you give it. Studio lets you decide which models the agent can see, which operations it may run on each, and which user it acts as — so an agent debugging one customer’s ticket sees only that customer’s rows. Your database credentials stay in the proxy you run and never reach the agent or ZenStack.
A typical database MCP server connects with a database role and gives the agent a SQL tool, so the agent can reach whatever that role can — usually every table and every tenant. Studio’s MCP server works at the level of your application schema instead: models and operations you allow, access policies evaluated per user, and a check step that type-checks each query against your schema before the agent runs it.
No. Studio introspects your existing database and your application code stays as it is. Per-user scoping reads access policies, which you add to the generated schema when you want them.
Any client that speaks the Model Context Protocol — Claude Code, Claude Desktop, Cursor, and others. Studio gives you a connection URL and a ready-made configuration block to paste into the client.
Yes. Run the local delegate, @zenstackhq/studio-mcp-remote, as the MCP command in your client. It runs on your machine and forwards requests between the agent and the proxy on your network.
npx @zenstackhq/cli studio