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
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。