Writing ·
How do I make an MCP server read-only?
People asking this usually mean something specific: I want the agent to be able to look at our data and not be able to change any of it. Here is how to get there properly, in the order the layers matter — and if you are not yet sure that is the whole of what you want, what people actually mean by a read-only MCP server takes the phrase apart first.
Layer 1: don’t generate the tool
This is the one that does the work. In MCP DB Wizard a table is curated per operation, not per
table — read, create, update and delete are four separate ticks. A newly selected table is
read-only: read is ticked and the other three are yours to
tick, deliberately, one table at a time.
If you never tick delete, there is no delete tool. Not a disabled one, not one that returns
“permission denied” — the method and the class are simply not in the generated code. There is
nothing to invoke and nothing to talk into invoking itself.
That distinction matters more than it sounds. A tool that exists and refuses is a tool whose refusal is a runtime decision, and runtime decisions have bugs, edge cases and bypasses. A tool that was never emitted has none of those, because it isn’t there.
Layer 2: back it with the grant
Do this anyway. If a table is read-only in the config, don’t grant INSERT on it to the account the
server connects as. See Oracle user privileges for the shape we
suggest, and choosing the account itself for
why it should never be the one that owns the tables.
This is belt and braces, and the braces are worth having: the config is a file that a human edits, and humans tick the wrong box. The database grant is the thing that is still true when someone regenerates a config at half past five on a Friday.
Layer 3: know what happened
Read-only systems still need an audit trail — partly because “read-only” is a claim you may have to demonstrate, and partly because reads themselves are worth knowing about. Every installation has a local trail, free tier included; what a licence changes is how long it is kept and whether it can be streamed off the box.
The bit people get wrong
Read-only is not a switch, and we deliberately did not build one. A master “read-only mode” flag sounds convenient right up until someone turns it off, at which point every write tool in your config becomes live at once, everywhere, with no review.
Curating per operation is more work on day one. It is also the only version where “what can this thing change?” has an answer you can read off a list instead of inferring from a runtime setting.
The other bit people get wrong
A foolish, ill-informed or malign agent can do a huge amount of damage by returning results which do not match business reality. Finding out after the fact that the wrong information was provided is a ‘closing the stable door after the horse has bolted’ situation.
What about your own SQL statements?
Those you write yourself, so you decide. A statement that reads is read-only; a statement that updates is not. The product does not guess — the SQL statements you add are yours, tested by you, and the agent runs those and only those.
If you ask your DBA team you’ll find that for any given application there are a core set of SQL statements that make up 80% of traffic. Giving an MCP server ‘canned’ access to these, and these alone, means that the MCP server is no longer in the business of looking at the schema and making wild guesses.
How do I get MCP DB Wizard?
It’s available from our GitHub repo as a Docker image.