# Why I built a SQL client when 10 already exist — then let AI agents into it

> Source: <https://dev.to/gillarohith/why-i-built-a-sql-client-when-10-already-exist-then-let-ai-agents-into-it-4kk4>
> Published: 2026-07-18 12:59:03+00:00

There are plenty of good SQL clients. I built another one. For a long time the honest answer to "why?" was just *taste* — I wanted something fast, keyboard-first, monospace-native, with no telemetry and no ceremony. A tool that gets out of the way. That's a fine reason to build for yourself, but it's a weak reason to expect anyone else to care.

Then AI agents showed up, and the question changed.

More and more of my day runs through an AI agent. And increasingly that agent wants to *touch the database* — check a migration, count some rows, verify data before it writes code against it.

The naive way to give it that is genuinely alarming: hand the agent raw connection credentials, or wire up a "run this SQL" tool with no guardrails. Now a probabilistic system has an unmonitored write path to your data. One confidently-wrong `UPDATE ... WHERE`

(or a missing `WHERE`

) and you're restoring from backup.

I didn't want to hand an agent my database. I wanted to *lend* it — with rules. None of the clients I had were built around that, so that became the actual reason for mine to exist.

data-peek can now run a local MCP server, so any MCP client (Claude Code, etc.) can work against your connections. The interesting part isn't the protocol — it's the safety model. Three independent mechanisms:

The read tools (`run_query`

, `list_schemas`

, `explain_query`

) don't just promise to be read-only. Each query runs inside a transaction that is **always rolled back**, and on PostgreSQL the session is additionally set to `SET TRANSACTION READ ONLY`

. Results are capped at 500 rows.

So even if an agent crafts something clever — a data-modifying CTE, a function with side effects — the transaction is discarded either way. "Read-only" is enforced by the database, not by string-matching the SQL. Defense in depth beats a regex every time.

There's exactly one tool that can change data, and it doesn't run anything on its own. `execute_statement`

shows you the **exact SQL** in an approval dialog inside the app and blocks until you decide. Approve and it runs; reject and it doesn't; ignore it for 60 seconds and it auto-rejects.

The agent proposes. You dispose. That single interaction turned out to be the whole product — the moment you feel in control instead of hoping the model behaves.

Every statement — reads and writes, agent or human — lands in a local audit log. Each entry is hashed together with the hash of the entry before it, forming a chain. Edit or delete a past entry and the chain breaks from that point, which a one-click **Verify** surfaces (it reports the first broken entry). You can export the whole thing to CSV/JSON.

It's local, off by default, and prunable. Nothing is uploaded — the point is *you* can answer "what did the agent actually run," not that I can.

`127.0.0.1`

, secured with a bearer token you can regenerate to revoke clients.Setup is one command it generates for you — `claude mcp add ...`

— and you're connected.

Because the ten good ones were built for a world where the only thing querying your database was *you*. That's no longer true, and "let an agent in, but on your terms" turned out to be a real, unmet design problem — not a checkbox you bolt onto an existing tool.

data-peek is a fast desktop SQL client for PostgreSQL, MySQL, SQL Server, and SQLite. It's MIT source, free for personal use, and there's a continuity guarantee so adopting it isn't a leap of faith.

If you've given an agent database access some other way, I'd genuinely like to hear how you handled the write path — that's the part I'm least done thinking about.
