pg-analytics-mcp
pg-analytics-mcp
一个配置驱动、只读的 Postgres MCP 服务器,专为 Claude 设计。将 Postgres 模式通过 Streamable HTTP 暴露给 Claude,模式与枚举值 在启动时从实时数据库内省获取,所有客户端特定配置集中在一个 YAML 文件里。
专为在 Cloudflare Access 之后、运行在 cloudflared → 反向代理
架构上而设计(附带了完整的配置手册),但服务器本身不依赖 Cloudflare,可在任何地方运行。
与客户端无关。 server/ 下的任何代码都不知道任何特定客户端的存在。
要服务新客户端:复制仓库、编写配置文件、设置 .env。
为什么会有这个项目
前身方案为了绕开一个供应商包,堆叠了三个进程:
supergateway → enrich.py → postgres-mcp → Postgrespostgres-mcp 只支持 stdio/SSE(Cloudflare 要求 Streamable HTTP),
完全没有配置面,而 supergateway 为每个 MCP 会话派生一个从未回收的子进程 ——
实测 23 个子进程 / 15 个连接,而角色上限是 20,表现为"大约调用 9 次后一切失败,
连 SELECT 1 都不行"。
本服务器是一个进程,使用一个共享连接池。实测:30 次工具调用后仍是 1 个进程。
Related MCP server: Brand MCP Server
架构
Claude → portal.<zone> Cloudflare MCP Server Portal (OAuth)
→ mcp-origin.<zone> Access app + Managed OAuth
→ cloudflared tunnel
→ traefik Host-header routing
→ this container uvicorn, Streamable HTTP at /mcp
→ Postgres read-only role → analytics.* views安全边界是数据库角色,而不是这个服务器。
快速开始
cp .env.example .env # set DATABASE_URI + the deployment vars
$EDITOR config/example.yaml # domain prose for this client
docker compose up -d --build
curl -s localhost:8000/healthz # ok
curl -s localhost:8000/introspection # what the server decided at boot然后按照 docs/PLAYBOOK-NEW-CLIENT.md 处理 Cloudflare 侧。
配置
.env —— 与主机相关,是不同 VPS 之间唯一变化的部分:
变量 | 用途 |
| 只读角色。在 Supavisor 池化器上,用户名必须携带 |
| 容器、镜像标签和 traefik 路由名称 |
| 公开主机名;自动加入传输安全允许列表 |
| traefik 监听的外部 docker 网络 |
| 镜像内客户端 YAML 的路径 |
| 主机侧发布端口(默认 8000) |
config/<client>.yaml —— 领域配置。不要在此列出列或枚举值:
它们在启动时从实时数据库内省获取,因此不会过期。
只写内省无法获知的内容——业务含义与陷阱。
工具
内置工具:
execute_sql(sql)—— 原始只读 SQL。其描述在启动时由你撰写的说明 加上 生成的模式与枚举列表组装而成。list_views()—— 所有可读对象,含列、行数、枚举。describe_view(name)—— 单个对象的列。
配置定义:tools.queries 下的每个条目都会变成真正的 MCP 工具,带类型化参数。参数通过 psycopg 命名占位符绑定——绝不使用字符串插值——并且 min/max 在绑定前强制校验。
tools:
queries:
monthly_trend:
description: |
Donations per month. The most recent month is PARTIAL.
params:
months: {type: integer, default: 6, min: 1, max: 36}
sql: |
select ... where donated_at >= date_trunc('month', now())
- make_interval(months => %(months)s - 1)这正是拉近与 n8n 差距的关键:添加一个工具就是写说明文字 + SQL,而非 Python。
为什么描述放在这里
工具描述是模型在工具可用时所能看到的唯一上下文——每个客户端、每段对话都如此,无需技能加载,也无需项目说明。放在外部文档里的领域知识,往往是模型并不具备的知识。
每段描述一半是撰写的(判断),一半是生成的(事实)。生成的那一半,正是 boxy 平台和 daily 频率不会再像之前手写提示词那样丢失的原因。
运维
curl -s localhost:8000/introspection | python3 -m json.tool # objects, enums, tools, limits
docker top <container> # must stay at 1 process
docker compose up -d --build # after a config edit配置或模式变更需要重启 —— 内省结果会在进程生命周期内缓存,这是刻意为之, 这样行为就不会在运行中途漂移。
五项边界测试
在对视图、授权或配置做任何修改后重新运行。五项必须全部失败:
update donations set amount = 0 where false; -- permission denied for view
select count(*) from public.donations; -- permission denied for table
select count(*) from public.website_orders; -- permission denied for table
create table analytics.t (id int); -- read-only transaction
select phone_number from customers limit 1; -- column does not existlimits.select_only 默认关闭:角色才是边界,而受限模式会拦截合法的只读构造,却毫无收益 —— 这正是 postgres-mcp 的受限模式被放弃的原因。
血泪教训
Compose 的标签键不做变量替换。 标签必须使用列表形式 (
- "traefik...=value"),否则你会得到一个名字恰恰是${MCP_CONTAINER_NAME}的路由器,然后 traefik 返回 404。MCP SDK 默认开启 DNS 重绑定保护。 代理后转发的
Host必须被允许;MCP_HOSTNAME和MCP_LOCAL_PORT会 自动添加。将 MCP 应用挂载到你自己的 Starlette 下会覆盖生命周期。 必须显式启动会话管理器(
server.session_manager.run()),否则 每个请求都会以 "Task group is not initialized" 报 500 错误。set_read_only/set_autocommit必须在任何execute()之前调用, 否则连接池会报 "connection in transaction status INTRANS"。pg_class.reltuples对视图毫无意义,因此行数估算在启动时 回退为有界count(*)。Supavisor 会把
application_name改写成 "Supavisor",因此无法通过池化器做按客户端连接归属。MCP SDK 2.0 将
FastMCP重命名为MCPServer并移出了mcp.server.fastmcp。requirements.txt因此是完整锁定版本。
许可证
MIT —— 见 LICENSE。
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseNot gradedqualityDmaintenanceEnables Claude to interact with PostgreSQL databases by executing SQL queries, exploring schemas, and monitoring database health. It provides tools for data manipulation and schema management via a secure SSE connection.287MIT
- FlicenseNot gradedqualityDmaintenanceEnables Claude Desktop to query a PostgreSQL brand database through MCP. Supports local stdio and remote HTTP/SSE deployments with API key authentication for secure database access.
- FlicenseNot gradedqualityDmaintenanceEnables natural language querying of PostgreSQL databases through the Model Context Protocol. It translates user questions into validated SQL, executes read-only queries safely, and returns results to MCP-compatible clients like Claude Desktop.
- AlicenseAqualityAmaintenanceQuery and manage PostgreSQL databases from Claude Code, Cursor, and any MCP client, with read-only by default and built-in schema introspection, EXPLAIN, and performance diagnostics.211,8093MIT
Related MCP Connectors
Analytical memory for AI agents: a real Postgres queried in plain English over MCP. One command.
Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.
MCP server for managing Prisma Postgres.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/Sa3fa/pg-analytics-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server