Skip to main content
Glama
Kenza-21

SQL MCP Server

by Kenza-21

SQL MCP Server

Ein Model Context Protocol-Server, der LLM-Agenten (Claude Desktop, Claude Code oder ein beliebiger MCP-Client) über sechs schreibgeschützte Tools Zugriff auf eine Postgres-Datenbank gibt. Setzen Sie einen Agenten darauf an und stellen Sie Fragen wie „Welche Kunden haben letzten Monat mehr als fünf Bestellungen aufgegeben?" – der Agent erkundet das Schema und fragt die Daten selbst ab, über die unten aufgeführten Tools.

Tools

Tool

Beschreibung

list_tables()

Übersicht über alle Tabellen: Name, Beschreibung, Größe, Spaltenanzahl

describe_table(table)

Spalten, Typen und Fremdschlüsselbeziehungen für eine Tabelle

search_schema(keyword)

Tabellen/Spalten finden, deren Name einem Schlüsselwort entspricht

sample_rows(table, limit)

Echte Zeilen ansehen (Standard: 5)

count_rows(table)

Zeilenanzahl einer Tabelle

execute_select(sql)

Eine beliebige schreibgeschützte SELECT- / WITH ... SELECT-Abfrage ausführen

Related MCP server: mcp-data-gateway

Warum das kein „bloßer Wrapper um psycopg2" ist

Text-to-SQL-Demos sind weit verbreitet; der Teil, der wirklich schwierig ist – und auf den dieses Projekt seinen Fokus legt – ist, execute_select so sicher zu machen, dass es einem LLM übergeben werden kann, das beliebiges SQL generiert:

  1. Schreibgeschützte Postgres-Rolle. Der Server verbindet sich als mcp_readonly, eine Rolle mit ausschließlich SELECT-Berechtigungen (siehe scripts/init_schema.sql). Selbst ein Fehler in den unten genannten Prüfungen auf Anwendungsebene kann keinen Schreibvorgang auslösen.

  2. Schreibschutz auf Sitzungsebene. Jede Verbindung führt SET TRANSACTION READ ONLY aus (db.py).

  3. Statement-Validierung (security.py): Es ist nur eine einzelne SELECT/WITH-Anweisung erlaubt – keine gestapelten Anweisungen (; DROP TABLE ...), keine SQL-Kommentare (blockiert kommentarbasiertes Einschleusen von Anweisungen), und eine Keyword-Blocklist deckt INSERT/UPDATE/DELETE/DDL/GRANT/usw. ab, einschließlich SELECT ... INTO (das stillschweigend eine Tabelle erstellt).

  4. Bezeichner-Validierung. describe_table, sample_rows und count_rows akzeptieren einen Tabellennamen als Parameter. Da SQL-Bezeichner nicht mit Platzhaltern parametrisiert werden können, werden Tabellennamen gegen einen strengen Regex und eine live aus information_schema abgerufene Whitelist geprüft – nicht nur per String-Escaping.

  5. Ressourcenlimits. Ein Postgres-statement_timeout verhindert, dass Abfragen außer Kontrolle geraten, und ein serverseitiges Zeilenlimit wird bei jedem Abfrageergebnis durchgesetzt, selbst wenn die Abfrage des LLMs kein LIMIT angegeben hat.

Schnellstart

git clone <this-repo>
cd sql-mcp-server
pip install -r requirements.txt

# 1. Start Postgres with the sample schema
docker compose up -d

# 2. Generate sample e-commerce data (uses the postgres superuser, not mcp_readonly)
PGUSER=postgres PGPASSWORD=postgres python scripts/generate_sample_data.py

# 3. Configure the server to use the read-only role
cp .env.example .env
# edit .env if you changed the default mcp_readonly password

# 4. Run the tests
pytest

# 5. Run the server (stdio transport, for use with an MCP client)
python -m sql_mcp_server.server

Verbinden mit Claude Desktop

Fügen Sie Folgendes zu Ihrer MCP-Konfiguration von Claude Desktop hinzu (claude_desktop_config.json):

{
  "mcpServers": {
    "sql-explorer": {
      "command": "python",
      "args": ["-m", "sql_mcp_server.server"],
      "cwd": "/absolute/path/to/sql-mcp-server",
      "env": {
        "PGHOST": "localhost",
        "PGPORT": "5432",
        "PGDATABASE": "sales",
        "PGUSER": "mcp_readonly",
        "PGPASSWORD": "change_me"
      }
    }
  }
}

Starten Sie Claude Desktop neu und fragen Sie dann etwas wie „Welche Tabellen sind verfügbar und welche Produktkategorie hat den höchsten Gesamtumsatz?"

Beispielschema

orders → order_items → products → categories, plus customers. Der Umsatz einer Bestellung = sum(order_items.quantity * order_items.unit_price). Der Generator erzeugt ~600 Kunden, ~3.500 Bestellungen und eine Handvoll absichtlicher Daten-Eigenheiten (fehlende E-Mails, ein paar Ausreißer bei Großbestellungen), damit die Abfragen den Eindruck erwecken, auf echte Daten zu treffen.

Tests

tests/test_security.py und tests/test_tools.py laufen ohne Datenbank – sie testen die Validierungsschicht direkt und die Tool-Funktionen mit gemockter DB-Schicht. Das ist es, was CI ausführt. db.py selbst (die psycopg2-Schicht) wird in der Praxis erprobt, indem der Server gegen die Docker-Postgres-Instanz ausgeführt wird; siehe Schnellstart oben.

Projektstruktur

sql_mcp_server/
  config.py    Environment-based settings
  security.py  SQL/identifier validation (the core safety logic)
  db.py        psycopg2 access layer
  server.py    MCP tool definitions
scripts/
  init_schema.sql            Schema + read-only role setup
  generate_sample_data.py    Faker-based sample data
tests/
  test_security.py  Validation logic (18+ cases: injection, stacked
                     statements, comment smuggling, DDL/DML blocking, etc.)
  test_tools.py     Tool functions with mocked DB

Related MCP Connectors

Related MCP Servers

  • F
    license
    Not graded
    quality
    D
    maintenance
    Enables interaction with PostgreSQL databases through MCP, allowing users to explore database structures, inspect table schemas, and execute read-only SQL queries.
    -
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables AI agents to query a PostgreSQL database through a small set of controlled, read-only tools for schema inspection, row lookup, and aggregate statistics.
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A read-only natural-language database agent that exposes PostgreSQL schema-discovery and SELECT tools via MCP, enabling users to query databases in plain English.
    MIT