mcp-pg元工具
PostgreSQL的模型上下文协议(MCP)服务器,使AI代理能够执行SQL查询并创建可重用的参数化查询工具。
特性
- 执行任意SQL 具有命名参数支持(
:param_name语法) - 保存参数化查询 作为可重用的MCP工具,在会话中持久存在
- 数据库自检 用于探索模式、表、视图及其结构的工具
- 连接池 实现高效的数据库访问
安装
npm install
npm run build配置
数据库连接
设置以下选项之一:
# Option 1: Connection URL (recommended)
export DATABASE_URL="postgresql://user:password@localhost:5432/dbname"
# Option 2: Individual variables
export PGHOST="localhost"
export PGPORT="5432"
export PGDATABASE="mydb"
export PGUSER="myuser"
export PGPASSWORD="mypassword"可选设置
# SSL mode (disable, require, verify-ca, verify-full)
export PGSSLMODE="require"
# Connection pool size (default: 10)
export PG_POOL_MAX="10"
# Data directory for saved queries (default: ./data)
export MCP_PG_DATA_DIR="./data"
# Disable core tools: "none" (default), "management", or "all"
export DISABLE_CORE_TOOLS="none"安全功能
两个选择加入控件,用于限制MCP服务器向代理公开的内容。 这些是深度防御,而不是主要控制。 限制代理可以做什么的权威方法是与一个专用的PostgreSQL角色连接,该角色的权限范围是适当的(例如。 GRANT SELECT ON ... TO readonly_role, GRANT SELECT (col1, col2) ON sensitive_table TO readonly_role).
# Block mutations at the tool layer. When enabled, every pooled connection
# runs `SET SESSION default_transaction_read_only = on`, so PostgreSQL itself
# rejects INSERT/UPDATE/DELETE/DDL/TRUNCATE — including writes smuggled
# inside CTEs (WITH x AS (UPDATE ...) SELECT ...).
export READONLY_MODE="true"
# Comma-separated list of sensitive columns to redact from tool responses.
# Format: schema.table.column
export FIELD_BLACKLIST="public.users.ssn,public.users.password_hash,public.payments.cc_number"
# Per-statement timeout in milliseconds. Sets `statement_timeout` on every
# pooled connection so PostgreSQL cancels any query that runs too long —
# applies to the agent's queries and to the server's own introspection lookups.
# Unset (or 0) means no timeout.
export QUERY_TIMEOUT_MS="30000"
# Auto-populate the field blacklist from the DB user's column-level GRANTs.
# At startup, runs `has_column_privilege(current_user, ...)` against every
# user-schema column and merges any denials into FIELD_BLACKLIST. Lets the
# tool-level filter track the DB ACL without maintaining two lists.
export AUTO_BLACKLIST_FROM_GRANTS="true"这 list_inaccessible_columns 该工具根据需要向代理显示相同的信息,使其能够主动选择显式的列列表,而不是点击 SELECT * 权限错误。
只读警告。 PostgreSQL的只读事务模式仍然允许 SET, SHOW、临时表和写入 *其他* 数据库通过 dblink/FDW。使用DB角色权限进行权威锁定。
黑名单行为。 对于查询返回的每一列,服务器通过以下方式解析其来源 pg_class/pg_attribute 并删除任何符合以下条件的条目 schema.table.column 与黑名单匹配。匹配的列将以某种方式报告给代理 redactedColumns 阵列。计算/混叠输出(例如。 SELECT ssn AS x FROM users)无法解析为源列并回退到按输出名称匹配;这些报告如下 unresolvedRedactions 作为尽力而为的过滤器——依赖于列级别 GRANT/REVOKE 如果这个边缘案例对你来说很重要。黑名单也会过滤 describe_table / describe_view 输出,这样敏感的列名就不会通过内省泄露。
黑名单并不能阻止侧信道探测。 过滤器只检查返回的行,不检查查询本身。代理正在运行 SELECT id FROM users WHERE ssn = '123-45-6789' 即使没有,仍然可以通过观察行数来了解SSN是否存在 ssn 列始终返回。柱级 REVOKE SELECT (ssn) 在PostgreSQL中,两个读取都被阻止 *和* 对列进行过滤/排序/连接——这是缩小这一差距的唯一方法。将工具级黑名单视为显示层安全网,而不是访问控制。
用法
运行服务器
# Development
npm run dev
# Production
npm startMCP客户端配置
添加到您的MCP客户端配置中(例如,Claude Desktop):
{
"mcpServers": {
"postgres": {
"command": "node",
"args": ["/path/to/mcp-pg-metatool/dist/index.js"],
"env": {
"DATABASE_URL": "postgresql://user:password@localhost:5432/dbname"
}
}
}
}可用工具
查询执行
| 工具 | 说明 |
|---|---|
execute_sql_query | 使用命名参数执行任意SQL查询 |
查询管理
| 工具 | 说明 |
|---|---|
save_query | 从参数化SQL查询创建可重用工具 |
list_saved_queries | 列出所有已保存的查询工具 |
show_saved_query | 查看已保存查询的完整定义 |
delete_saved_query | 删除已保存的查询工具 |
数据库反思
| 工具 | 说明 |
|---|---|
list_schemas | 列出数据库中的所有架构 |
list_tables | 列出架构中的表 |
describe_table | 显示表的列、类型和约束 |
list_views | 列出架构中的视图 |
describe_view | 显示视图列和定义 |
list_inaccessible_columns | 列出当前数据库用户缺少SELECT的列 |
示例
执行查询
Tool: execute_sql_query
Arguments:
query: "SELECT * FROM users WHERE status = :status LIMIT :limit"
params: { "status": "active", "limit": 10 }保存可重用查询
Tool: save_query
Arguments:
tool_name: "get_active_users"
description: "Get active users with optional limit"
sql_query: "SELECT id, name, email FROM users WHERE status = 'active' LIMIT :limit"
parameter_schema: {
"type": "object",
"properties": {
"limit": {
"type": "integer",
"default": 100,
"description": "Maximum number of users to return"
}
}
}保存后, get_active_users 作为一种新工具,它可以在会话中持续使用。
探索数据库结构
Tool: list_tables
Arguments:
schema_name: "public"
Tool: describe_table
Arguments:
table_name: "users"
schema_name: "public"命名参数
SQL查询使用冒号前缀的命名参数,这些参数转换为PostgreSQL的位置 $1, $2, ... 执行时的语法:
-- You write:
SELECT * FROM orders WHERE user_id = :user_id AND status = :status
-- Executed as:
SELECT * FROM orders WHERE user_id = $1 AND status = $2这避免了与PostgreSQL的冲突 :: 类型转换语法。
保存的查询格式
保存的查询以JSON文件存储在 data/tools/:
{
"name": "get_user_orders",
"description": "Get orders for a specific user",
"sql_query": "SELECT * FROM orders WHERE user_id = :user_id",
"sql_prepared": "SELECT * FROM orders WHERE user_id = $1",
"parameter_schema": {
"type": "object",
"properties": {
"user_id": { "type": "integer" }
},
"required": ["user_id"]
},
"parameter_order": ["user_id"]
}发展
# Run in development mode with hot reload
npm run dev
# Run tests
npm test
# Lint code
npm run lint
# Format code
npm run format许可证
麻省理工学院
