关于 PostgreSQL MCP Server
PostgreSQL MCP Server 为 Claude Code、Cursor 等客户端提供数据库查询、结构检查和性能诊断。它默认限制写入,可通过 PostgreSQL 角色和可选写入开关控制权限,并包含索引建议工具。
主要功能
- 01执行 SQL 查询并支持参数绑定
- 02检查模式、表、列与权限
- 03查看执行计划和数据库健康信息
- 04诊断查询、索引、锁与复制状态
- 05基于假设索引评估索引建议
适用场景
- 01通过自然语言协助检查数据库数据
- 02了解表结构及角色权限
- 03排查慢查询、锁等待或膨胀表
- 04评估查询工作负载的索引候选
MCP 相关
该 MCP 服务向客户端暴露 PostgreSQL 查询、结构检查、解释计划和诊断工具。查询默认在只读事务中执行,并可选择启用写入;工具还提供结构化输出。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
23收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| sql | string | 是 | 要执行的 SQL 语句。上限为 1 MB。 |
| params | array | 否 | 在 SQL 中以 $1、$2、... 引用的位置参数。 |
详细介绍
@yawlabs/postgres-mcp
点击一次即可将其添加到本地 Yaw MCP 配置,以便在每个 Yaw Terminal 会话中使用。也可以按下文手动安装。
可通过 Claude Code、Cursor 和任何 MCP 客户端查询 PostgreSQL 数据库。 默认只读——只需设置一个环境变量即可启用写入——这样 Agent 就无法悄悄删除你的表。
由 Yaw Labs 构建和维护。
0.12 版新增内容
索引顾问、可选审计日志、结构化工具输出,以及对当前修订版 MCP 客户端的支持。详情请参阅 CHANGELOG。
pg_index_advisor可针对工作负载推荐索引,并只保留能显著降低预估成本的索引。候选索引使用 HypoPG 假设索引进行成本估算,不会在磁盘上创建索引;搜索也会考虑到 PostgreSQL 18 的跳跃扫描会改变哪些多列索引有用。- 可选的审计日志会记录 SQL 工具发送的语句:每条经过审计的语句输出一行 JSON,可写入 stderr 或文件。不会记录绑定参数的值。默认关闭,且并非完整记录——请参阅审计日志。
- 结构化工具输出。 每个工具都声明了
outputSchema,并在保持文本块不变的同时返回structuredContent,因此目前读取文本的程序仍可正常工作。 - 支持 MCP 协议的两个时代。 此前,服务只支持旧版(2025)协议修订版,而使用当前 2026-07-28 修订版的客户端无法与之通信。现在服务同时支持两者。
正在使用 0.12.0?请升级。 0.12.1 修复了 pg_index_advisor 中的多语句查询漏洞:传入其 statements 参数的 SQL 会在接受单个字符串包含多条命令的协议上执行,因此 SELECT 1; COMMIT; DROP SCHEMA public CASCADE; 能逃出只读事务。该工具标记为只读,因此宿主通常会自动允许它。同一版本还修复了 pg_inspect_locks 将其他数据库中的锁错误归因于本地共享相同 OID 的表的问题,修正了顾问的贪心搜索,并让审计日志行补上了缺失的 tool 字段。
从 0.10.x 升级? 0.11.0 包含三项不兼容变更:pg_seq_scan_tables、pg_unused_indexes 和 pg_top_queries 返回一个封装对象(原先读取 data 的地方现在应读取 data.rows);pg_explain 在 analyze: true 时会输出 BUFFERS(传入 buffers: false 可恢复旧版输出);并且最低要求为 Node 22。详情请参阅 0.11.0 更新日志条目。
背景
Anthropic 的 Postgres MCP 参考服务 @modelcontextprotocol/server-postgres 已于 2025 年 5 月归档,并于 2025 年 7 月在 npm 上标记为弃用。Anthropic 尚未推出替代产品。尽管已弃用,最后发布的版本(v0.6.2)每周仍被拉取约 20,000 次——许多 Agent 仍在使用一个无人维护的包。
这个无人维护的包还存在一个已知且有公开文档记录的堆叠查询 SQL 注入漏洞(Datadog Security Labs):攻击者可以通过 COMMIT; DROP SCHEMA public CASCADE; 这样的输入绕过其 BEGIN READ ONLY 包装。该漏洞从未在 npm 上得到修复。
社区中出现了少数几个分支,但各自只覆盖了较窄的领域:
@zeddotdev/postgres-context-server- Zed 的分支,主要是对原有方案进行安全修补。- Postgres MCP Pro(Crystal DBA)- 专注于索引调优以及假设索引 / 缓冲区缓存诊断。
- AWS Labs Postgres MCP - 与 Aurora / RDS Data API 和 Secrets Manager 绑定。
它们都没有定位为可日常使用的通用工具,让你可以将它交给 Claude Code 或 Cursor,用于连接任意 Postgres,并开箱即用地提供现代化内省、性能辅助、角色 / 权限感知和写入安全机制。这正是 @yawlabs/postgres-mcp 要填补的空白。
为什么选择它?
- 默认只读,并提供始终只读的工具 -
pg_query会在BEGIN READ ONLY事务中运行用户 SQL,因此由 postgres 本身(而非字符串解析)阻止写入;设置ALLOW_WRITES=1可选择启用写入。pg_readonly是一个独立工具,无论ALLOW_WRITES如何设置,它始终保持只读,因此会单独控制工具权限的宿主(Claude Code 权限、mcp.hosting)可以自动允许它——但应配合权限最小化的角色使用,因为READ ONLY限制的是对数据库的写入,而非所有副作用(详情)。 - 以基于角色的访问控制为主要防护措施 - 建议的做法是在
DATABASE_URL中使用权限最小化的 postgres 角色(例如,拥有GRANT pg_read_all_data权限的角色);这样 postgres 本身就会强制执行访问边界,无需环境变量。请参阅配置访问权限。 - 所有用户 SQL 均使用扩展查询协议 -
pg_query使用queryMode: 'extended'发送用户输入,这会将每个请求限制为单条语句。这杜绝了堆叠查询注入这一类攻击(COMMIT; DROP SCHEMA x CASCADE;),此类攻击曾绕过参考服务的BEGIN READ ONLY包装器。集成测试会断言此类请求被拒绝。 - 参数化查询 -
pg_query接受用于$1、$2等占位符的params数组。我们的代码路径中不会使用字符串插值构造 SQL。 - 从头编写,积极维护 - 并非已弃用代码的分支。单元测试和集成测试(
npm test、npm run test:integration)均针对真实的 Postgres 运行;通过release.sh发布版本。 - 内置架构检查 -
pg_list_schemas、pg_list_tables、pg_describe_table会返回列、主键、外键和索引,Agent 无需记住pg_catalog联接方式。 - 将
EXPLAIN作为一等工具 - 支持文本或 JSON 格式,也可选择使用ANALYZE。对于非 SELECT 语句,使用 ANALYZE 需要设置ALLOW_WRITES=1,且始终会回滚,因此执行计划是真实的,但写入的行不会持久化。(Postgres 无法回滚的内容仍会保留:语句推进的序列会保持推进后的状态。) - 已弃用的服务从未提供的性能诊断功能 -
pg_top_queries(基于pg_stat_statements)、pg_seq_scan_tables、pg_unused_indexes、pg_table_bloat、pg_inspect_locks、pg_replication_status。一次工具调用即可回答“为什么这么慢?”。 - 健康状态快照 -
pg_health一次调用即可返回版本、数据库大小、连接数和运行时间最长的 10 条活动查询。 - 角色和权限感知 -
pg_list_roles和pg_table_privileges可用于解答常见的“谁能操作什么?”问题。 - 即时启动 - 以单个打包文件形式提供,运行时零依赖。每次
npx冷启动都无需花几分钟安装node_modules。 - 结果截断 - 大型结果集会限制在
POSTGRES_MAX_ROWS(默认值为 1000),并附带truncated: true标志,避免意外执行SELECT * FROM events导致模型上下文溢出。
快速开始
1. 在项目根目录创建 .mcp.json
macOS / Linux / WSL:
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@yawlabs/postgres-mcp@latest"],
"env": {
"DATABASE_URL": "postgres://user:password@host:5432/dbname"
}
}
}
}
Windows:
{
"mcpServers": {
"postgres": {
"command": "cmd",
"args": ["/c", "npx", "-y", "@yawlabs/postgres-mcp@latest"],
"env": {
"DATABASE_URL": "postgres://user:password@host:5432/dbname"
}
}
}
}
为什么 Windows 需要额外步骤? 从 Node 20 开始,
child_process.spawn无法直接执行.cmd文件(npx在 Windows 上就是这种文件)。使用cmd /c包装是标准解决方法。
2. 重启并批准
重启 Claude Code(或你的 MCP 客户端),并在出现提示时批准 postgres MCP 服务。
3.(可选)启用写入
默认情况下为只读。如果希望 Agent 能够执行 INSERT、UPDATE、DELETE 或 DDL,请在 env 块中添加 ALLOW_WRITES=1:
"env": {
"DATABASE_URL": "postgres://...",
"ALLOW_WRITES": "1"
}
最好仅在开发/测试数据库中启用此设置;对于生产环境,请关闭写入,并使用外部迁移工具。
配置访问权限
DATABASE_URL 中的角色是主要的访问控制手段。Postgres 拥有经过 30 年实践检验的权限系统;应充分利用它,而不是只依赖 ALLOW_WRITES。采用权限最小化的角色,无论配置了哪些工具或环境变量,服务器都会拒绝写入。
只读 Agent(推荐默认设置):
CREATE ROLE mcp_reader LOGIN PASSWORD 'change-me';
GRANT CONNECT ON DATABASE your_db TO mcp_reader;
GRANT USAGE ON SCHEMA public TO mcp_reader;
GRANT pg_read_all_data TO mcp_reader;
将 DATABASE_URL 指向 mcp_reader。Postgres 会拒绝所有写入、所有 DDL 和所有权限变更,无论 ALLOW_WRITES 如何设置。没有可绕过的应用层保护;数据库就是安全边界。
范围受限的写入 Agent(开发/测试或生产环境中的有限用途):
CREATE ROLE mcp_writer LOGIN PASSWORD 'change-me';
GRANT CONNECT ON DATABASE your_db TO mcp_writer;
GRANT USAGE ON SCHEMA public TO mcp_writer;
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO mcp_writer;
GRANT USAGE ON ALL SEQUENCES IN SCHEMA public TO mcp_writer;
-- DDL not granted -- the agent can change data but not schema.
设置 ALLOW_WRITES=1,以便 pg_query 执行写入,并依靠角色限制 Agent,防止其执行 DDL 或访问其他架构。
工具可明确划分为两类权限:
- 自动允许:
pg_readonly(服务端执行BEGIN READ ONLY,无条件),pg_index_advisor(只对提供给它的语句执行 EXPLAIN,从不使用 ANALYZE,并在BEGIN READ ONLY中执行),以及内省和诊断工具(pg_list_*、pg_describe_table、pg_search_columns、pg_health、pg_inspect_locks、pg_table_bloat、pg_unused_indexes、pg_seq_scan_tables、pg_top_queries、pg_io_stats、pg_replication_status、pg_advisor、pg_table_privileges)。 - 始终提示:
pg_query(设置ALLOW_WRITES=1且角色允许时会执行写入),pg_explain(analyze: true会执行语句;设置ALLOW_WRITES=1时也包括写入,但会回滚;未设置时,该工具的可执行范围与pg_readonly相同),pg_kill(会更改会话状态;需要ALLOW_WRITES=1)。
这种划分依据各工具的 readOnlyHint 注解;Claude Code 的 permissions 块和 mcp.hosting 的按工具切换开关都遵循该注解。
READ ONLY能做什么,不能做什么。BEGIN READ ONLY事务会阻止对数据库的写入——INSERT/UPDATE/DELETE、DDL、nextval/setval。但它不会阻止影响落在表数据之外的函数。SELECT pg_terminate_backend(...)、pg_cancel_backend、pg_read_file、lo_export和COPY ... TO PROGRAM都能在pg_readonly中执行完毕。这意味着,自动允许pg_readonly所能提供的能力,与pg_kill在ALLOW_WRITES=1后才开放的能力相同。它们每一个仍然都需要DATABASE_URL角色实际持有相应权限(pg_signal_backend、pg_read_server_files、超级用户权限),因此,限制此工具能力的是角色,而不是事务模式。 如果自动允许pg_readonly,请使用权限最小化的角色——参见配置访问权限。
将 ALLOW_WRITES 作为纵深防御:
ALLOW_WRITES 是一道额外的防护门。以下情况适用:
- 使用托管数据库,创建第二个角色不方便(某些 Supabase/Neon 方案)。
- 希望使用单个可写入的角色,但仍希望 MCP 服务在正常运行期间拒绝写入。
除此之外,请配置好角色,不要再依赖 ALLOW_WRITES。
Agent 可以用它做什么?
连接后,Agent 会根据你的请求自动选择工具。以下是一些使用单个工具的示例:
- “描述一下 users 表” ->
pg_describe_table-> 返回类型、列、主键、外键和索引。 - “哪些表有
user_id列?” -> 使用模式user_id调用pg_search_columns-> 一次调用即可,无需逐一遍历每张表。 - “这个查询很慢,为什么?” -> 调用
pg_explain并设置analyze: true-> 返回包含实际行数和耗时的执行计划。 - “我们运行的最慢查询是什么?” ->
pg_top_queries-> 返回pg_stat_statements中排名前 N 的查询,以及平均、总计、最短和最长耗时。 - “我们有未使用的索引吗?” ->
pg_unused_indexes-> 返回扫描次数为零或较低的非唯一、非主键索引及其大小。 - “安装了
pgvector吗?” ->pg_list_extensions-> 返回是否安装及其版本。
更大的价值在于多工具推理。以下是一些实际工作流:
- 让卡死的应用恢复运行。
pg_inspect_locks会返回被阻塞的 PID、阻塞它的 PID 以及导致问题的查询,随后pg_kill(需要设置ALLOW_WRITES=1)会取消阻塞操作。Agent 可以在一次交互中运行这两个工具——这是让“应用卡住”最快恢复到“重新运行”的途径。 - 排查页面加载缓慢。
pg_top_queries会对最糟糕的查询排序,pg_explain在设置analyze: true后会展示排名第一的查询的执行计划,pg_seq_scan_tables和pg_unused_indexes则会帮助判断应该“在这里添加索引”还是“在那里删除无用索引”。 - 值班分诊。
pg_health会检查连接状态、活动查询数量和数据库大小;pg_inspect_locks和pg_replication_status则会确认是否存在争用或复制延迟,再决定是否通知值班 DBA。
工具
| 工具 | 描述 |
|---|---|
pg_readonly | 执行 SQL 语句,且不会对持久化数据做出更改——无论 ALLOW_WRITES 的值如何,始终在 BEGIN READ ONLY 中执行。建议用于读取数据,也是临时执行 SQL 时应自动允许的工具;请搭配权限最小化的角色使用(原因)。 |
pg_query | 执行 SQL 查询。写入操作首先受 DATABASE_URL 中的角色限制,其次受 ALLOW_WRITES 限制。支持通过 params 执行参数化查询。结果字段包含 dataTypeName(例如 int4、jsonb)和 dataTypeID。 |
pg_list_schemas | 列出非系统架构。 |
pg_list_tables | 列出某个架构中的表(也可选择包含视图),并提供估算行数。支持通过 limit/offset 分页。 |
pg_describe_table | 返回关系的类型、列、主键、外键(指向其他表)、入向外键(referenced_by)、CHECK / UNIQUE / EXCLUDE 约束、索引,以及分区父表 / 子表信息。生成列和标识列会标记为 generated、identity、generation_expression,以避免 Agent 尝试写入这些列。约束包含 validated,PG18+ 还包含 enforced / has_period。 |
pg_list_views | 列出某个架构中的视图和物化视图,包括其 SQL 定义。 |
pg_list_functions | 列出某个架构中的函数、过程和聚合函数,并提供签名和返回类型。 |
pg_list_extensions | 列出已安装的扩展(pgvector、postgis、pg_stat_statements 等)及其版本。 |
pg_search_columns | 按名称模式查找所有用户架构中的列。不区分大小写,支持 SQL LIKE 通配符。 |
pg_explain | 对 SQL 语句执行 EXPLAIN 或 EXPLAIN ANALYZE。支持文本或 JSON 输出。规划器选项:buffers(默认在启用 analyze 时开启)、settings、verbose、wal、costs、timing,以及 generic_plan(PG16+,在没有参数值的情况下规划参数化查询)和 memory / serialize(PG17+)。可选的 hypothetical_indexes(需要 HypoPG 扩展)支持询问“如果有这些索引,执行计划会是什么?”,而无需在磁盘上创建索引。 |
pg_index_advisor | 为工作负载推荐索引,并先验证每个索引确实能带来收益。可接收你传入的 statements,或从 pg_stat_statements 中取排名前 N 的语句;通过规划器报告的过滤条件 / 联接键 / 排序键提取候选列(不使用 SQL 解析器——每个词元都会与实际的 pg_attribute 列清单取交集),然后使用 HypoPG 假设索引计算每个候选项的成本,只保留能显著降低估算成本的索引。通过 max_candidates / max_explains 实现贪心搜索并限制搜索范围,避免大型工作负载导致搜索失控;budget_exhausted 表示搜索已被截断。返回 CREATE INDEX(以及 CONCURRENTLY 形式)、创建前后的成本、各索引有助于优化的语句,以及估算大小。**支持 PG18:**PG18 引入了 B-tree 跳跃扫描,因此不再是前导列从未用于过滤的多列索引都毫无用处——经典的剪枝逻辑会根据服务器版本决定是否启用,而不会一概而论。需要 HypoPG;索引仅在会话期间有效,并会在每种退出路径中重置。 |
pg_health | 服务器版本、数据库大小、与 max_connections 相比的连接数、包含等待事件和事务运行时长的活动查询、pg_stat_database 汇总(死锁、临时文件、缓存命中率),以及表数量。 |
pg_top_queries | 按总执行时间 / 平均执行时间列出排名前 N 的查询。需要 pg_stat_statements 扩展。返回 stats_reset(来自 pg_stat_statements_info,其计时基准与其他统计工具不同),以及扩展 1.9+ 中的 dealloc——dealloc 非零表示条目数量超过 pg_stat_statements.max 后有条目被驱逐,因此排名基于不完整的数据集。 |
pg_seq_scan_tables | 列出顺序扫描次数较多的表——这些表可能缺少索引。会连同结果一起返回 stats_reset 时间范围,因为没有该信息,计数器就毫无意义。PG16+ 还提供 last_seq_scan / last_idx_scan。 |
pg_unused_indexes | 列出扫描次数较少的非唯一、非主键索引——这些索引可能适合删除。也会返回 stats_reset:计数器刚重置时,每个索引看起来都未使用,而这可能导致关键索引被删除。PG16+ 提供 last_idx_scan。 |
pg_io_stats | I/O 可观测性:按后端类型和上下文提供 pg_stat_io 的读取 / 写入 / 扩展 / fsync 次数、字节数和耗时(PG16+),以及正在进行的异步 I/O 句柄(来自 pg_aios)和活动的 io_method(PG18+)。 |
pg_inspect_locks | 查看当前谁在阻塞谁(被阻塞的 PID、阻塞方 PID、锁类型、查询)。 |
pg_list_roles | 列出数据库角色及其登录 / 超级用户 / 创建数据库标记和组成员身份。 |
pg_table_privileges | 查看谁对某张表或整个架构拥有 SELECT/INSERT/UPDATE/DELETE 等权限。 |
pg_table_bloat | 列出死元组比例较高的表——这些表可能需要 VACUUM。 |
pg_replication_status | 列出复制槽、已连接的副本,以及当前 WAL 位置。 |
pg_advisor | 一次调用即可汇总 DBA 检查结果:可能耗尽的序列、两种计数器的回卷风险(针对数据库和表,分别比较 age(relfrozenxid) 与 autovacuum_freeze_max_age,以及 mxid_age(relminmxid) 与 autovacuum_multixact_freeze_max_age——锁密集型工作负载可能在 xid 看起来正常时耗尽 multixact;triggered_by 会说明触发原因)、没有主键的表,以及(可配置的)已禁用 RLS 的 public 表。这是“我应该先检查什么?”的起点。 |
pg_kill | 取消正在运行的查询或终止后端连接。需要 ALLOW_WRITES=1。 |
配置
所有环境变量均从 MCP 服务的环境中读取:
| 变量 | 默认值 | 用途 |
|---|---|---|
DATABASE_URL | (必需) | PostgreSQL 连接字符串。 |
ALLOW_WRITES | 未设置 | pg_query、pg_explain 的写操作 ANALYZE,以及 pg_kill 的第二道写入门禁。设为 1 或 true,即可取消前两者的 BEGIN READ ONLY 包装,并允许运行 pg_kill。DATABASE_URL 中的角色是主要控制项——请参阅配置访问权限。不影响始终只读的 pg_readonly。 |
POSTGRES_STATEMENT_TIMEOUT_MS | 30000 | 每条语句的超时时间。 |
POSTGRES_CONNECTION_TIMEOUT_MS | 10000 | TCP 连接超时时间。如果不设置,连接到无法访问的主机时会一直挂起,直到操作系统放弃(约 2 分钟)。 |
POSTGRES_MAX_ROWS | 1000 | pg_query 返回的行数上限。 |
POSTGRES_POOL_MAX | 5 | 连接池的最大连接数。对于单线程后端(pglite-socket、PgBouncer 事务模式),设为 1。 |
POSTGRES_SSL_REJECT_UNAUTHORIZED | 未设置 | 设为 false 可跳过 TLS 证书验证(适用于使用私有 CA 证书的托管数据库)。连接仍会加密。 |
POSTGRES_APPLICATION_NAME | postgres-mcp | 在 pg_stat_activity.application_name 中报告的值,让监控数据库的人员能够识别 Agent 流量。DATABASE_URL 中的 application_name 优先级高于此项。 |
POSTGRES_AUDIT_LOG | 未设置(关闭) | 设为 1、true 或 stderr 可开启审计日志:每条经审计的语句记录一行 JSON,除非同时设置了 POSTGRES_AUDIT_LOG_FILE,否则写入 stderr。设为 0、false 或 off 表示明确关闭。值不区分大小写。任何其他值都会导致服务在启动时停止,包括空值或仅包含空白字符的值。请参阅审计日志记录。 |
POSTGRES_AUDIT_LOG_FILE | 未设置 | 将审计日志行追加到此文件,而不是写入 stderr。单独设置此项也会开启审计。如果值为空、文件无法打开,或 POSTGRES_AUDIT_LOG 明确设为关闭,服务将拒绝启动。 |
POSTGRES_AUDIT_REDACT | 未设置(关闭) | 设为 1 或 true 时,每条语句仅记录其首个关键字及文本的 SHA-256 值,而不记录 SQL。设为 0、false 或 off 表示明确关闭:记录完整 SQL。单独设置此项不会开启审计。任何其他值都会导致服务在启动时停止,包括空值或仅包含空白字符的值,即使审计已关闭也一样。 |
POSTGRES_MCP_RUNTIME | auto | 执行服务的 JS 运行时:auto(使用最新的 oam,版本为 0.18.0 或更高;否则使用 Node)、oam(同上,但若不可用则报错退出,而不回退到 Node)、node(始终使用 Node——通过 oam run 启动,并将执行交给 PATH 中的 Node;启用 POSTGRES_MCP_SANDBOX 时会拒绝此选项)。值不区分大小写;任何其他值均按 auto 处理。请参阅运行时。 |
OAM_BIN | 未设置 | 指定优先于自动发现使用的 oam 二进制文件路径,版本须为 0.18.0 或更高。如果文件不存在、版本较旧或无法运行,启动器会在 stderr 输出提示,然后继续自动发现。 |
POSTGRES_MCP_SANDBOX | 未设置(关闭) | 设为 1 或 true 时,在 oam 的 --permission 沙箱下运行服务:禁止文件系统和子进程访问,并将网络访问限制为 pg 驱动连接的单个主机和端口——优先取自 DATABASE_URL(其中的 host= 和 port= 参数优先),其次取自 PGHOST/PGPORT,否则使用驱动自身顺序中的 localhost:5432。设为 0、false 或 off 表示明确关闭。值不区分大小写。任何其他值都会导致启动器在启动时停止,包括空值或仅包含空白字符的值:这通常是因为存在类似 "POSTGRES_MCP_SANDBOX": "${SANDBOX}" 的 env 条目,而 MCP 客户端运行环境中未设置该变量;若将其视为未设置,服务就会在无沙箱的情况下运行。只有完全未设置的变量才视为未设置。沙箱不会悄然自行关闭:如果无法应用沙箱——POSTGRES_MCP_RUNTIME=node、没有可用的 oam 0.18.0 或更高版本、oam 启动失败,或数据库端点无法限定为单个 TCP 主机和端口(Unix 套接字、多个主机、端口不在 1-65535 范围内、主机不是纯 DNS 名称或 IP 地址,或 DATABASE_URL 不是可读取的 postgres:// URL)——启动器会退出并说明如何修复。未设置 DATABASE_URL 时,服务不会获得任何网络访问权限,其工具会报告缺少此变量。根据 oam 的变更日志,直到 0.9.1 版本,--permission 才覆盖所有 fs 和 child_process 操作;直到 0.15.0 版本,端口授权才是精确的。oam 不会限制 DNS 查询。沙箱会从其环境中移除继承的 NODE_OPTIONS 中的 --permission 或 --allow-* 标志:oam 会从该环境中获取命令行未指定的所有权限标志,因此若有标志留在其中,就会扩大授权范围。沙箱下无法打开文件审计目标;请使用 stderr 目标。请参阅故障排除。 |
支持的 PostgreSQL 版本
集成测试矩阵已在 PostgreSQL 15、17 和 18 上测试。
支持 PG13 及更高版本,但请注意上游支持的实际情况:PG13 已于 2025-11-13 结束生命周期,PG14 将于 2026-11-12 结束生命周期。 本项目不会测试 PG13/14,今后也不会将其作为兼容目标。PG12 及更早版本则已更早停止支持,且部分工具依赖于 PG13 才引入的列(pg_replication_status 读取 wal_status,pg_top_queries 读取 *_exec_time)。
较新的服务端版本会解锁额外字段,而非必需条件。所有依赖版本的列都会根据 server_version_num 进行判断,在不支持这些列的服务端上直接省略,因此不会报错——返回结果只是稍少一些。相关版本节点如下:
| 服务端 | 新增内容 |
|---|---|
| PG16+ | 统计工具中的 last_idx_scan / last_seq_scan(用于判断索引/表是否陈旧,而非仅提供计数器),pg_explain 中的 generic_plan |
| PG17+ | pg_explain 中的 memory 和 serialize |
| PG18+ | 生成列类型(stored 或 virtual)、NOT NULL 约束有效性、pg_describe_table 中的 conenforced / conperiod 约束元数据、pg_advisor 中的 relallfrozen 冻结覆盖率。在服务端使用 EXPLAIN ANALYZE 时,默认启用 BUFFERS |
如果版本探测失败,服务端会采用最旧的受支持结构,而不会生成可能被服务端拒绝的 SQL。
运行时
发布的 postgres-mcp 命令是一个小型启动器,会优先使用能找到的最新 oam 运行时,找不到时则回退到 Node。
如果你没有 oam,一切照旧——除非启用了 POSTGRES_MCP_SANDBOX;该模式需要 oam,如果找不到 oam,启动器会显示消息并停止。回退操作不会重新执行进程:npm 已经启动 Node 来运行启动器,因此回退时会在同一进程中直接 import() 服务。它只会产生少量 existsSync 调用,不会启动子进程,行为与直接在 Node 下运行 dist/index.js 完全相同。
使用哪个 oam。 只使用 oam 0.18.0 或更高版本——也就是最新版本。启动器会在已安装的位置(如果设置了 $OAM_INSTALL_DIR,则先查找该目录;然后在 Windows 上查找 %LOCALAPPDATA%\oam\bin 和 ~/.oam/bin,其他平台上查找 ~/.oam/bin)以及 PATH 中查找 oam,向找到的每个 oam 查询版本,并运行最新版本;若版本相同,则优先使用已安装的副本。较旧的 oam 会被跳过。在 Windows 上,只有 oam.exe 符合要求;绝不会运行 oam.cmd / oam.bat 垫片。只有在找不到可用的 oam 时,才会仅在 stderr 中列出被跳过的二进制文件和任何垫片;运行较新的 oam 时,不会输出相关信息。此时打印的修复建议会根据找到的内容而定:对于版本过旧的 oam,建议运行 oam self-update;对于无法运行的二进制文件,建议检查该文件;只有完全找不到 oam 时,才建议从 oamjs.org 安装。只要启动器正在查找 oam,就始终会列出无法使用的 OAM_BIN,即使之后运行了更新的版本也是如此。若宿主使用 oam 0.18.0 或更高版本通过 oam run 启动命令,服务会直接在该 oam 中运行,不会再启动另一个 oam——但启用 POSTGRES_MCP_SANDBOX 时除外;该模式需要新启动一个 oam,如果无法启动,程序会报错退出。版本低于 0.18.0 的宿主 oam 不会直接运行服务:它会交由最新的可用 oam 运行;如果找不到可用版本,则在未启用沙箱时交由 PATH 中的 Node 运行;否则报错退出。
**如果你有可用的 oam,**服务会在其下运行。已验证两种运行时的行为相同:全部 23 个工具都会注册,查询返回完全相同的行和 dataTypeName 值,错误处理路径也一致。oam 提供驱动所需的所有 node: 内置模块,包括 net、tls、crypto 和 dns(SCRAM 身份验证和扩展查询协议均可正常工作)。
测得的启动耗时。 windows-arm64,1.4 MB 的 bundle,运行 postgres-mcp version(完整模块初始化),先预热所有二进制文件,取 12 次运行的平均值:
| 路径 | 启动耗时 |
|---|---|
独立二进制文件(oam compile) | 298ms |
oam run dist/index.js | 306ms |
node dist/index.js | 358ms |
| 启动器 -> Node(进程内) | 370ms |
| 启动器 -> oam(启动子进程) | 409ms |
在此环境中,oam 的启动速度比 Node 更快。启动器的开销来自启动子进程:到达 oam 之前,Node 已经启动;这一跳(约 100ms)比 oam 约 52ms 的优势还要大。因此,通过 npm bin 启动时,两者相差约 40ms,而 POSTGRES_MCP_RUNTIME=node 只是略有优势,并无明显差别。这些数据是在机器上只有一个 oam 的情况下测得的:启动器现在会对找到的每个 oam 二进制文件运行 --version,因此每多一个副本,就会多一次探测。
无论哪种方式,这都是每个 MCP 会话只需付出一次的开销,而不是每次工具调用都要付出——宿主只会启动一次服务,并让它持续运行。如果启动速度确实很重要,独立二进制文件无需经过启动器,速度也是最快的。
本 README 的早期版本报告 Node 的启动耗时约为 650-900ms、oam 约为 980-1290ms,并据此建议禁用 oam。这些数据是在冷启动、刚构建的二进制文件上测得的,反映的是 Windows 按需病毒扫描器的影响,而非任一运行时的性能。它们在数值大小和结论方向上都不正确。已在 0.9.1 中修正。
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": ["-y", "@yawlabs/postgres-mcp"],
"env": {
"DATABASE_URL": "postgres://...",
"POSTGRES_MCP_RUNTIME": "node" // opt out of oam
}
}
}
}
连接托管型 Postgres(Supabase、Neon、RDS 等)
大多数托管型数据库都要求使用 TLS,但提供的证书由 Node 的默认信任存储无法识别的私有 CA 签发。常见错误如下:
self signed certificate in certificate chainunable to get local issuer certificateunable to verify the first certificate
若要在保持流量加密的同时允许连接,请在 env 块中添加 POSTGRES_SSL_REJECT_UNAUTHORIZED=false:
"env": {
"DATABASE_URL": "postgres://user:pass@host:5432/db?sslmode=require",
"POSTGRES_SSL_REJECT_UNAUTHORIZED": "false"
}
这只会禁用证书链验证——TCP 连接仍通过 TLS 进行端到端加密。对于可以安装 CA 的生产环境,建议将证书加入 Node 信任存储(NODE_EXTRA_CA_CERTS),而不是全局禁用验证。
在 PG17+ 上减少一次往返。 Postgres 17 新增了直接 TLS 协商,可跳过 TLS 握手前的明文 SSLRequest 握手。内置驱动支持此功能,因此请在 DATABASE_URL 后追加 sslnegotiation=direct:
postgres://user:pass@host:5432/db?sslmode=require&sslnegotiation=direct
此选项需显式启用,而非默认开启,因为 PG16 或更早版本的服务端会直接拒绝连接;并且每个连接池连接只能减少一次往返——对于距离较远的托管型数据库很有价值,但在本地数据库上则无从察觉。
审计日志
默认关闭。可在 env 块中设置 POSTGRES_AUDIT_LOG=stderr,或仅设置 POSTGRES_AUDIT_LOG_FILE 来启用:
"env": {
"DATABASE_URL": "postgres://...",
"POSTGRES_AUDIT_LOG_FILE": "/var/log/postgres-mcp/audit.jsonl"
}
随后,服务端会为每条经过审计的语句写入一行 JSON。以下是从 PostgreSQL 17 捕获的两条记录——一条参数化查询,然后是一条失败的查询:
{"ts":"2026-09-12T19:26:42.587Z","tool":"pg_query","source":"user","sql":"SELECT $1::int AS n","params":1,"ms":2.827,"rows":1,"ok":true}
{"ts":"2026-09-12T19:26:42.591Z","tool":"pg_readonly","source":"user","sql":"SELECT * FROM does_not_exist_xyz","params":0,"ms":2.217,"rows":null,"ok":false,"sqlstate":"42P01"}
| 字段 | 含义 |
|---|---|
ts | 写入该行的 ISO 8601 时间,紧接在语句执行完毕之后。 |
tool | 发出该语句的 MCP 工具。仅当在工具处理程序之外调用服务端的查询函数时才会缺省,例如将其嵌入进程内时。 |
source | 对于传给 pg_query、pg_readonly 或 pg_explain 的 SQL,值为 user。其他所有情况均为 internal:服务端自身的目录查询(一次 pg_describe_table 调用会写入多行)、pg_kill 的信号调用(该语句由服务端写入;Agent 仅提供 pid),以及 pg_index_advisor 执行的每条语句——包括传入其 statements 的工作负载 SQL。按 user 筛选不会显示 Agent 提供的所有 SQL,也不会显示 pg_kill 调用;要筛选这些内容,请按 tool 筛选。通过接受 SQL 的工具发送的 SQL 形式的终止命令(SELECT pg_terminate_backend(...))会作为该工具名下的一条普通 user 行记录。 |
sql | 按发送时的内容记录语句文本。对于 pg_explain,这是组合后的语句:EXPLAIN SELECT ...,或带选项的 EXPLAIN (ANALYZE, BUFFERS) SELECT ...。 |
sqlKeyword、sqlSha256 | 启用 POSTGRES_AUDIT_REDACT 时,用这两个字段替代 sql:去掉开头的空白或 ( 后的第一段字母,并转换为大写(如果开头是其他内容,例如注释,则为 UNKNOWN);以及完整文本的十六进制 SHA-256 值。关键词是第一个单词,而非语句的效果:删除日志的 CTE 记录为 WITH,每条 pg_explain 行都记录为 EXPLAIN。 |
params | 传入的绑定参数数量。只记录数量,绝不记录参数值。 |
ms | 审计步骤的墙钟毫秒数,而非服务端执行时间。user 行的计时从取出连接开始,到语句完成为止,因此包括等待连接池提供连接、BEGIN、pg_explain 的假设索引设置,以及行数上限游标的往返时间;internal 行也可能包括等待连接池提供连接,或等待同一次调用中的其他目录查询。 |
rows | 失败时为 null。否则记录 postgres 报告的数量;如果 postgres 未报告数量,则记录返回的行数(SET 记录为 0)。受上限约束的 SELECT 最多报告 POSTGRES_MAX_ROWS + 1 行,多出的一行用于检测截断;无法使用游标的语句(EXPLAIN、SHOW、... RETURNING)即使响应被截断,也会报告完整数量。 |
ok | 语句是否执行并成功。值为 false 也涵盖因调用先行失败而从未发送语句的情况——例如连接被拒绝、BEGIN 失败,或 pg_explain 无法创建假设索引;此时该行会带有相应失败的代码。PostgreSQL 自身的日志不会记录此类语句。对于 Agent SQL,值为 true 并不表示事务已提交:后续的 COMMIT 不会被记录,因此即使提交失败,写入操作仍会显示为 true。 |
sqlstate | 仅当 ok 为 false 且错误包含代码时才会记录。通常是五个字符的 SQLSTATE,例如 42P01;但连接失败时会记录 Node 错误代码(ECONNREFUSED、ENOTFOUND)。连接超时和缺少 DATABASE_URL 时则不会记录代码。 |
任何模式下都不会记录: 绑定参数的值(只记录数量)和错误消息(只记录代码),因为 postgres 会在错误消息中原样引用触发错误的值。语句文本会按原样记录,因此请将敏感字面值作为 params 传给 pg_query、pg_readonly 或 pg_explain。pg_index_advisor 不接受 params;请改为在其 statements 中写入 $1 样式的占位符(使用 GENERIC_PLAN 进行规划,需 PostgreSQL 16+)。
严格解析取值。 如果取值不在配置表列出的可接受集合 yes、on、hash 中,服务器会在启动时停止,而不会将其视为关闭;即使审计已关闭,POSTGRES_AUDIT_REDACT 也不例外。一个悄无声息地自行禁用的审计控制,比没有审计控制更糟。系统会忽略大小写和首尾空格。变量已设置但值为空或全为空白字符时,服务器也会停止:这通常是因为存在类似 "POSTGRES_AUDIT_REDACT": "${AUDIT_REDACT}" 的 env 条目,而该变量在 MCP 客户端运行的环境中未设置(在 Windows 上,bash 或 WSL 配置文件中的变量不会传递给通过 cmd 启动的服务器);若将其视为未设置,就会记录完整 SQL。只有完全未设置的变量才视为未设置;因此,要让任一标志保持关闭,请将其从 env 块中移除,或设为 0。
文件输出目标。 仅设置 POSTGRES_AUDIT_LOG_FILE 就会启用审计;若两者同时设置,它会优先于 POSTGRES_AUDIT_LOG=stderr,且不会发出警告。与另外两个变量一样,值为空或仅含空白字符时会报错,不会视为未设置。路径必须指向一个已存在目录中的文件:如果文件不存在,会自动创建;服务器启动时会以追加模式打开,并在进程的整个生命周期内保持打开状态。请使用绝对路径;相对路径会基于 MCP 客户端启动服务器时所在的目录解析。之后如果写入失败(例如磁盘已满),查询不会因此失败:系统会向 stderr 输出一条警告,之后的行仍会继续尝试写入。
在 stderr 上, 审计行会与启动横幅和警告混在一起,因此请跳过非 JSON 行;文件输出目标中则只有审计行。绝不会使用 stdout——它是 MCP 协议通道。
脱敏会隐藏文本,不会消除猜测风险。 相同语句会生成相同哈希,因此你仍可以对其计数和关联;也正因如此,任何持有日志的人都能验证自己猜测的语句,因此,可预测查询中的短字面值可能被还原。敏感值应安全地放在绑定参数中。
在 POSTGRES_MCP_SANDBOX 下, 沙箱会禁止文件系统访问,因此文件输出目标无法打开,服务器会在启动时退出(could not be opened for append: Access to this API has been restricted)。此时请使用 POSTGRES_AUDIT_LOG=stderr;这三个审计变量都会传递到沙箱中。
审计记录不会显示的内容。
pg_kill发出了哪种信号。 每次信号都会写入一行——tool: "pg_kill"、source: "internal"、params: 1,以及sql,值为SELECT pg_cancel_backend($1) AS signaled或SELECT pg_terminate_backend($1) AS signaled——但 pid 是绑定参数,因此日志中只会记录其数量(PostgreSQL 自身的日志可以记录该值;参见本节末尾)。如果目标是此服务自身的一条语句,且信号生效,那么该语句也会写入一行自己的ok: false(取消时通常为sqlstate57014,终止时为57P01),两行之间只能通过ts配对。在通过环回 TCP 测试本地服务时,目标行通常与pg_kill行的毫秒时间戳相同,或晚一毫秒;终止一个 CPU 密集型目标最多需要几百毫秒;如果目标需要较长时间才会检查中断,则耗时可能更久。目标行通常晚于两行中的另一行,偶尔也会更早。时间接近可作为证据,但不能作为定论:语句超时也会写入57014。在POSTGRES_AUDIT_REDACT下,两种模式的sqlKeyword都是SELECT,因此要区分取消和终止,请对上面两段文本进行哈希——使用不带尾随换行符的精确文本,并在 shell 中用单引号括起来,这样$1才能保留。pg_kill信号是否生效。ok描述的是pg_kill自身的语句,不会记录它返回的signaled值。ok: true可能表示信号已发出、pid 不是一个后端(postgres 会返回false),也可能表示取消操作没有产生任何变化:postgres 在发送信号后就会返回true,而不是等信号生效后才返回;例如,处于事务中但空闲的会话会忽略该信号。ok: false且为42501表示拒绝:该角色可能无权向该后端发送信号。pg_kill自身那一行出现ok: false且为57014或57P01,表示pg_kill自身的语句被取消或终止,例如 pid 指向运行pg_kill的连接;即使该行显示ok: false,终止后该后端也已消失。因缺少ALLOW_WRITES=1而被拒绝的调用不会发送信号,也不会写入日志。- Agent SQL 周围的辅助操作(
BEGIN READ ONLY、行数上限保存点和游标、收尾的COMMIT/ROLLBACK)、dataTypeName背后的pg_type查询,以及pg_explain的hypothetical_indexes背后的hypopg_create_index/hypopg_reset调用。这些操作都不会单独写入一行。BEGIN、保存点或hypopg_create_index执行失败时,会显示在该语句自己的ok: false行中(见上文的ok);因为该语句不会被发送。pg_type查询失败时则不会显示,因为语句已经执行,查询只会为其结果添加信息。pg_index_advisor是个例外:它发送的所有内容都会记入日志,包括事务控制语句和对每条工作负载语句执行的EXPLAIN。部分工具会先运行的服务器版本探测语句SELECT current_setting('server_version_num') AS v,是一条普通的internal行:每次成功读取时写入一次,随后会在进程整个生命周期内缓存(并发执行的首次读取调用会共用结果);如果服务器无法连接,则每次探测调用都会写入,因为失败不会被缓存。 - 调用未能继续到拼接出的语句。每个工具都会把连接被拒绝记录为它原本要发送的第一条语句对应的
ok: false行,使用各自的tool,并在sqlstate中记录 Node 错误代码;连接超时时则不包含sqlstate:对于pg_query和pg_readonly,是 Agent SQL;对于pg_explain,是EXPLAIN语句本身,除非传入了版本受限选项(settings、wal、generic_plan、memory、serialize、不带analyze的buffers)或hypothetical_indexes,此时该行记录的是版本探测或 HypoPG 检查语句,而EXPLAIN只有在这些操作之后才会拼接,因此不会出现在该行中;对于pg_kill,是信号语句;对于其余工具,包括多个查询共用一个连接的工具(pg_describe_table、pg_health、pg_advisor、pg_replication_status、pg_seq_scan_tables、pg_unused_indexes、pg_io_stats),则是版本探测语句或第一条目录查询;第一个查询就是取出连接的查询。 PostgreSQL 自带的日志是完整的服务端记录:log_statement = 'all'会记录每条进入执行阶段的语句,而默认值为error的log_min_error_statement会额外记录更早阶段失败的语句。日志还会准确记录本追踪日志未包含的内容——绑定参数值和完整的错误消息。
故障排查
DATABASE_URL is not set - MCP 客户端启动服务时没有传入环境变量。尤其在 Windows 上,通过 bash / PowerShell 配置文件设置的环境变量不会传递给通过 cmd 启动的 MCP 服务。请将 DATABASE_URL 直接放入 .mcp.json 的 env 块中。
password authentication failed - 检查用户名、密码,以及用户是否拥有数据库的 CONNECT 权限。对密码中的特殊字符进行 URL 编码(@ → %40、# → %23、/ → %2F)。
SASL: SCRAM-SERVER-FIRST-MESSAGE: client password must be a string - 连接字符串中的密码为空,或 URL 解码后变成了 null。请重新检查连接字符串。
canceling statement due to statement timeout - 单个查询超出了 POSTGRES_STATEMENT_TIMEOUT_MS(默认 30 秒)。请增大该值,使用 WHERE 缩小查询范围,或添加索引。这是预期行为——设置超时是为了避免失控的查询让 Agent 一直卡住。
Write blocked: this server is in read-only mode - 你要求 Agent 通过 pg_query 写入,但未设置 ALLOW_WRITES。你可以在 .mcp.json 的 env 块中添加 ALLOW_WRITES=1,然后重启 MCP 客户端(适用于开发/测试数据库);或者,对于生产环境,更干净的做法是在 DATABASE_URL 中使用拥有 INSERT/UPDATE/DELETE 授权的角色,并保持 ALLOW_WRITES 未设置。请参阅配置访问权限。请注意,pg_readonly 始终会拒绝写入;如需写入,调用必须通过 pg_query 进行。
启动时出现 Error: [postgres-mcp] POSTGRES_AUDIT_... 或 Error: [postgres-mcp] audit log file ... could not be opened for append - 审计变量配置错误,服务会以堆栈跟踪退出,而不会自行猜测。Error: 行会说明具体情况:无法识别的值(会列出可接受的值)、已设置但为空的变量(通常是 MCP 配置中的变量未展开——请将其从 env 块中移除,或提供有效值:两个标志使用 0 或 1,文件则使用路径)、设置了文件但未启用 POSTGRES_AUDIT_LOG,或打开文件时出现的操作系统错误——ENOENT 通常表示目录不存在,而 Access to this API has been restricted 表示 POSTGRES_MCP_SANDBOX=1。请参阅审计日志。
postgres-mcp: POSTGRES_MCP_SANDBOX=... refusing to start without the sandbox - 已请求启用沙箱,但无法应用,因此启动器会停止,而不会在未启用沙箱的情况下运行服务。第一行会说明具体情况,最后一行会说明解决办法:POSTGRES_MCP_RUNTIME=node(Node 没有 --permission);没有可用的 oam 0.18.0 或更高版本(缩进的行会列出找到的内容,以及跳过每个选项的原因);oam 启动失败;或无法固定数据库端点——Unix 套接字(oam 可以连接,但沙箱只授权 TCP 主机和端口;请通过 TCP 连接,或取消设置 POSTGRES_MCP_SANDBOX)、多个主机、端口不在 1-65535 范围内、主机包含空白字符或非 ASCII 字符(请使用其 xn-- 形式),或 DATABASE_URL 不是可读取的 postgres:// URL。绝不会打印 DATABASE_URL 本身。postgres-mcp: POSTGRES_MCP_SANDBOX="..." is not a recognized value 表示值不正确:1 或 true 会启用沙箱,0、false 或 off 会关闭沙箱。
使用 PgBouncer 事务模式或 pglite-socket 时连接池耗尽 - 这些后端不支持在单个连接上并发执行查询。请在 env 块中设置 POSTGRES_POOL_MAX=1。
首次查询较慢,后续查询很快 - 这是预期行为。pg 驱动会延迟建立首次连接;后续查询会重复使用连接池。
开发
针对真实的 Postgres 运行完整测试套件(单元测试 + 集成测试):
DATABASE_URL='postgres://user:pass@host:5432/db' POSTGRES_MCP_INTEGRATION=1 npm run test:integration
集成测试套件假定使用一次性数据库——它会创建并删除 test_fixture 架构。请勿将其指向任何重要数据库。
若要针对真实的 oam 运行 POSTGRES_MCP_SANDBOX 路径,还需进行握手并通过启动器在 --permission 下执行 select 1,然后尝试连接到固定端口旁的端口,该连接必须被 ERR_ACCESS_DENIED 拒绝——请在 DATABASE_URL 旁设置 OAM_BIN。只有两者都设置时才会运行此文件,并且它绝不会写入数据:
OAM_BIN=/path/to/oam DATABASE_URL='postgres://user:pass@host:5432/db' npm run test:integration
若要同时运行破坏性测试(REVOKE / 受限角色路径),请添加 POSTGRES_MCP_DESTRUCTIVE_TESTS=1。仅可在一次性集群上运行:
DATABASE_URL='postgres://user:pass@host:5432/db' POSTGRES_MCP_INTEGRATION=1 POSTGRES_MCP_DESTRUCTIVE_TESTS=1 npm run test:integration
Windows:通过 WSL2 运行集成测试
Windows ARM64 上的原生 Postgres 不稳定(UCRT 运行时缺失、缺少 ARM64 构建)。可靠的做法是在 WSL2 下使用一次性的 Ubuntu,并在 WSL 内运行集成测试(WSL2 的 NAT 会阻止 Windows 主机访问 :5432,因此请勿尝试从 PowerShell 运行测试):
wsl --install -d Ubuntu --no-launch
# reboot, then:
wsl -d Ubuntu -u root bash -c "apt-get update && apt-get install -y nodejs npm rsync"
wsl -d Ubuntu -u root bash /mnt/c/path/to/postgres-mcp/scripts/wsl-pg-setup.sh
wsl -d Ubuntu -u root bash /mnt/c/path/to/postgres-mcp/scripts/wsl-test-matrix.sh
wsl-pg-setup.sh 会从 PGDG apt 仓库安装 PG15、PG17 和 PG18(端口由 pg_createcluster 自动分配——通常 PG17 使用 5432、PG18 使用 5433、PG15 使用 5434),将 postgres 密码设为 postgres,并在每个版本中创建 postgres_mcp_test。wsl-test-matrix.sh 会将工作树 rsync 到 /root/postgres-mcp,运行一次 npm ci,然后针对通过 pg_lsclusters 找到的每个集群运行集成测试套件。
要从 Git Bash 而非 PowerShell 运行这些脚本? 请在两个脚本调用前加上 MSYS_NO_PATHCONV=1。Git Bash 会在 wsl.exe 接收到参数之前改写 /mnt/c/...,导致脚本路径变成 C:/Users/<you>/scoop/apps/git/<ver>/mnt/c/...,随后 bash 会报错 "No such file or directory",且实际上什么也没运行。另外,请避免将任一脚本通过管道传给 tail/head——管道的退出状态取决于最后一条命令,因此即使矩阵运行失败也会报告成功。
完成后清理:wsl --unregister Ubuntu。
许可证
MIT © 2026 YawLabs
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。