. MCP Server: PostgreSQL
Tool-Lektion | 25 Minuten
Der PostgreSQL MCP Server gibt Claude Code direkten Zugriff auf deine PostgreSQL Datenbanken. Claude kann Queries ausführen, Schema analysieren, Daten einfügen/updaten und Migrationen durchführen
Lernziele
- Grundkonzepte und Architektur verstehen
- Verstehen warum dieses Tool wichtig ist
- Installation und grundlegende Nutzung beherrschen
- Production-ready Patterns anwenden
- Real-World Use Cases umsetzen
. MCP Server: PostgreSQL
🚀 Claude Code Relevanz: Der PostgreSQL MCP Server gibt Claude Code direkten Datenbank-Zugriff, sodass Schema-Analysen, Query-Optimierung und Migrationen direkt aus der Entwicklungsumgebung heraus moeglich werden.
Was ist der PostgreSQL MCP Server?
Der PostgreSQL MCP Server gibt Claude Code direkten Zugriff auf deine PostgreSQL Datenbanken. Claude kann Queries ausführen, Schema analysieren, Daten einfügen/updaten und Migrationen durchführen - alles strukturiert über MCP Tools.
Warum PostgreSQL via MCP?
Ohne MCP:
Ohne den PostgreSQL MCP Server muss Claude SQL-Queries als Shell-Befehle ueber psql ausfuehren und den Text-Output parsen. Das ist fehleranfaellig, weil das Ausgabeformat von der psql-Konfiguration abhaengt und sich bei verschiedenen PostgreSQL-Versionen unterscheiden kann. Ausserdem erhaelt Claude keine typisierten Daten -- alles kommt als String zurueck, und Claude muss raten, ob eine Spalte ein Integer, ein Datum oder ein Text ist. Bei grossen Ergebnismengen wird der Text-Output unleserlich, und bei Fehlern erhaelt Claude nur eine kryptische Fehlermeldung. Der MCP-Ansatz loest all diese Probleme.
# Claude generiert SQL + Shell-Command
psql -U user -d mydb -c "SELECT * FROM users WHERE id = 1"
→ Parse Text-Output ist fehleranfällig
Mit MCP:
Mit dem PostgreSQL MCP Server fuehrt Claude SQL-Queries direkt ueber die MCP-Schnittstelle aus und erhaelt eine strukturierte JSON-Response zurueck. Die Response enthaelt nicht nur die Ergebnis-Rows als JSON-Objekte, sondern auch Metadaten wie die Feldnamen, Datentypen und die Anzahl der betroffenen Zeilen. Claude kann diese Daten sofort weiterverarbeiten, ohne Text-Parsing betreiben zu muessen. Stell dir vor, Claude fragt die Users-Tabelle ab -- es erhaelt ein sauberes Array von Objekten mit typisierten Werten, die es direkt analysieren und praesentieren kann. Die strukturierte Fehlerbehandlung liefert bei Problemen klare, maschinenlesbare Fehlermeldungen statt kryptischer psql-Ausgaben.
{
"method": "postgres_query",
"params": {
"query": "SELECT * FROM users WHERE id = 1"
}
}
→ Strukturierte JSON-Response mit Rows & Metadata
Berechtigung
Warum brauchst du den PostgreSQL MCP Server?
- 1. Structured Queries: JSON statt Text-Parsing
- 2. Safety Checks: Verhindert destructive Operations (DROP, TRUNCATE ohne Confirm)
- 3. Schema Introspection: Claude versteht deine DB-Struktur
- 4. Migration Help: Claude erstellt/applied Migrations
- 5. Query Optimization: Claude analysiert EXPLAIN Plans
Use Cases
- Schema Analysis: Claude analysiert Tables, Columns, Indexes
- Data Exploration: Claude queried & visualisiert Daten
- Migration Generation: Claude erstellt Migrations aus Natural Language
- Query Optimization: Claude optimiert langsame Queries
- Seed Data: Claude generiert Test-Daten
Verwendung
Von der Installation bis zu den verfuegbaren MCP Tools -- dieser Abschnitt zeigt dir die komplette Einrichtung des PostgreSQL MCP Servers.
Installation & Setup
Der folgende Befehl installiert den PostgreSQL MCP Server global auf deinem System. Der Connection String folgt dem standardisierten Format postgresql://user:password@host:port/database, das von allen PostgreSQL-Tools verwendet wird. Bevor du den MCP Server nutzen kannst, muss PostgreSQL selbst natuerlich installiert und gestartet sein -- pruefe das mit pg_isready. Falls du einen Cloud-Dienst wie Supabase, Neon oder Railway verwendest, findest du den Connection String in den Dashboard-Einstellungen deines Providers. Beachte, dass der Connection String das Passwort im Klartext enthaelt -- speichere ihn deshalb niemals direkt in einer Konfigurationsdatei, die in Git committed wird, sondern nutze Umgebungsvariablen.
# MCP Server installieren
npm install -g @modelcontextprotocol/server-postgres
# PostgreSQL Connection String format:
# postgresql://username:password@host:port/database
Konfiguration
Die Konfiguration verbindet den MCP Server mit deiner Datenbank und legt Sicherheitsoptionen fest. Besonders wichtig: admin: false verhindert DROP- und TRUNCATE-Operationen.
~/.config/mcp/postgres.json:
{
"mcpServers": {
"postgres": {
"command": "npx",
"args": [
"-y",
"@modelcontextprotocol/server-postgres"
],
"env": {
"DATABASE_URL": "postgresql://user:pass@localhost:5432/mydb"
},
"permissions": {
"read": true,
"write": true,
"schema": true,
"admin": false // Kein DROP DATABASE
},
"options": {
"maxConnections": 5,
"queryTimeout": 30000,
"safeMode": true // Bestätigung bei DELETE/DROP
}
}
}
}
⚠️ Warnung: Verwende fuer den MCP-Zugriff niemals den PostgreSQL-Superuser. Erstelle einen dedizierten Benutzer mit eingeschraenkten Rechten und setze "admin": false in der Konfiguration, um versehentliche DROP- oder TRUNCATE-Operationen zu verhindern.
Available MCP Tools
. `postgres_query`
Dieses Tool fuehrt eine beliebige SQL-Query aus und gibt die Ergebnisse als strukturiertes JSON mit Rows, Feldtypen und Zeilenanzahl zurueck. Es ist das Haupt-Tool des PostgreSQL MCP Servers und wird fuer alle Lese- und Schreiboperationen verwendet. Die Response enthaelt neben den eigentlichen Daten auch die Spaltennamen und ihre PostgreSQL-Datentypen, sodass Claude die Struktur der Ergebnisse versteht. Stell dir vor, du fragst Claude "Zeige mir die letzten 10 Bestellungen" -- Claude formuliert die SQL-Query, fuehrt sie aus und praesentiert die Ergebnisse in einer lesbaren Tabelle. Beachte, dass bei aktiviertem safeMode destruktive Queries (DELETE, DROP, TRUNCATE) eine Bestaetigung erfordern.
{
"name": "postgres_query",
"description": "Execute SQL query",
"parameters": {
"query": "SELECT * FROM users LIMIT 10"
}
}
Response:
{
"rows": [
{ "id": 1, "name": "Alice", "email": "alice@example.com" },
{ "id": 2, "name": "Bob", "email": "bob@example.com" }
],
"rowCount": 2,
"fields": [
{ "name": "id", "type": "integer" },
{ "name": "name", "type": "text" }
]
}
. `postgres_schema`
Dieses Tool liest das Datenbankschema aus und liefert Informationen ueber Tabellen, Spalten, Datentypen, Constraints und Beziehungen. Ohne den table-Parameter werden alle Tabellen der Datenbank aufgelistet, mit dem Parameter erhaeltst du die detaillierte Struktur einer bestimmten Tabelle. Claude nutzt dieses Tool typischerweise als ersten Schritt, um die Datenbankstruktur zu verstehen, bevor es Queries schreibt oder Migrationen erstellt. Stell dir vor, du uebernimmst ein bestehendes Projekt und willst wissen, wie die Datenbank aufgebaut ist -- postgres_schema gibt dir sofort eine vollstaendige Uebersicht aller Tabellen und ihrer Relationen. Die Response enthaelt auch Informationen ueber Indexes, Foreign Keys und Constraints, was Claude hilft, performante und korrekte Queries zu schreiben.
{
"name": "postgres_schema",
"description": "Get database schema",
"parameters": {
"table": "users" // Optional: specific table
}
}
. `postgres_explain`
Dieses Tool analysiert den Ausfuehrungsplan einer Query, ohne sie tatsaechlich auszufuehren, und identifiziert dabei Performance-Engpaesse und fehlende Indexes. Das Ergebnis zeigt, ob PostgreSQL einen Sequential Scan (langsam, liest die gesamte Tabelle) oder einen Index Scan (schnell, nutzt den Index) verwendet. Stell dir vor, eine Query dauert 5 Sekunden statt 50 Millisekunden -- mit postgres_explain kann Claude den Ausfuehrungsplan analysieren und feststellen, dass ein Index auf der user_id-Spalte fehlt. Claude schlaegt dann das passende CREATE INDEX-Statement vor und erklaert die erwartete Performance-Verbesserung. Dieses Tool ist unverzichtbar fuer die Optimierung langsamer Queries in Produktionsdatenbanken.
{
"name": "postgres_explain",
"description": "Analyze query performance",
"parameters": {
"query": "SELECT * FROM users WHERE email = 'test@example.com'"
}
}
Best Practices
Sicherheit und Performance sind bei Datenbank-Operationen besonders wichtig. Die folgenden Practices schuetzen vor SQL Injection und Datenverlust.
. **Parameterized Queries**
Parameterisierte Queries verhindern SQL Injection, indem Benutzereingaben nie direkt in den SQL-String eingefuegt werden. Stattdessen werden Platzhalter ($1, $2) verwendet, und die Werte werden separat als Array uebergeben. Das ist die wichtigste Sicherheitsmassnahme bei Datenbankzugriffen, da ein Angreifer ueber nicht-parametrisierte Queries beliebigen SQL-Code einschleusen koennte. Stell dir vor, ein User gibt als Suchbegriff '; DROP TABLE users; -- ein -- ohne Parametrisierung wuerde das die gesamte Users-Tabelle loeschen. Mit Platzhaltern wird die Eingabe als reiner Text behandelt, unabhaengig vom Inhalt. Claude verwendet standardmaessig parametrisierte Queries, aber es ist wichtig, das Pattern zu kennen, falls du eigene Queries schreibst.
// ❌ SQL Injection Risk
const query = SELECT * FROM users WHERE id = ${userId};
// ✅ Parameterized Query
const query = {
text: 'SELECT * FROM users WHERE id = $1',
values: [userId]
};
💡 Tipp: Aktiviere safeMode: true in der Konfiguration. Damit wird bei DELETE-, DROP- und TRUNCATE-Operationen eine Bestaetigung verlangt, bevor sie ausgefuehrt werden -- ein wichtiges Sicherheitsnetz fuer Produktionsdatenbanken.
. **Transaction Safety**
Zusammengehoerige Operationen sollten in einer Transaktion ausgefuehrt werden, damit bei einem Fehler alle Aenderungen zurueckgerollt werden. Ohne Transaktion koennten die Daten in einem inkonsistenten Zustand landen, z.B. wenn eine Bestellung erstellt wurde, aber das Inventar nicht aktualisiert werden konnte. Die transaction-Methode fuehrt alle enthaltenen Queries als atomare Einheit aus: Entweder sind alle erfolgreich, oder keine wird ausgefuehrt. Stell dir vor, du ueberweist Geld von einem Konto auf ein anderes -- ohne Transaktion koennte das Geld von einem Konto abgebucht werden, ohne auf dem anderen anzukommen. Claude nutzt Transaktionen automatisch bei zusammenhaengenden Operationen wie dem Erstellen einer Bestellung mit Inventaraktualisierung.
// Wrap Related Operations in Transaction
await postgres.transaction(async (client) => {
await client.query('INSERT INTO orders ...');
await client.query('UPDATE inventory ...');
// Auto-rollback on error
});
. **Schema Migrations**
Migrationen dokumentieren Schema-Aenderungen als nummerierte SQL-Dateien, die versioniert und reproduzierbar sind. Jede Migration erhaelt eine aufsteigende Nummer (hier 001_), damit die Reihenfolge klar ist und Migrationen auf jeder Umgebung in der gleichen Reihenfolge ausgefuehrt werden. Das CREATE TABLE-Statement definiert die Tabellenstruktur mit Spaltentypen und Constraints wie UNIQUE und NOT NULL. Besonders wichtig ist der Index auf der email-Spalte: Ohne ihn muesste PostgreSQL bei jeder Suche nach einer E-Mail-Adresse die gesamte Tabelle durchscannen (Sequential Scan), was bei Millionen von Zeilen sehr langsam wird. Stell dir vor, du deployst deine App auf einem neuen Server -- die Migrationen erstellen die Datenbankstruktur automatisch in der richtigen Reihenfolge, ohne dass du manuell eingreifen musst.
-- Migration: 001_create_users.sql
CREATE TABLE users (
id SERIAL PRIMARY KEY,
email TEXT UNIQUE NOT NULL,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX idx_users_email ON users(email);
Beispiele (12+)
Beispiel 1: Schema Analysis
Du: "Zeig mir die Struktur der users Tabelle"
Claude:
postgres_schema({ table: "users" })
Ausgabe:
Table: users Columns:
- - id: integer (PRIMARY KEY)
- - email: text (UNIQUE, NOT NULL)
- - name: text
- - created_at: timestamp (DEFAULT now())
Indexes:
- - users_pkey (PRIMARY KEY on id)
- - idx_users_email (INDEX on email)
### Beispiel 2: Data Exploration
Du: "Wie viele Users haben wir?"
Claude: postgres_query({ query: "SELECT COUNT(*) FROM users" })
→ "Ihr habt 1.234 Users in der Datenbank"
### Beispiel 3: Migration Generator
Du: "Füge ein 'role' Feld zur users Tabelle hinzu"
Claude generiert Migration:
-- Migration: 002_add_user_role.sql
ALTER TABLE users
ADD COLUMN role TEXT DEFAULT 'user'
CHECK (role IN ('user', 'admin', 'moderator'));
CREATE INDEX idx_users_role ON users(role);
🚀 Beispiel: Nutze postgres_explain um langsame Queries zu analysieren -- Claude liest den EXPLAIN-Plan, identifiziert fehlende Indexes und schlaegt konkrete CREATE INDEX Statements vor.
Beispiel 4: Query Optimization
Du: "Warum ist diese Query so langsam?"
Query: SELECT * FROM orders WHERE user_id = 123
Claude:
1. postgres_explain({ query: "..." })
2. Analysiert EXPLAIN Plan
Ausgabe:
Performance Issue Found:
❌ Seq Scan on orders (cost=1000..5000) → Full table scan, kein Index
Recommendation: CREATE INDEX idx_orders_user_id ON orders(user_id);
Expected Improvement: 50x faster
### Beispiel 5: Seed Data Generator
Du: "Generiere 100 Test-Users"
Claude:
INSERT INTO users (name, email)
SELECT
'User ' || generate_series,
'user' || generate_series || '@example.com'
FROM generate_series(1, 100);
Beispiel 6: Data Validation
Du: "Check ob alle Emails valide sind"
Claude:
postgres_query({
query: "SELECT id, email FROM users WHERE email !~ '^[^@]+@[^@]+\.[^@]+