mid:plane
Access layer for your PostgresOpen source · MITBacked by Y Combinator

Let your agent touch production. Without the postmortem.

Midplane sits in front of your Postgres as an MCP server and decides what each query can do — parser-level, audited, denied before it runs.

Start free →no credit card · live in 2 minutes
works withCursor · Claude Code · Codex · any MCP client
the same query an agent runs on a Tuesday — with and without midplane in front of Postgres
before:midplanetue 09:17:34

Production gone in nine seconds.

# cursor agent, cleaning up stale rows
WITH cleanup AS (
  DELETE FROM users
  RETURNING *
)
SELECT count(*) FROM cleanup;
runs against your Postgres
postgres · prod0.9 s
users · 41,802 rows deleted
production: gone
09:18 — #incidents · sev1 · “what happened?”
after:midplanetue 09:17:34

Denied before it runs.

# same agent, same query
WITH cleanup AS (
  DELETE FROM users
  RETURNING *
)
SELECT count(*) FROM cleanup;
hits midplane policy first
midplane · policytable_access
DENIED · users is not in the write-list
the DELETE in the CTE was caught at parse time
09:17 — audit logged · agent pivots to a SELECT
— try it

See what it allows. And what it stops.

Pick a query an agent might run. Flip a table's access level. Watch the policy decide — live, right here.

1 · pick a query
2 · set table access
users
orders
feature_flags

tap a value to change it · guardrails still apply

the query · Delete one user row
DELETE FROM users
WHERE id = 42;
midplane decides
DENIEDchecked at the policy

Writes to users aren’t allowed — users resolves to read. Flip it to read + write on the left to permit this exact statement.

Every decision is written to an append-only audit log before the query runs.

The full policy model →
— masking

The agent broke nothing. Just every email and SSN, in a context you don't control.

Table access decides whether a read runs. Masking is the layer underneath — it decides what each column returns, redacting sensitive values before they ever leave Postgres.

the agent runs
SELECT id, country, email,
       phone, ssn
FROM users
LIMIT 50;
A perfectly valid read. Allowed — but not at face value.
MASKEDby the column policy
what the agent receives
idcountryemail •phone •ssn •
1042USs••••@••••.com+1 ••• ••• ••42•••-••-••81
1043DEm•••@••••••.io+1 ••• ••• ••07•••-••-••07
1044GBj•@•••••.dev+1 ••• ••• ••88•••-••-••88
sensitive columns, masked before they leave Postgres · id and country pass through untouched.
How column masking works →
— the layer

One layer. Six guarantees.

Where your data lives, who can decrypt it, how agents get in — and how you'd leave.

01

Audit trail

Every query on the record before it runs — denials included.

How it works →
02

Data residency

EU or US, chosen once. Your data never moves.

03

Tenant isolation

Your keys, your rows — no path between accounts.

04

Scoped agents

Least privilege per agent, revoked in one click.

05

One endpoint

Any MCP client, OAuth sign-in, nothing to install.

Connect your agent →
06

Self-host

The whole product, MIT, on your infrastructure.

— get started

Three ways in. Pick your door.

Rolling this out to a team, or want it in front of production first? Talk to the founders →