Does the AI Write the SQL, or Does MCP?
When Claude or ChatGPT 'queries your database,' who actually writes the SQL? A clear breakdown of the four tools an MCP database gateway exposes — list_tables, describe_table, query_table, execute_sql — and which one is running when.
"Wait — is the AI writing SQL queries against my database? That seems dangerous. Or is it MCP doing that, and the AI just... asks?"
That question comes up constantly from people who just connected Claude or ChatGPT to a database for the first time. The honest answer is both, depending on the question — and once you see the four tools underneath, the confusion mostly goes away.
For the protocol-level version of this (JSON-RPC, tools/call, transports), read how MCP actually works. This post stays one level up: what actually happens, in practice, when you ask "where are my customers coming from?"
The model never touches your database directly
However this gets phrased, one thing is true across every setup: the AI model does not open a connection to your Postgres, MySQL, or SQL Server instance. It has no driver, no credentials, no network path to it.
What it has is a list of tools — named functions with a description and a schema — that an MCP server (Synra, or a self-hosted one) exposes. The model reads your question, decides which tool answers it, and sends a structured request. The MCP server is the only thing holding real credentials and the only thing that opens the actual database connection.
So the question "does AI write SQL" doesn't have one answer — it depends on which tool it reaches for.
The four tools, and who writes what
A typical database MCP server (Synra's included) exposes four tools:
list_tables — no SQL at all. Returns the table names the connection can see. This is what runs when you ask "what tables do I have?"
describe_table — no SQL either. Given a table name, returns its columns and types. Runs when you ask "what's in the orders table?" or when the model self-corrects after guessing a column name wrong (see stop AI guessing column names).
query_table — the AI does not write SQL here. The model passes a table name and simple filters ("status = active", "created after 2026-07-01") as structured parameters. The MCP server builds the actual SELECT statement. This is the tool for most everyday questions — "show me trial signups from last week" — and it's the safer default because there's no free-form SQL to get wrong.
execute_sql — this is where the AI writes real SQL. For anything query_table's simple filters can't express — joins, aggregates, GROUP BY, window functions — the model writes a SELECT statement itself and sends it as text. The gateway validates it's read-only, runs it, and returns rows (capped — see below).
So: "where are my customers coming from" with a simple grouping is probably execute_sql with a GROUP BY utm_source. "What's in the customers table" is describe_table, no SQL involved. Same AI, same conversation, different tool depending on what the question actually requires.
Why the distinction changes what can go wrong
This isn't just trivia — it changes how you debug a bad answer.
If query_table gave you a wrong-looking result, the SQL wasn't the problem (there wasn't any AI-written SQL); the issue is more likely a filter that doesn't mean what you assumed, or a table that isn't what you think it is.
If execute_sql gave you a wrong-looking result — or an outright error — the model's SQL is now a real suspect: a misspelled column, a reserved word used unquoted (why AI's SQL fails on reserved words), a join that silently duplicates rows. That's the moment to ask "show me the SQL you ran" and actually read it.
Rows are also capped at 500 for execute_sql on Synra specifically, so a forgotten LIMIT doesn't return your entire orders table into chat — the gateway truncates it and tells the model to add a LIMIT or use an aggregate instead. That's a execute_sql-only concern; query_table doesn't have this failure mode because you're never assembling an unbounded query in the first place.
How to actually see which tool ran
Ask the model directly — "what tool did you just call, and if it was execute_sql, show me the query." Models will echo this back from their own context; nothing about it is hidden from you.
If you're on a managed gateway, the usage log is the more reliable source — it records the tool name, the connection, duration, and status for every call, independent of what the model chooses to tell you. That's the same log covered in what your AI query audit log is for.
The short version
You didn't misread it — the AI can write SQL. It just doesn't for every question, and when it does, it's writing a SELECT against a read-only connection it never held credentials for. MCP is the layer in between that decides whether your question needs raw SQL at all, and if it does, the layer that runs it, caps it, and hands back rows — not a live wire straight into your database.
Read-only MCP gateway with all four tools, row caps, and a usage log: mcpserver.design.
Related reading: