pg-analytics-mcp
pg-analytics-mcp
Ein konfigurationsgesteuerter, schreibgeschützter Postgres-MCP-Server für Claude. Stellen Sie ein Postgres-Schema über Streamable HTTP für Claude bereit, wobei Schema- und Enum-Werte beim Start aus der Live-Datenbank introspiziert werden und alles Clientspezifische in einer einzigen YAML-Datei liegt.
Entworfen für den Betrieb hinter Cloudflare Access auf einem cloudflared → Reverse-Proxy-Stack (ein vollständiges Provisioning-Playbook ist enthalten), aber der Server selbst hat keine Cloudflare-Abhängigkeit und läuft überall.
Client-agnostisch. Nichts unter server/ weiß von einem bestimmten Client. Um einen neuen zu bedienen: Repo kopieren, Konfigurationsdatei schreiben, .env setzen.
Warum es das gibt
Der Vorgänger stapelte drei Prozesse, um ein Anbieterpaket zu umgehen:
supergateway → enrich.py → postgres-mcp → Postgrespostgres-mcp spricht nur stdio/SSE (Cloudflare erfordert Streamable HTTP), hat überhaupt keine Konfigurationsoberfläche, und supergateway forkte ein Kind pro MCP-Sitzung, das nie beendet wurde – gemessen 23 Kinder / 15 Verbindungen gegen ein Rollenlimit von 20, was sich als „funktioniert für ~9 Aufrufe, dann schlägt alles fehl, einschließlich SELECT 1“ äußerte.
Dieser Server ist ein Prozess mit einem gemeinsamen Pool. Gemessen: 1 Prozess nach 30 Tool-Aufrufen.
Related MCP server: Brand MCP Server
Architektur
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.* viewsDie Sicherheitsgrenze ist die Datenbankrolle, nicht dieser Server.
Schnellstart
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 bootFolgen Sie dann docs/PLAYBOOK-NEW-CLIENT.md für die Cloudflare-Seite.
Konfiguration
.env – hostspezifisch, das Einzige, was sich zwischen VPS ändert:
Variable | Zweck |
| Schreibgeschützte Rolle. Beim Supavisor-Pooler muss der Benutzername unbedingt |
| Container, Image-Tag und Traefik-Router-Name |
| Öffentlicher Hostname; wird automatisch zur Transport-Sicherheits-Allowlist hinzugefügt |
| Externes Docker-Netzwerk, das Traefik überwacht |
| Pfad zur Client-YAML im Image |
| Hostseitiger Veröffentlichungsport (Standard 8000) |
config/<client>.yaml – die Domäne. Listen Sie hier keine Spalten oder Enum-Werte auf: Sie werden beim Start aus der Live-Datenbank introspiziert, können also nicht veralten. Schreiben Sie nur, was die Introspection nicht wissen kann – geschäftliche Bedeutung und Fallstricke.
Werkzeuge
Eingebaut:
execute_sql(sql)– rohes schreibgeschütztes SQL. Seine Beschreibung wird beim Start aus Ihrem verfassten Prosa plus den generierten Schema- und Enum-Listen zusammengesetzt.list_views()– jedes lesbare Objekt mit Spalten, Zeilenzahlen, Enums.describe_view(name)– Spalten eines Objekts.
Konfigurationsdefiniert: Jeder Eintrag unter tools.queries wird zu einem echten MCP-Tool mit typisierten Parametern. Parameter binden über psycopg benannte Platzhalter – niemals String-Interpolation – und min/max werden vor dem Binden erzwungen.
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)Das ist der Teil, der die Lücke zu n8n schließt: Ein Tool hinzuzufügen ist Prosa + SQL, nicht Python.
Warum Beschreibungen hier leben
Tool-Beschreibungen sind der eine Kontext, den ein Modell immer dann sieht, wenn das Tool verfügbar ist – jeder Client, jedes Gespräch, kein Skill-Laden und keine Projektanweisungen. Domänenwissen, das in einem externen Dokument aufbewahrt wird, ist Wissen, das das Modell oft nicht hat.
Die Hälfte jeder Beschreibung ist verfasst (Urteil), die Hälfte generiert (Fakten). Die generierte Hälfte ist der Grund, warum die boxy-Plattform/Prozessor und die daily-Frequenz nicht mehr so fehlen können, wie sie es in dem handgeschriebenen Prompt taten, der diesem vorausging.
Betrieb
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 editEine Konfigurations- oder Schemaänderung erfordert einen Neustart – die Introspection wird für die Prozesslebensdauer bewusst gecacht, damit sich das Verhalten während des Laufs nicht ändern kann.
Die fünf Grenztests
Nach jeder Änderung an Views, Grants oder Konfiguration erneut ausführen. Alle fünf müssen fehlschlagen:
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 existiert, ist aber standardmäßig aus: Die Rolle ist die Grenze, und ein SQL-Validator darüber blockiert gültige schreibgeschützte Konstrukte ohne Nutzen – deshalb wurde der eingeschränkte Modus von postgres-mcp aufgegeben.
Mit Blut bezahlte Fallstricke
Compose-Label-Schlüssel werden nicht variabel substituiert. Labels müssen in Listenform vorliegen (
- "traefik...=value"), sonst erhalten Sie einen Router, der buchstäblich${MCP_CONTAINER_NAME}heißt, und Traefik 404s.DNS-Rebinding-Schutz ist standardmäßig aktiviert im MCP SDK. Der weitergeleitete
Hosthinter einem Proxy muss erlaubt sein;MCP_HOSTNAMEundMCP_LOCAL_PORTwerden automatisch hinzugefügt.Das Mounten der MCP-App unter Ihrem eigenen Starlette ersetzt dessen Lebensdauer. Der Sitzungsmanager muss explizit gestartet werden (
server.session_manager.run()), sonst antwortet jede Anfrage mit 500 und „Task group is not initialized“.set_read_only/set_autocommitmüssen jedemexecute()auf einer Verbindung vorausgehen, sonst schlägt der Pool mit „connection in transaction status INTRANS“ fehl.pg_class.reltuplesist für Views bedeutungslos, daher fallen Zeilenschätzungen beim Start auf ein begrenztescount(*)zurück.Supavisor schreibt
application_namezu „Supavisor“ um, daher ist eine pro-Client-Verbindungszuordnung durch den Pooler nicht möglich.MCP SDK 2.0 hat
FastMCPinMCPServerumbenannt und es ausmcp.server.fastmcpverschoben.requirements.txtist aus diesem Grund ein vollständiger Lock.
Lizenz
MIT – siehe 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