Give your agent a backend it cannot guess at
Your agent writes the frontend against real tables, applies schema changes through a governed kernel, and structurally cannot drop a table on a bad turn.
- Who this is for
- Developers using Claude Code, Cursor, or Codex
- What you already have
- A frontend and an agent in the editor
- What you need
- A live schema and safe writes
The problem
Ask an agent for a full-stack feature without giving it a backend and it invents one. It writes fetch calls to endpoints that do not exist, defines response types nothing returns, and mocks the data so the UI renders. The frontend works the way a film set works. Then the session ends, and everything the agent knew about the schema ends with it. The next session re-derives it, slightly differently.
What you would normally build
A schema and its migrations, REST or GraphQL handlers, auth middleware and session handling, row-level authorization on every query path, a deploy pipeline, and enough monitoring to know when one of them breaks. Then you own all of it, including the parts the agent wrote and will not remember writing.
What Backenly does
Connect
One command, one scoped key, one restart
Local over stdio or remote over Streamable-HTTP. The key is scoped to a single project and revocable, and can be minted read-only, which withholds every write door including backend_chat.
Read
Your agent grounds itself in the real schema
read_backend_state for the project, get_table_schema for one table, which returns column types, foreign keys with their ON DELETE behaviour, indexes, and CHECK constraints with their permitted values. An agent that has not read those writes an insert that looks correct and fails on a constraint it had no way to see.
Write
Schema changes as ordinary DDL
apply_migration takes CREATE TABLE, ALTER TABLE, and CREATE INDEX, applies them as written, and translates them into governed typed actions. Anything it cannot map is refused with the route forward rather than silently dropped. Row changes go through db_insert, db_update, and db_delete.
Refuse
Destructive operations never execute over MCP
They are absent from the advertised surface. A request to drop a table parks in the Review Queue with an approval id; the dashboard card shows the target and the live row count. Your agent polls check_approval; after a failed run it checks the current state before asking again, because a call that stops part-way can leave some of its work applied.
Type
Generated types instead of hand-written ones
generate_types reads the live catalog and carries a schema hash, so you can tell whether a regeneration actually changed anything. The CLI's diff command exits non-zero when committed types drift from the schema, which makes it a CI gate.
You: What tables does this project have?
Agent: (read_backend_state) users, recipes, follows, favorites,
with columns, types, and relations from the live schema.
You: Add a saved_searches table with user_id and query.
Agent: (apply_migration) Applied. The table is served at
/db/saved_searches immediately, no generation step.
You: Drop the users table.
Agent: Not available over MCP. Sent to the Review Queue as
approval a1f3…, 1,284 live rows. Approve in the dashboard.What you end up with
A backend that outlives the session and a record of how it got there. The agent reads real field names, so its integration code compiles against something that exists; the change ledger explains what happened last Tuesday and why, whether you or the agent did it.
Who owns what
Backenly does
- Serves the tool manifest and enforces key scope on every call.
- Applies every structural change through one audited kernel.
- Refuses destructive operations over MCP and routes them to human approval.
- Keeps the schema, the change history, and the verification evidence after the session ends.
You own
- Restart the MCP host after installing. The tools do not exist until it reconnects.
- Approve or reject anything that reaches the Review Queue.
- Own the frontend, the product decisions, and whether a proposed schema is the right one.
- Keep the scoped key out of the repository.
What this is built on
The tools, routes and modules involved, by name, so you can go and check each one.
| Capability | What it does here |
|---|---|
| MCP server | 23 advertised tools over stdio or Streamable-HTTP; the dispatcher stays wider so pinned clients keep working. |
| get_table_schema | Columns, foreign keys with ON DELETE, indexes, CHECK constraints with permitted values, and live RLS policies with their roles. |
| apply_migration | Ordinary PostgreSQL DDL, applied as written and translated into governed actions. All-or-nothing. |
| check_approval | Polls an escalated operation: pending, executed, partial, failed, rejected, expired. |
| generate_types | TypeScript declarations or a typed client from the live catalog, with a schema hash. |
| Read-only keys | A reduced manifest; a write call is refused with READ_ONLY_KEY before anything runs. |
Known limitations
Where this workflow stops. If one of these is load-bearing for you, it should decide it.
- MCP hosts read their manifest at process start. Tools are absent from the session that installed them until the host restarts. This is the single most common "it did not work" report, and it is not a bug.
- The advertised surface is capped at 23 tools on purpose. Capabilities beyond it (preview-branch discard, vector search, schema adoption) are reached by describing them to backend_chat rather than by a named tool.
- There is no raw-SQL path for mutating structure. Operations the migration parser cannot map are refused rather than passed through.
- Backenly exposes no SQL functions, so there is no rpc() surface. Custom logic runs as an event, cron, or HTTP function.
Common questions
Anything that speaks MCP. Claude Code, Cursor, Codex, Cline, and Claude Desktop are the ones with tested setup paths, and the Connect tab renders the exact config for each. Two transports are available: the npm package over stdio, or a remote Streamable-HTTP endpoint with nothing to install.
It cannot execute a destructive operation. Those tools are not on the MCP surface, so a request to drop or truncate returns an approval id instead of a result and waits for a human in the dashboard. Non-destructive changes it can make are applied through the governed kernel and recorded, and schema changes capture a snapshot before they run.
Regenerate them with generate_types or the CLI. If you commit generated types, wire `backenly diff` into CI: it exits non-zero when the committed types no longer match the live schema, which turns silent drift into a failed build.
Try it on one free project
No credit card. Connect your agent over MCP and judge it by the verification evidence.