内容
# postgres-mcp — 从 AI 助手与 PostgreSQL 数据库对话
[](https://github.com/gupta-akshay/postgres-mcp/actions/workflows/ci.yml)
[](LICENSE)
[](https://go.dev)
[](https://github.com/gupta-akshay/postgres-mcp/actions/workflows/ci.yml)
[](https://github.com/gupta-akshay/postgres-mcp/stargazers)
[](https://github.com/gupta-akshay/postgres-mcp/graphs/contributors)
在编辑器和 SQL 客户端之间切换上下文。 **postgres-mcp** 是一个 [模型上下文协议(MCP)](https://modelcontextprotocol.io) 服务器,为 Claude Code 和 Cursor 提供直接、实时的 PostgreSQL 数据库访问功能。这样,您可以在不离开对话的情况下分析慢查询、探索模式、模拟索引和检查数据库健康状况。
> [crystaldba/postgres-mcp](https://github.com/crystaldba/postgres-mcp) 的 Go 重实现。纯 Go,无 Python,无 CGo。作为 Alpine 上的 ~15 MB 静态二进制文件发布。
---
## 您可以使用
连接后,您的 AI 助手成为 PostgreSQL 高级用户。只需询问:
```
"显示我当前 10 个最慢的查询"
"对这个查询运行 EXPLAIN ANALYZE 并告诉我为什么它很慢"
"orders 表上存在哪些索引?"
"模拟在 orders(status, user_id) 上添加索引 - 它会有帮助吗?"
"根据实际查询规划器成本,为这组查询推荐索引"
"分析整个数据库健康状况 - 任何 vacuum、sequence 或 connection 问题?"
"列出 public 模式中的所有表及其大小"
"检查是否存在无效或重复的索引"
```
无需复制粘贴。无需切换标签。无需过时的模式猜测 - 助手读取您的实际实时模式。
---
## 工作原理
postgres-mcp 通过 MCP 协议公开了九种工具。您的 AI 助手像调用函数一样调用它们;您在对话中获得结构化的 JSON 结果。
| 工具 | 功能 |
| ---- | ------------ |
| `list_schemas` | 列出所有非系统模式及其所有者 |
| `list_objects` | 列出模式中的表、视图和序列 |
| `get_object_details` | 表的列、索引、约束和行估计 |
| `explain_query` | EXPLAIN(ANALYZE)查询;可选地通过 HypoPG 模拟假设索引 |
| `execute_sql` | 运行任意 SQL(在限制模式下为只读) |
| `get_top_queries` | 来自 `pg_stat_statements` 的最慢/最占用资源的查询 |
| `analyze_workload_indexes` | 根据 `pg_stat_statements` 中的实际查询工作负载推荐索引 |
| `analyze_query_indexes` | 为显式 SQL 查询列表推荐索引 |
| `analyze_db_health` | 健康检查:索引有效性、连接、vacuum/XID、序列、复制、缓冲区缓存、约束 |
突出功能是 **假设索引模拟** (通过 `hypopg`)和 **DTA 贪婪索引顾问**:您可以在创建索引之前测试索引是否 действительно 有助于查询规划器,或者让顾问分析您的工作负载并告诉您要添加哪些索引。
---
## 先决条件
- **Docker** (推荐)- 或 Go 1.26.4+ 从源代码构建
- **PostgreSQL** 在本地运行(Postgres.app、Homebrew 或 Docker)
- **Claude Code** 和/或 **Cursor**
两个 PostgreSQL 扩展是可选的,但可以解锁最有用的功能:
| 扩展 | 解锁功能 |
| --------- | --------------- |
| `pg_stat_statements` | `get_top_queries` 和 `analyze_workload_indexes` |
| `hypopg` | `explain_query` 和两个 `analyze_*_indexes` 工具中的假设索引模拟 |
[跳转到扩展设置 →](#postgresql-extensions-setup)
---
## 快速入门
### 1. 构建 Docker 镜像
```bash
git clone https://github.com/gupta-akshay/postgres-mcp.git
cd postgres-mcp
docker build -t postgres-mcp:latest .
```
这就是整个安装过程。无需 Python 环境,无需系统库,无需版本冲突。
---
### 2. 连接到 Claude Code(stdio - 推荐)
使用 `claude` CLI 注册。这会写入 `~/.claude.json` - MCP 服务器的正确位置(`~/.claude/settings.json` 不会读取 MCP 配置):
```bash
claude mcp add-json postgres '{
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "DATABASE_URI",
"-e", "ACCESS_MODE",
"--add-host=host.docker.internal:host-gateway",
"postgres-mcp:latest"
],
"env": {
"DATABASE_URI": "postgresql://username:password@host.docker.internal:5432/dbname",
"ACCESS_MODE": "unrestricted"
}
}' --scope user
```
验证它是否已连接:
```bash
claude mcp list # postgres: ... ✓ 已连接
claude mcp get postgres
```
> **重启 Claude Code** 在添加后 - MCP 服务器仅在启动时加载。
> **macOS 注意:** Docker Desktop 自动映射 `host.docker.internal`。您不需要在 Mac 上使用 `--add-host`;为 Linux 兼容性保留它。
> **团队设置:** 在存储库根目录提交一个 `.mcp.json`,具有相同的 `{ "mcpServers": { "postgres": { ... } } }` 形状,团队成员将自动获得它。
---
### 3. 连接到 Cursor
编辑 `~/.cursor/mcp.json`(全局),`.cursor/mcp.json`(项目),或转到命令面板 → **Cursor 设置 → MCP 选项卡**:
```json
{
"mcpServers": {
"postgres": {
"command": "docker",
"args": [
"run", "-i", "--rm",
"-e", "DATABASE_URI",
"-e", "ACCESS_MODE",
"--add-host=host.docker.internal:host-gateway",
"postgres-mcp:latest"
],
"env": {
"DATABASE_URI": "postgresql://username:password@host.docker.internal:5432/dbname",
"ACCESS_MODE": "unrestricted"
}
}
}
}
```
---
## 使用 Docker Compose 保持运行(SSE 模式)
默认的 stdio 传输方式为每个会话启动一个新的容器。如果您希望在后台保持一个持久的服务器运行,请使用 SSE 模式:
```bash
# 复制并填写凭证
cp .env.example .env # 设置 DATABASE_URI 和 ACCESS_MODE
# 启动服务器
docker-compose up -d
# 确认它是否健康
docker-compose ps
```
服务器监听在 `http://localhost:8000/sse`。
**Claude Code** (`~/.claude/settings.json`):
```json
{
"mcpServers": {
"postgres": {
"url": "http://localhost:8000/sse"
}
}
}
```
**Cursor** (`~/.cursor/mcp.json`):
```json
{
"mcpServers": {
"postgres": {
"url": "http://localhost:8000/sse"
}
}
}
```
---
## 访问模式
postgres-mcp 支持两种访问模式,因此您可以安全地将其连接到您不完全拥有的数据库:
| 模式 | 用例 | 允许操作 |
| ---- | -------- | -------------- |
| `unrestricted` | 本地开发 | 完全读写,DDL,DML |
| `restricted` | 共享/生产数据库 | 只读;在 PostgreSQL 事务级别强制执行 |
通过 `--access-mode` 标志或 `ACCESS_MODE` 环境变量设置。在限制模式下,`EXPLAIN ANALYZE` 也会静默降级为 `EXPLAIN`(因为 ANALYZE 实际上执行查询)。
---
## PostgreSQL 扩展设置
### Postgres.app(macOS)
`pg_stat_statements` 已捆绑。`hypopg` 必须从源代码构建:
```bash
export PATH="/Applications/Postgres.app/Contents/Versions/17/bin:$PATH"
xcode-select --install # 如果尚未安装
git clone https://github.com/HypoPG/hypopg.git
cd hypopg && make && make install
```
启用 `pg_stat_statements`(需要重启服务器):
1. 查找 `postgresql.conf`:
```sql
SHOW config_file;
```
2. 添加到 `shared_preload_libraries`:
```
shared_preload_libraries = 'pg_stat_statements'
```
3. 重启 Postgres.app(退出并重新打开,或通过 CLI):
```bash
pg_ctl restart -D "/Users/$USER/Library/Application Support/Postgres/var-17"
```
4. 创建两个扩展:
```sql
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS hypopg;
```
---
### Homebrew Postgres(macOS)
```bash
brew install hypopg
```
启用 `pg_stat_statements`(需要重启服务器):
1. 查找 `postgresql.conf`:
```sql
SHOW config_file;
```
2. 添加到 `shared_preload_libraries`(如果有其他条目,请用逗号分隔):
```
shared_preload_libraries = 'pg_stat_statements'
```
3. 重启:
```bash
brew services restart postgresql@17 # 调整版本
```
4. 创建两个扩展:
```sql
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS hypopg;
```
---
### 云托管 Postgres(RDS,Cloud SQL,Supabase)
两个扩展都预先安装。只需启用它们:
```sql
CREATE EXTENSION IF NOT EXISTS pg_stat_statements;
CREATE EXTENSION IF NOT EXISTS hypopg;
```
---
## 从源代码构建
无需 Docker - 二进制文件没有任何 CGo 和系统依赖项:
```bash
go build -o postgres-mcp .
# 使用位置 URI 运行
./postgres-mcp "postgresql://user:pass@localhost:5432/mydb" --access-mode unrestricted
# 或使用环境变量
DATABASE_URI="postgresql://user:pass@localhost:5432/mydb" \
ACCESS_MODE=unrestricted \
./postgres-mcp
```
需要 Go 1.26.4+。
---
## 测试
测试套件有三个层次 - 您可以运行快速层或整个堆栈:
### 快速:单元测试(无需数据库)
```bash
go test ./...
# 或
make test-unit
```
单元测试涵盖所有子包业务逻辑,对 `MockQuerier` 和每个 MCP 处理程序通过进程内 MCP 客户端。
### 完整:集成 + 端到端测试
```bash
make test-integration # 启动 Docker Postgres,运行所有测试
make coverage # 相同,加上覆盖率报告(CI 门控:≥ 95%)
```
或指向您已经拥有的任何实时 Postgres:
```bash
export TEST_DATABASE_URL="postgresql://postgres:test@localhost:5433/postgres_mcp_test?sslmode=disable"
go test -tags integration ./... -coverprofile=coverage.out
go tool cover -html=coverage.out
```
集成测试会访问一个真正的 `db.Driver` - 连接模式、限制模式写入阻止、JSON 列解码。端到端测试(`internal/server/e2e_integration_test.go`)通过真实协议调用所有九个 MCP 工具,对一个安装了两个扩展的实时 Postgres 进行。
### 可丢弃的测试数据库
`make test-db-up` 在端口 **5433** 上启动一个预配置的 Postgres 17 镜像(内置 `pg_stat_statements` + `hypopg`)- 它不会与主机本地 Postgres 冲突到 5432。
```bash
make test-db-up # 启动
make test-db-down # 停止并删除卷
```
覆盖率目前为 **~97.5%**。CI 阻止合并覆盖率低于 95%。
---
## 项目结构
```
postgres-mcp/
├── main.go
├── cmd/root.go — CLI 入口点(cobra),标志 + 环境变量连接
├── Dockerfile — 运行时镜像(Alpine 上的 ~15 MB 静态二进制文件)
├── Dockerfile.test-postgres — 测试的 PG17 + pg_stat_statements + hypopg
├── docker-compose.yml — 生产 SSE 部署
├── docker-compose.test.yml — 可丢弃的测试数据库
├── Makefile — 测试 / 覆盖率 / lint 目标
├── .github/workflows/ci.yml — 完整套件在 CI 中,≥ 95% 覆盖率门控
├── test/init.sql — 测试 DB 的扩展引导
└── internal/
├── config/ — 配置结构 + IsRestricted()
├── db/ — pgxpool 驱动程序,Querier 接口,扩展检查
├── dbtest/ — MockQuerier 测试替身(跨包共享)
├── schema/ — list_schemas, list_objects, get_object_details
├── explain/ — EXPLAIN 计划 + HypoPG 假设索引模拟
├── topqueries/ — pg_stat_statements 排名(PG12/13+ 版本感知)
├── health/ — 协调器 + 7 个并行健康检查模块
├── index/ — DTA 贪婪算法 + 类型
└── server/ — MCP 服务器引导,工具注册,端到端测试
```
有关架构和调试技巧的深入了解,请参阅 **[代码库指南](docs/CODEBASE.md)**。
---
## 故障排除
**`"pg_stat_statements 扩展未安装"`**
`pg_stat_statements` 需要 `shared_preload_libraries` - 仅 `CREATE EXTENSION` 不够。按照上述 [扩展设置](#postgresql-extensions-setup),重启 Postgres,然后运行 `CREATE EXTENSION`。
**`"hypopg 扩展未安装"`**
在 psql 中运行 `CREATE EXTENSION IF NOT EXISTS hypopg;`。如果服务器上扩展不可用,请先安装软件包([上述设置说明](#postgresql-extensions-setup))。
**Docker 中 `"dial tcp: connect: connection refused"`**
在 `DATABASE_URI` 中使用 `host.docker.internal` 代替 `localhost`。在 Linux 上,还要为 `docker run` 传递 `--add-host=host.docker.internal:host-gateway`。
**Claude Code 看不到服务器**
MCP 服务器仅在启动时加载。在更改 `~/.claude.json` 后重启 Claude Code。
**`"在限制模式下不允许写入操作"`**
设置 `ACCESS_MODE=unrestricted`(或 `--access-mode unrestricted`)用于本地开发。