postgresql-mcp
A production-ready MCP server that connects AI assistants to any PostgreSQL database with 25 tools and role-based access control.
README
PostgreSQL MCP Server
A production-ready Model Context Protocol (MCP) server that connects AI assistants to any PostgreSQL database — cloud-hosted or self-hosted. Built on Cloudflare Workers and the Agents SDK, it provides 25 database tools with enterprise-grade authentication via Cloudflare Access and role-based access control through OIDC identity provider groups.
Key Features
- Universal PostgreSQL compatibility — connects to Neon, Supabase, Amazon RDS, Google Cloud SQL, Azure Database, self-hosted instances, or any PostgreSQL-compatible database
- 25 database tools organized into 4 permission tiers (universal, read-only, read-write, admin)
- Role-based access control — tools are conditionally registered per session based on IdP group membership
- SQL safety layer — blocks dangerous operations (DROP DATABASE, privilege escalation, multi-statement injection) at the parser level
- Enterprise SSO — OAuth 2.1 with PKCE via Cloudflare Access, supporting any OIDC identity provider (Okta, Authentik, Azure AD, etc.)
- Connection pooling — Hyperdrive manages connection pooling and TCP proxying to your database
- Private database support — reach databases on private networks via Cloudflare Tunnel
- Serverless — runs on Cloudflare Workers with Durable Objects for per-user MCP sessions, no infrastructure to manage
Architecture
MCP Client (Claude, Cursor, Windsurf, etc.)
|
| Streamable HTTP + OAuth 2.1
v
Cloudflare Worker
|-- OAuthProvider --> Cloudflare Access --> OIDC IdP (Okta, Authentik, Azure AD, ...)
|-- McpAgent (Durable Object — one per authenticated session)
| |-- Role-based tool registration via IdP groups
| |-- SQL Safety Parser (blocks dangerous patterns)
| |-- Prompts (query assistant, schema explorer)
| |-- Resources (schema dump, health dashboard)
|-- pg-client --> Hyperdrive --> PostgreSQL
|
+-----------+-----------+
| |
Public databases Private databases
(Neon, Supabase, (via Cloudflare Tunnel
RDS, Cloud SQL) + VPC Service)
Database Compatibility
This MCP server works with any PostgreSQL database that Hyperdrive can reach:
| Database | Connection Method | Tunnel Required? |
|---|---|---|
| Neon | Direct (public endpoint) | No |
| Supabase | Direct (public endpoint) | No |
| Amazon RDS (public) | Direct | No |
| Amazon RDS (VPC) | Cloudflare Tunnel | Yes |
| Google Cloud SQL | Direct or Tunnel | Depends on config |
| Azure Database for PostgreSQL | Direct | No |
| Self-hosted (public IP) | Direct | No |
| Self-hosted (private network) | Cloudflare Tunnel | Yes |
| Docker/local | Cloudflare Tunnel | Yes |
Role-Based Access Control
Tools are conditionally registered per MCP session based on the authenticated user's IdP groups. Users only see and can invoke tools matching their permission tier.
| IdP Group | Tools Available | Count |
|---|---|---|
| (any authenticated user) | Universal | 3 |
pg-readonly |
Universal + Read-Only | 10 |
pg-readwrite |
Universal + Read-Only + Read-Write | 15 |
pg-admin |
All tools | 25 |
Groups are extracted from the groups claim in the OIDC ID token. Multiple group formats are supported (Authentik, Okta, comma-separated strings, arrays).
Tools Reference
Universal Tools (3) — Always Available
| Tool | Description |
|---|---|
userInfo |
Current user's email, name, groups, and computed access level |
connectionInfo |
PostgreSQL version, database name, server time, current database user |
healthCheck |
MCP server and database connectivity check with response time |
Read-Only Tools (7) — Requires pg-readonly, pg-readwrite, or pg-admin
| Tool | Description |
|---|---|
listTables |
List all tables, views, and materialized views with row counts and sizes |
describeTable |
Full column definitions, indexes, and foreign key constraints |
executeQuery |
Execute validated read-only SQL (SELECT, WITH...SELECT) with parameterized values |
explainQuery |
EXPLAIN or EXPLAIN ANALYZE with JSON output for query optimization |
searchSchema |
Case-insensitive search across table and column names |
listIndexes |
Index listing with type, uniqueness, size, and scan count statistics |
getTableStats |
Live/dead row counts, dead row ratio, vacuum/analyze timestamps |
Read-Write Tools (5) — Requires pg-readwrite or pg-admin
| Tool | Description |
|---|---|
insertRows |
Parameterized INSERT with optional RETURNING clause |
updateRows |
Parameterized UPDATE with WHERE clause (auto-adjusts parameter indices) |
deleteRows |
DELETE with mandatory confirmation flag as a safety check |
executeSql |
Execute arbitrary non-DDL SQL (INSERT, UPDATE, DELETE, SELECT) |
upsertRows |
INSERT ... ON CONFLICT DO UPDATE with conflict target and update columns |
Admin Tools (10) — Requires pg-admin
| Tool | Description |
|---|---|
databaseHealth |
Connection utilization, buffer cache hit ratios, database size, uptime |
indexHealth |
Unused indexes, duplicate indexes, tables needing indexes |
vacuumHealth |
Dead row ratios, last vacuum timestamps, tables needing vacuum |
sequenceHealth |
Sequences approaching max value (prevents silent insert failures) |
createIndex |
Create indexes (CONCURRENTLY by default for non-blocking operations) |
dropIndex |
Drop indexes (CONCURRENTLY by default) |
executeDDL |
Execute DDL statements (CREATE TABLE, ALTER TABLE, etc.) |
analyzeTable |
Run ANALYZE to update query planner statistics |
getActiveQueries |
List running queries with duration, state, and wait events |
cancelQuery |
Cancel a running query by PID |
Prompts (2) — Always Available
| Prompt | Description |
|---|---|
queryAssistant |
Generate accurate SQL from natural language using live schema context |
schemaExplorer |
Guided database overview with tables, relationships, and exploration suggestions |
Resources (2) — Always Available
| Resource URI | Description |
|---|---|
schema://tables |
Full schema dump with tables, columns, types, and indexes (JSON) |
health://overview |
Database health dashboard with connections, cache, and table stats (JSON) |
SQL Safety
A dedicated SQL parser validates every query before execution:
Always blocked (all roles):
DROP DATABASE,DROP ROLE,DROP USERCREATE ROLE,CREATE USER,ALTER ROLE,ALTER USERGRANT,REVOKECOPY TO/FROM PROGRAM- Multi-statement injection (semicolons inside query body)
Role-enforced:
- Read-only — only
SELECT,EXPLAIN,SHOW, and CTEs without mutation - Read-write — adds
INSERT,UPDATE,DELETE(no DDL) - Admin — adds DDL (
CREATE TABLE,ALTER TABLE,DROP TABLE, etc.)
Getting Started
Prerequisites
- A Cloudflare account (Workers paid plan for Durable Objects)
- Node.js 18+ and npm
- Wrangler CLI (
npm install -g wrangler) - A PostgreSQL database (any provider)
- An OIDC identity provider configured in Cloudflare Access
Step 1: Clone and Install
git clone https://github.com/vnikhilbuddhavarapu/postgresql-mcp.git
cd postgresql-mcp
cp wrangler.jsonc.example wrangler.jsonc
npm install
Step 2: Create Cloudflare Resources
KV Namespace (stores OAuth state):
wrangler kv namespace create OAUTH_KV
Copy the id into wrangler.jsonc under kv_namespaces[0].id.
Hyperdrive Config (connection pooling):
# For a publicly reachable database:
wrangler hyperdrive create pg-mcp \
--connection-string="postgres://user:password@host:5432/dbname"
# For a private database via Cloudflare Tunnel:
# First create a VPC Service, then:
wrangler hyperdrive create pg-mcp \
--connection-string="postgres://user:password@<PRIVATE_IP>:5432/dbname" \
--vpc-id="<VPC_SERVICE_ID>"
Copy the Hyperdrive id into wrangler.jsonc under hyperdrive[0].id.
Step 3: Configure Cloudflare Access (OIDC)
- Go to Cloudflare Zero Trust > Access > Applications > Add SaaS Application
- Choose OIDC and select your identity provider
- Set the Redirect URI to
https://<your-worker>.workers.dev/callback - Enable scopes:
openid,email,profile,groups - Note down the following from the application configuration:
- Client ID
- Client Secret
- Token Endpoint
- Authorization Endpoint
- JWKS/Key Endpoint
- Configure your IdP to include a
groupsclaim with values:pg-readonly,pg-readwrite, and/orpg-admin
Step 4: Set Secrets
cp .dev.vars.example .dev.vars
# Edit .dev.vars with your Access credentials
Step 5: Deploy
# Generate types
wrangler types
# Deploy
wrangler deploy
# Push secrets to production
wrangler secret bulk .dev.vars
Step 6: Connect an MCP Client
Use the MCP endpoint URL with any compatible client:
https://<your-worker>.workers.dev/mcp
Or test with the MCP Inspector:
npx @modelcontextprotocol/inspector
# Enter your /mcp URL, authenticate via the OAuth flow
Development
npm install # Install dependencies
wrangler types # Generate TypeScript types from bindings
npm run type-check # TypeScript type checking
npm test # Run Vitest unit tests (48 tests)
npm run lint # Lint with oxlint
npm run format # Format with oxfmt
wrangler dev # Local development server (note: Hyperdrive requires deploy for full testing)
wrangler deploy # Deploy to Cloudflare
Project Structure
postgresql-mcp/
├── src/
│ ├── index.ts # McpAgent (Durable Object) + OAuthProvider entry point
│ ├── env.d.ts # Environment type declarations
│ ├── auth/
│ │ ├── access-handler.ts # OAuth /authorize + /callback flow with Cloudflare Access
│ │ └── workers-oauth-utils.ts # CSRF, PKCE, state management, token exchange
│ ├── db/
│ │ ├── pg-client.ts # PostgreSQL client wrapper (Hyperdrive connection pooling)
│ │ ├── sql-parser.ts # SQL classification and safety validation
│ │ └── schemas.ts # Zod schemas for all tool inputs and database types
│ ├── tools/
│ │ ├── universal.ts # 3 tools — userInfo, connectionInfo, healthCheck
│ │ ├── readonly.ts # 7 tools — listTables, describeTable, executeQuery, ...
│ │ ├── readwrite.ts # 5 tools — insertRows, updateRows, deleteRows, ...
│ │ └── admin.ts # 10 tools — databaseHealth, createIndex, executeDDL, ...
│ ├── prompts/
│ │ ├── query-assistant.ts # Natural language to SQL with live schema context
│ │ └── schema-explorer.ts # Guided database exploration
│ └── resources/
│ ├── schema.ts # schema://tables — full schema dump
│ └── health.ts # health://overview — database health dashboard
├── tests/
│ └── sql-parser.test.ts # 48 unit tests for SQL safety parser
├── .dev.vars.example # Template for environment secrets
├── wrangler.jsonc.example # Template for Worker configuration (copy to wrangler.jsonc)
├── tsconfig.json # TypeScript configuration
└── package.json # Dependencies and scripts
Tech Stack
- Runtime: Cloudflare Workers + Durable Objects
- MCP SDK: Agents SDK (
McpAgent) +@modelcontextprotocol/sdk - Authentication:
@cloudflare/workers-oauth-provider+ Cloudflare Access (Generic OIDC SaaS) - Database: Hyperdrive +
pgdriver - Validation: Zod v4
- Testing: Vitest
- Linting/Formatting: oxlint + oxfmt
Related Documentation
- Model Context Protocol
- Building Remote MCP Servers on Cloudflare
- Cloudflare Hyperdrive — Connect to PostgreSQL
- Cloudflare Access — SaaS Applications
- Cloudflare Tunnel — Private Networks
License
MIT
Recommended Servers
playwright-mcp
A Model Context Protocol server that enables LLMs to interact with web pages through structured accessibility snapshots without requiring vision models or screenshots.
Magic Component Platform (MCP)
An AI-powered tool that generates modern UI components from natural language descriptions, integrating with popular IDEs to streamline UI development workflow.
Audiense Insights MCP Server
Enables interaction with Audiense Insights accounts via the Model Context Protocol, facilitating the extraction and analysis of marketing insights and audience data including demographics, behavior, and influencer engagement.
VeyraX MCP
Single MCP tool to connect all your favorite tools: Gmail, Calendar and 40 more.
graphlit-mcp-server
The Model Context Protocol (MCP) Server enables integration between MCP clients and the Graphlit service. Ingest anything from Slack to Gmail to podcast feeds, in addition to web crawling, into a Graphlit project - and then retrieve relevant contents from the MCP client.
Kagi MCP Server
An MCP server that integrates Kagi search capabilities with Claude AI, enabling Claude to perform real-time web searches when answering questions that require up-to-date information.
E2B
Using MCP to run code via e2b.
Neon Database
MCP server for interacting with Neon Management API and databases
Exa Search
A Model Context Protocol (MCP) server lets AI assistants like Claude use the Exa AI Search API for web searches. This setup allows AI models to get real-time web information in a safe and controlled way.
Qdrant Server
This repository is an example of how to create a MCP server for Qdrant, a vector search engine.