readonly-postgres-mcp
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@readonly-postgres-mcpShow me the 10 newest orders in the sales database"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
readonly-postgres-mcp
Let Claude query your Postgres databases, read-only, from a server you own.
readonly-postgres-mcp is a remote MCP server that runs on Cloudflare Workers. Add it to claude.ai (or any MCP client that supports OAuth) as a custom connector, and Claude can answer questions and build dashboards from live data through a connection that cannot write.
Read-only. Every query runs in a read-only transaction that is always rolled back, one statement at a time.
Private. Only the Google accounts you list can sign in, and the list is checked on every request.
Cheap to run. Fits the Cloudflare free plan, with up to 10 databases.
How it works
flowchart LR
C[Claude / MCP client] -- OAuth token --> W[Worker /mcp]
W -- Google sign-in<br/>+ email allowlist --> G[Google]
W -- one read-only<br/>statement --> H[Hyperdrive]
H --> P[(Postgres)]The client signs in with Google. The Worker only issues a token if the email is verified and in
ALLOWED_EMAILS.Each MCP call is checked against the allowlist again, then the SQL runs through Hyperdrive inside
BEGIN READ ONLY…ROLLBACK.Rows come back as JSON.
Related MCP server: Secure RDS Read-Only MCP Server
Tools
Tool | Input | Returns |
| none |
|
|
|
|
|
|
|
describe_schema only shows the tables and columns the database role can SELECT.
Each query is limited to one statement of up to 16,000 characters, a 10s
statement timeout and 5,000 result rows. Results come back both as JSON text
and as structuredContent.
Setup
You need:
a Cloudflare account (free plan is fine)
a Google Cloud project, for the OAuth client
Node.js 22 or newer
a Postgres role that can read only what Claude should see (see Database roles)
Below, <your-subdomain> is your workers.dev subdomain, so the server lives
at https://readonly-postgres-mcp.<your-subdomain>.workers.dev.
1. Install
git clone https://github.com/zahidakhyar/readonly-postgres-mcp.git
cd readonly-postgres-mcp
npm install
cp wrangler.example.jsonc wrangler.jsonc
npx wrangler kv namespace create readonly-postgres-mcp-oauthThen edit wrangler.jsonc (it is gitignored, so your ids stay local):
Field | Set it to |
| the id printed by the last command |
|
|
MCP_RESOURCE must be exactly the URL you will add as the connector.
2. Create a Google OAuth client
In Google Cloud Console, go to APIs & Services → Credentials → Create credentials → OAuth client ID, choose Web application, and add these authorized redirect URIs:
https://readonly-postgres-mcp.<your-subdomain>.workers.dev/callback
http://localhost:8788/callback3. Set secrets and deploy
npx wrangler secret put GOOGLE_CLIENT_ID
npx wrangler secret put GOOGLE_CLIENT_SECRET
openssl rand -hex 32 | npx wrangler secret put COOKIE_ENCRYPTION_KEY
npx wrangler secret put ALLOWED_EMAILS
npm run deploySecret | Value |
| from step 2 |
| random; the command above generates one |
| comma-separated Google emails, e.g. |
| a Google Workspace domain; the sign-in screen then only offers accounts from it. Access is still decided by |
4. Add a database
npm run add-db -- <name> "postgres://<user>:<password>@<host>:5432/<db>"This creates a Hyperdrive config named <worker name>-<name> (caching off),
adds an HD_<NAME> binding to wrangler.jsonc, and redeploys. Names use
lowercase letters, digits and _. The connection string never appears in
error output.
To remove one: npm run remove-db -- <name>.
5. Connect Claude
In claude.ai, open Settings → Connectors → Add custom connector and enter:
https://readonly-postgres-mcp.<your-subdomain>.workers.dev/mcpSign in with an allowed Google account, then ask Claude to call
list_databases.
Database roles
The database role decides what Claude can see; the server's guards are a backstop. Give each database its own role and grant only the columns you need.
Run this as the table owner. A REVOKE run by any other role only prints
a warning and changes nothing, so do the check at the end:
REVOKE SELECT ON ALL TABLES IN SCHEMA public FROM <role>;
ALTER DEFAULT PRIVILEGES FOR ROLE <owner> REVOKE SELECT ON TABLES FROM <role>;
ALTER DEFAULT PRIVILEGES FOR ROLE <owner> IN SCHEMA public REVOKE SELECT ON TABLES FROM <role>;
GRANT SELECT (<columns>) ON <table> TO <role>;Then, through the connector, this must return false for every sensitive
table:
SELECT has_table_privilege('<table>', 'SELECT');Security model
Guard | What it does |
Google sign-in + allowlist | Only verified emails in |
Token audience | Tokens are bound to |
Read-only transaction | Each query runs in |
Single statement | The extended query protocol makes Postgres reject multiple statements. |
Limits | 10s statement timeout, 5s connect timeout, 16,000-character SQL, 5,000 rows. |
Logs | Query strings are redacted from Workers logs. |
To report a vulnerability, see SECURITY.md.
Troubleshooting
Symptom | Fix |
Sign-in fails with |
|
"This Google account is not allowed" | Add the email to |
| Pick another title; any name works. |
| Check the host, port and password in the Hyperdrive config ( |
| The role has no grant on that table or column. That's the role doing its job. |
Development
cp .dev.vars.example .dev.vars # fill it in; restart wrangler dev after edits
npm test
npm run type-checkTask | Command |
Integration tests against real Postgres |
|
Run locally on |
|
License
MIT. The OAuth code is adapted from Cloudflare's remote-mcp-google-oauth template (MIT); see THIRD_PARTY_NOTICES.
This server cannot be deployed
Maintenance
Related MCP Connectors
Query 40 databases from Claude, ChatGPT, or Cursor — on any device. Read-only, encrypted, audited.
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
Query your org's data in natural language — read-only MCP access to SQL, NoSQL, files & warehouses.
Query your Postgres from ChatGPT or Claude without exposing the database or handing over credentials. Run npx boltschema connect next to your database and it dials out over HTTPS — no inbound firewall rule, no open port, works with localhost and VPC-private databases. Read-only is enforced by a SQL guard, a Postgres READ ONLY transaction, and a scoped role generated for you.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceA hardened, read-only Postgres MCP server that enables LLMs to safely query databases without write, DDL, shell, or credential exposure.MIT
- AlicenseNot gradedqualityCmaintenanceProvides read-only access to PostgreSQL databases via MCP, enforcing least-privilege roles, row-level security, masked views, and SQL AST guardrails to prevent data leakage and unauthorized operations, enabling AI agents to safely query sensitive production data.MIT

MCP DB Gatewayofficial
AlicenseNot gradedqualityBmaintenanceProvides governed, read-only PostgreSQL access for AI agents via MCP. Enforces schema/table allowlists, query limits, and audit events.1MIT- AlicenseNot gradedqualityCmaintenanceEnables read-only, SELECT-only querying of any Postgres database through MCP-compatible clients like Claude, with schema introspection and guarded SQL execution.MIT