My AI-automated dev setup: MCP servers for your board, Postgres, and CI
Published July 14, 2026
I spend most of my week moving between two roles: writing code and reviewing code an agent wrote. That split only works because the agent isn't guessing what to do — it reads the same ticket I would, looks at the same database I would, and runs the same test suite I would. The thing that makes that possible is MCP.
This is a walkthrough of the shape of that setup: what's connected, why, and where it still falls over. Treat the specifics below as a template to adapt to your own tools, not a literal config to copy.
What MCP actually is
MCP (Model Context Protocol) is a standard way for an AI agent to talk to external systems — a database, a task board, a Git host, a CI system — without you writing custom glue code for every tool every time. An MCP server exposes a set of capabilities (read a ticket, run a query, list open PRs) over a common protocol. Any MCP-compatible agent can call those capabilities the same way, regardless of which model is behind it.
The useful mental model: MCP is to agents what a REST API is to a frontend. You don't hand-roll a new integration every time you want to read from a new data source — you point the agent at a server and it discovers what's available. The agent decides which tool to call and when; you don't have to script the sequence.
Why this beats copy-pasting into a chat window
Before I had this wired up, my "AI workflow" was: open the ticket, copy the description into a chat tab, copy in a couple of relevant files, describe the schema from memory, wait for a diff, paste it back into my editor, run tests myself, fix what broke. Every step was manual context transfer, and every manual step was a place where I'd forget something or the model would guess wrong.
With MCP servers wired into the agent, the agent pulls its own context. It reads the ticket instead of me summarizing it. It queries the actual schema instead of me describing it from memory (and getting a column name wrong). It runs the test suite itself instead of me running it and pasting the failure back in. None of this is exotic — it's the same steps I did by hand, just executed by the agent directly against the real systems, in a loop, without me relaying state back and forth.
The other benefit is less obvious: fewer errors from stale context. When I copy-paste a schema into a prompt, that schema is frozen at the moment I copied it. If a teammate ran a migration an hour ago, my copy-paste is wrong and I won't know it. An agent with a live MCP connection queries the current state every time.
The core loop
The setup that actually gets used day to day looks like this:
- Agent reads a ticket from the board MCP — title, description, acceptance criteria, linked PRs.
- Agent explores the relevant part of the codebase and, where needed, queries the database MCP to confirm schema and existing data shapes instead of assuming.
- Agent implements the change.
- Agent runs the test suite and lints locally, and iterates until it's green.
- Agent opens a PR with a description that references the ticket.
- I review the PR like I'd review anyone else's — that's the trust boundary, not any earlier step.
The important part is step 6 never moves earlier. The agent doesn't merge its own PR. It doesn't get write access to the database. It doesn't touch CI secrets. Everything upstream of my review is designed so that the worst outcome is a bad PR, not a bad deploy.
For step 1, the board MCP server needs read access to tickets and ideally comments/attachments, since a lot of real requirements live in the comment thread, not the description field. Which specific board and MCP server you use matters less than that property — pick whatever matches your team's existing task tracker.
Giving the agent a Postgres MCP
The single highest-leverage connection in this whole setup is the database MCP. Without it, the agent works from whatever schema knowledge is baked into old migration files or a stale ORM model in its context — and in a codebase that's been through a few refactors, that's often wrong. With a live, read-only connection to Postgres, the agent can:
- List actual tables and columns instead of trusting the model file.
- Check real data — is this column nullable in practice, not just in the migration; what values actually show up.
- Validate a query against the live schema before proposing it in code, instead of writing something that looks right and fails at runtime.
This turns "the agent guessed a column name and got it wrong" from a routine annoyance into something that basically stops happening.
A generic MCP config, as a template
A minimal setup looks like this — a template mcp.json shape you'd swap real values into for your own stack. This is the pattern (board + Postgres + CI), not literal config to paste.
{
"mcpServers": {
"task-board": {
"command": "npx",
"args": ["-y", "@example/board-mcp-server"],
"env": {
"BOARD_API_TOKEN": "${BOARD_API_TOKEN}",
"BOARD_WORKSPACE_ID": "${BOARD_WORKSPACE_ID}"
}
},
"postgres-readonly": {
"command": "npx",
"args": ["-y", "@example/postgres-mcp-server"],
"env": {
"DATABASE_URL": "${DATABASE_URL_READONLY}"
}
},
"ci": {
"command": "npx",
"args": ["-y", "@example/ci-mcp-server"],
"env": {
"CI_API_TOKEN": "${CI_API_TOKEN}"
}
}
}
}
The one thing I'd underline: DATABASE_URL_READONLY is not a naming convention, it's a requirement. The connection string the agent uses should point at a role that literally cannot write. More on that below. Once you've settled on your own stack, swap in real server names, packages, and whichever env vars your setup actually injects.
Guardrails: what keeps this safe
None of this is safe by default. An agent with a shell and a database connection can do real damage if you don't constrain it. The guardrails that matter, in order of importance:
Read-only DB roles. The Postgres MCP server connects with a role that has SELECT only. No INSERT, UPDATE, DELETE, DROP, nothing. If the agent needs to reason about data, it can read it. It never needs write access to do its job, because the actual writes happen through application code in a PR, not through the agent hitting the database directly.
CREATE ROLE agent_readonly LOGIN PASSWORD '...';
GRANT CONNECT ON DATABASE app TO agent_readonly;
GRANT USAGE ON SCHEMA public TO agent_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO agent_readonly;
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO agent_readonly;
Allowlisted commands. The agent's shell access is scoped — it can run the test suite, the linter, the build, package manager commands. It's not handed an open shell with sudo or deploy credentials. If a command isn't on the list, it prompts for approval instead of running silently.
PR review as the actual trust boundary. This is the one that matters most, and it's worth being explicit about it instead of assuming it's implied by "we use CI." Every guardrail above reduces the blast radius of a mistake before it happens. The PR review is what catches everything else — bad logic, a subtly wrong migration, a change that's technically correct but the wrong thing to do. I do not treat green tests as approval. Tests catch what they were written to catch; they don't catch "this is solving the wrong problem."
Where it still breaks down
This setup is good at well-scoped, well-described tickets against a codebase the agent can explore. It's noticeably worse at:
- Tickets that are vague or where the real requirement is a Slack conversation that never made it into the ticket.
- Anything that needs a judgment call about product behavior, not just code correctness.
- Cross-service changes where the agent doesn't have visibility into the other service's contract.
- Migrations — I don't let the agent generate and apply schema migrations unsupervised. It can propose one; a human applies it.
In practice, the failures cluster around missing context rather than the agent misusing the tools it has — which is exactly why the PR review step stays non-negotiable.
Where I'd start if you're setting this up
Start with the board MCP and the read-only Postgres MCP. Those two alone remove most of the manual context-relaying that makes AI-assisted work feel like babysitting a chat window. Add CI integration once the first two are boring and reliable. Keep the PR review as the one step you never automate away — that's not a temporary caution, it's the design.