Cursor + MCP 让 AI 直接操作数据库:从零到生产
适用场景
- 开发时频繁需要查表结构、跑 SQL 验证
- AI 生成代码时需要知道数据库 schema
- 想让 AI 帮写数据库迁移文件
- 调试慢查询,需要 AI 看真实执行计划
如果你只是偶尔查一次表结构,手动复制粘贴就够,不必上 MCP。MCP 的价值在"高频往返"场景——下面会算这笔账。
为什么用 MCP 而不是复制粘贴
传统做法:手动跑 \d table_name → 复制结果 → 粘给 Cursor → AI 生成 SQL → 手动执行验证 → 报错 → 再复制错误回去。
MCP 做法:Cursor 直接连数据库 → AI 自己查 schema → 生成 SQL → 自己执行验证 → 看到结果/报错 → 自己修正。
省的是中间的复制粘贴往返。在复杂查询调试时,这个往返可能 5-10 次,每次都要切窗口、复制、粘贴。MCP 把这个循环闭合在 AI 内部,你只看最终结果。
MCP 在这里到底做了什么
MCP(Model Context Protocol)是一层标准协议:MCP Server 把数据库能力(查表、执行 SQL、看执行计划)封装成标准化的"工具",Cursor 作为 MCP 客户端调用这些工具。AI 不是"直连数据库",而是"调用 MCP Server 暴露的受控工具"——这点很关键,意味着你能在 Server 这层卡住权限。协议原理见 什么是 MCP,生态选型见 MCP 生态实测。
第一步:装 MCP PostgreSQL Server
用 Smithery 一行装好:
npx @smithery/cli install @modelcontextprotocol/server-postgres --client cursor
或手动配 Cursor Settings → MCP → Add Server,编辑 .cursor/mcp.json:
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "postgresql://user:***@localhost:5432/mydb"
}
}
}
}
重启 Cursor,Agent 模式现在能查数据库了。验证:在 Agent 里问"列出所有表",能返回表名就说明连通了。
第二步:安全配置(最重要的一步)
这一步决定了 MCP 是"提效工具"还是"事故源头"。三道防线,全部要做。
防线一:用只读账号
绝对不要用超级用户账号连 MCP。创建专用只读账号:
CREATE ROLE mcp_readonly WITH LOGIN PASSWORD '***';
GRANT USAGE ON SCHEMA public TO mcp_readonly;
GRANT SELECT ON ALL TABLES IN SCHEMA public TO mcp_readonly;
-- 让未来新建的表也自动只读可见
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT ON TABLES TO mcp_readonly;
这样即使 AI 生成了 DROP TABLE,数据库层面也会直接拒绝——权限是最硬的护栏,比"在 prompt 里叮嘱 AI 别删数据"可靠一万倍。
防线二:开发/生产物理隔离
{
"mcpServers": {
"postgres-dev": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {
"DATABASE_URL": "postgresql://mcp_readonly:***@localhost:5432/mydb_dev"
}
}
}
}
只在 dev 环境配 MCP。生产数据库永远不连 MCP,连只读都不连——生产库的连接串一旦进了配置文件,就有泄露和误连风险。
防线三:敏感表用视图隔离
有些表(用户密码 hash、token、支付信息)不该让 AI 看到。用视图暴露脱敏后的子集:
CREATE SCHEMA IF NOT EXISTS public_safe;
CREATE VIEW public_safe.users_safe AS
SELECT id, username, created_at FROM public.users;
REVOKE SELECT ON public.users FROM mcp_readonly;
GRANT SELECT ON public_safe.users_safe TO mcp_readonly;
AI 能查到用户名和注册时间,但碰不到密码字段。
第三步:实战用法
场景一:查 schema 生成代码
在 Cursor Agent 模式输入:
帮我写一个查询用户订单的 API,需要分页
Cursor 会:
- 调 MCP
list_tables看有哪些表 - 调 MCP
describe_table看 orders 和 users 表结构 - 基于真实字段生成 JOIN 查询 + 分页代码
关键区别:它用的是真实 schema,不是猜的字段名。这能消掉"AI 把 user_id 写成 userId"这类幻觉。
场景二:调试慢查询
这个查询很慢,帮我优化:
SELECT * FROM orders o JOIN users u ON o.user_id = u.id WHERE o.status = 'pending'
Cursor 会:
- 跑
EXPLAIN ANALYZE看真实执行计划 - 发现
orders.status上全表扫描 - 建议加索引并解释收益
- 生成 migration 文件
它看的是真实执行计划,不是"我觉得这里可能慢"。
场景三:生成迁移
给 orders 表加一个 shipping_address 字段,类型 jsonb,可空
Cursor 会:
- 查当前 orders 表结构(确认字段不冲突)
- 生成
ALTER TABLESQL - 生成 Drizzle / Prisma migration 文件
- 生成对应的回滚 SQL
权限边界与可写 MCP
| 操作 | 只读 MCP | 可写 MCP |
|---|---|---|
| 查表结构 | ✅ | ✅ |
| SELECT 查询 | ✅ | ✅ |
| EXPLAIN | ✅ | ✅ |
| INSERT/UPDATE/DELETE | ❌ | ✅ |
| CREATE/DROP TABLE | ❌ | ⚠️ 需额外授权 |
| ALTER TABLE | ❌ | ⚠️ 需额外授权 |
建议:日常用只读 MCP,需要写操作时再切到可写 MCP。
如果一定要可写,加这两道闸
- 配两个 Server,按需切换:
postgres-ro(只读,默认用)和postgres-rw(可写,临时用)。平时不挂可写的,要写时才启用,用完关掉。 - 可写账号也别给 DDL 权限:给 INSERT/UPDATE/DELETE 就够日常用,
DROP/ALTER这类结构变更走人工执行 migration,不交给 AI 直接跑。
-- 可写但不能改结构、不能删表
CREATE ROLE mcp_readwrite WITH LOGIN PASSWORD '***';
GRANT USAGE ON SCHEMA public TO mcp_readwrite;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO mcp_readwrite;
-- 注意:故意不给 CREATE / DROP / ALTER 权限
踩坑记录
- MCP Server 默认无连接池——AI 连续查询会打满 PG 连接数。前面挂 PgBouncer 做连接池,或限制并发。
- 大表
SELECT *卡死——AI 可能跑SELECT * FROM huge_table。给只读账号设语句超时兜底:ALTER ROLE mcp_readonly SET statement_timeout = '10s'; - 不支持事务——Cursor MCP 每条 SQL 独立执行,不能
BEGIN/COMMIT包多步。需要原子性的多步操作走存储过程或应用层。 - DATABASE_URL 泄露——
.cursor/mcp.json含明文连接串,极易被 git 提交上去。务必加进.gitignore,用本地覆盖文件.cursor/mcp.local.json放真实凭据。 - AI 仍会偶尔编字段名——即便连了 MCP,长对话里它可能凭记忆写字段而不重新查。关键查询让它"先 describe_table 再写 SQL"。
延伸阅读
- Cursor 工具卡 · Smithery · Composio
- 什么是 MCP — 协议原理
- MCP 生态实测 — Smithery vs Composio vs 手搓
- Cursor MCP 深度集成 — 接更多类型的 MCP Server