In-house flow
Change a schema without taking the site down
The dangerous migration is not the one that fails. It is the one that runs perfectly and holds a lock on your busiest table for four minutes. One item for the idioms, one that reads the live schema, and two that read the SQL before anything does.
The failure this is for
An agent asked to change a schema is working from a mental model assembled out of
migration files, an ORM's types, and whatever it last read. Sometimes that model
is stale and the failure is loud: a column that was renamed, an insert that hits
a NOT NULL it could not see. Those are fine. They fail immediately and somebody
fixes them.
The expensive ones do not fail at all.
| The failure | What it looks like | What answers it |
|---|---|---|
| Stale mental model of the schema | references a column renamed two migrations ago | read the deployed schema |
| A lock nobody costed | CREATE INDEX stalls writes for four minutes at 2pm | classify the lock before it runs |
| Foreign key with no index | deletes get slower every week, forever | the same static pass |
| An index the planner ignores | it exists, it is never chosen, writes pay for it | the plan, before you build it |
| A join that double counts | a valid number, fast, and wrong | semantic analysis of the query |
| MySQL-shaped Postgres | works, then does not scale | current Postgres idiom |
Structure, then behaviour, then arithmetic
The order is the argument. Idioms first because a good first draft saves three rounds. The live schema second because that is the only item here that can contradict the agent about what exists. Then two static passes, and those two are the half people skip.
Once a team has wired up a read-only database server, the database problem feels
solved: the agent can see the schema, what else is there. What else is there is
that a live connection tells you about a lock by taking it. explain and the
slow query log are both after the fact. The only way to learn that an
ALTER TABLE will hold ACCESS EXCLUSIVE on your largest table without learning
it from your on-call engineer is to read the DDL statically first.
The last item catches a different species entirely. Every other item here is about whether the SQL will run. That one is about whether the answer is true. A fan-out join that doubles a metric produces no error, no slow query, and no symptom except a number somebody will later build a decision on.
Why three of these never touch your database
Three of the four items in this stack are text analysers. They read documentation, DDL, or a query, and they hold no credentials. Only the second one connects, and it connects read-only.
That is not an accident of what was available. It is the property that made this stack shippable, and it is worth being explicit about the rule, because a fifth item was cut by it.
There is a Postgres tuning server that answers a question genuinely missing here: whether an index the agent is about to create would actually get used. It simulates the index with HypoPG and runs the plan against real data distribution, so you learn the planner will ignore your index before you spend a lock building it. Nothing else in this stack answers that.
It has 25 stars and it wants a DATABASE_URI.
Meanwhile the third item in this stack has 5 stars, and it is here. That looks inconsistent and is not, because the bar is not a star count. It is a ratio: what a tool asks for, against how much is known about it. A 5-star project that parses SQL text on your machine and holds no credentials is a small bet with a small downside. A 25-star project that wants a live connection string to your production database is a much larger one, and 25 stars is not enough evidence to underwrite it.
A flat threshold would have made the opposite call on both. That is the argument for judging the ask alongside the number rather than ranking on the number alone.
Set it all up
3 of 4, in order
claude mcp add pg-aiguide -- npx -y @tigerdata/pg-aiguide
claude mcp add dbhub -- npx -y @bytebase/dbhub
claude mcp add migrationpilot -- npx -y migrationpilotSome of these are the commands their projects publish and some are assembled from repository paths. Each one is labelled where it appears below. Nobody here has run them as a set.
How it goes
Their working order, our numbers
First, because the cheapest correction is the one you do not have to make. Curated Postgres practice plus documentation search, so the first draft is idiomatic rather than the MySQL-flavoured SQL that turns up when a model answers from the average of everything it has read. Never connects to a database.
Pg aiguideMCP server
timescale/pg-aiguide/io.github.timescale/pg-aiguide1,803★ repoApache-2.0
claude mcp add pg-aiguide -- npx -y @tigerdata/pg-aiguideAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
Then read the schema that is actually deployed, rather than the one implied by the migration folder or an ORM's cached types. Structure: columns, types, the nullable nobody remembers, the indexes that already exist. Set `readonly = true` on `execute_sql` and this can look at everything and change nothing.
DBHubMCP server
bytebase/dbhub/io.github.bytebase/dbhub3,265★ repoMIT
claude mcp add dbhub -- npx -y @bytebase/dbhubAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
Then, before the migration runs anywhere, find out what it locks. It parses the DDL with Postgres's own parser and classifies the lock each statement takes, so "CREATE INDEX blocks writes on users, use CONCURRENTLY" arrives as a review comment rather than as an incident. It also catches the foreign key with no index behind it.
MigrationpilotMCP server
mickelsamuel/migrationpilot/io.github.mickelsamuel/migrationpilot5★ repoMIT
claude mcp add migrationpilot -- npx -y migrationpilotAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
Last, for the backfill and the verification query, because the failure here is silence. A one-to-many join that fans out and doubles a SUM returns a valid number, quickly, and nothing anywhere reports a problem. Reads the query text and never connects.
SqlsureMCP server
sqlsure/sqlsure/io.github.sqlsure/sqlsure97★ repoApache-2.0
No install line here. This server does not publish one we could copy, and it has no package name recorded, so anything shown here would be a guess at whether it runs from npm, PyPI, a container or a hosted URL.
The repository will have the real instructions: github.com/sqlsure/sqlsure
More of these
Stacks are written by hand and there are not many. The catalog underneath is large, and its default ordering puts whatever has been picked at the front.