pg-analytics-mcp
pg-analytics-mcp
Конфигурационный read-only Postgres MCP-сервер для Claude. Открывает схему Postgres для Claude через Streamable HTTP; схема и значения enum интроспектируются из работающей базы данных при запуске, а всё клиент-специфичное хранится в одном YAML-файле.
Спроектирован для работы за Cloudflare Access на стеке cloudflared → reverse-proxy (в комплекте идёт полный playbook по развёртыванию), но сам сервер не зависит от Cloudflare и работает где угодно.
Не зависит от клиента. Внутри server/ нет ничего, что знало бы о конкретном клиенте. Чтобы обслужить нового клиента: скопируйте репозиторий, напишите конфигурационный файл, задайте .env.
Зачем это существует
Предыдущее решение нагромождало три процесса, чтобы обойти сторонний пакет:
supergateway → enrich.py → postgres-mcp → Postgrespostgres-mcp поддерживает только stdio/SSE (Cloudflare требует Streamable HTTP), у него нет ни поверхности конфигурации, а, supergateway порождал по дочернему процессу на каждую MCP-сессию, которые никогда не завершались, — измерено 23 дочерних процесса / 15 соединений при лимите роли 20, что проявлялось как «работает около 9 вызовов, а затем всё падает, включая SELECT 1».
Этот сервер — это один процесс с одним общим пулом. Измерено: 1 процесс после 30 вызовов инструментов.
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 pooler имя пользователя обязано содержать |
| Контейнер, тег образа и имя роутера traefik |
| Публичное имя хоста; автоматически добавляется в allowlist транспортной безопасности |
| Внешняя docker-сеть, за которой следит traefik |
| Путь к клиентскому YAML внутри образа |
| Публикуемый порт на стороне хоста (по умолчанию 8000) |
config/<client>.yaml — предметная область. Не перечисляйте здесь колонки или значения enum: они интроспектируются из живой базы при запуске и поэтому не могут устареть. Пишите только то, что интроспекция не может узнать, — бизнес-смысл и ловушки.
Инструменты
Встроенные:
execute_sql(sql)— сырой SQL только для чтения. Его описание собирается при запуске из вашего авторского текста плюс сгенерированного списка схемы и enum.list_views()— все доступные для чтения объекты с колонками, количеством строк и enum.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 существует, но по умолчанию выключен: роль — это граница, а SQL-валидатор поверх неё блокирует корректные read-only конструкции без всякой выгоды — именно поэтому ограниченный режим postgres-mcp был и abandoned.
Грабли, оплаченные кровью
Ключи labels в Compose не подставляют переменные. Labels должны быть в же списке (
- "traefik...=value"), иначе вы получите роутер, буквально названный${MCP_CONTAINER_NAME}, и traefik отдаёт 404.Защита от DNS-rebinding включена по умолчанию в MCP SDK. Проброшенный
Hostза прокси должен быть разрешён;MCP_HOSTNAMEиMCP_LOCAL_PORTдобавляются автоматически.Монтирование MCP-приложения под ваше Starlette-приложение заменяет его жизненный цикл. Менеджер сессий нужно запускать явно (
server.session_manager.run()), иначе каждый запрос падает коду 500 «Task group is not initialized».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— это полный lock-файл.
Лицензия
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