Skip to main content
Glama
harutlc

SQL MCP Server

by harutlc

SQL MCP Server

Ein KI-gestützter Model Context Protocol (MCP)-Server, mit dem Sie eine E-Commerce-SQLite-Datenbank in natürlicher Sprache abfragen und analysieren können.

Stellen Sie Fragen wie:

  • „Wer sind unsere Top-5-Kunden nach Gesamtausgaben?“

  • „Zeige alle Produkte in der Kategorie Elektronik mit einem Bestand unter 50“

  • „Wie hoch war unser Gesamtumsatz für abgeschlossene Bestellungen im Jahr 2026?“

Vier Tools, von denen drei überhaupt keinen API-Schlüssel benötigen. Schreibgeschützt auf zwei unabhängigen Ebenen, paginierte Ergebnisse, SQLites eigene Fehlermeldungen werden an den Aufrufer zurückgegeben, und 74 automatisierte Tests.

InhaltSchnellstart · KI-Anbieter konfigurieren · Tools · Paginierung · Fehler · Tests · Docker · MCP-Clients · Konfiguration · Sicherheit · Datenabfluss · Projektstruktur


🚀 Schnellstart

1. Voraussetzungen

  • Node.js: v22.5.0 oder höher (für das eingebaute node:sqlite-Modul); v24 empfohlen

  • npm: v11.0.0 oder höher

2. Installation

Klonen Sie dieses Repository und installieren Sie die Abhängigkeiten:

npm install
cp .env.example .env
npm run build

Das reicht aus, um den Server mit einem Client zu verbinden und list_tables, describe_table und execute_sql zu verwenden. Ein Anbieter wird nur für das Tool für natürliche Sprache benötigt – siehe unten.


Related MCP server: Shop SQLite MCP

🔑 KI-Anbieter konfigurieren

Öffnen Sie die .env-Datei und richten Sie Ihr bevorzugtes KI-Modell ein. Der Server erkennt Ihren Anbieter automatisch anhand der von Ihnen gesetzten Variablen:

Option A: Anthropic Claude (Empfohlen)

ANTHROPIC_API_KEY=sk-ant-api03-...
ANTHROPIC_MODEL=claude-opus-5

Option B: Lokales Ollama (Kostenlos & Offline)

OLLAMA_BASE_URL=http://localhost:11434
OLLAMA_MODEL=llama3.2

Hinweis: Stellen Sie sicher, dass Ollama läuft (ollama serve) und Sie das Modell heruntergeladen haben (ollama pull llama3.2).

Option C: OpenAI

OPENAI_API_KEY=sk-proj-...
OPENAI_MODEL=gpt-4o-mini

Option D: Benutzerdefiniert / Drittanbieter (Groq, DeepSeek, OpenRouter)

OPENAI_API_KEY=your_api_key
OPENAI_BASE_URL=https://api.groq.com/openai/v1
OPENAI_MODEL=llama-3.3-70b-versatile

🛠 Verfügbare Tools

Drei der vier sprechen direkt mit SQLite – kein API-Schlüssel, keine Kosten, sofort:

Tool

Was es tut

Benötigt einen Anbieter

list_tables

Jede Tabelle mit einer verständlichen Erklärung, was sie enthält, ihrer Zeilenanzahl und ihren Spalten, sowie die Beziehungen zwischen den Tabellen und die Umsatzkonvention, die diese Datenbank verwendet.

Nein

describe_table

Eine Tabelle vollständig – Spalten mit Typen, Schlüsseln und Beschreibungen, Fremdschlüssel, die CREATE TABLE-Anweisung, Einschränkungen und den tatsächlichen Bereich der Datumsspalten.

Nein

execute_sql

Jede schreibgeschützte SELECT-Abfrage, die strukturierte JSON-Zeilen und Spaltennamen zurückgibt. Unterstützt limit / offset-Paginierung. Dies ist das Tool für analytische Arbeiten, die Sie selbst steuern möchten.

Nein

query_database

Nimmt eine Frage in natürlicher Sprache, generiert und führt das passende SQL aus und gibt eine schriftliche Antwort mit Erkenntnissen zurück.

Ja

Die Beschreibung jedes Tools sagt dem aufrufenden Agenten nicht nur, was es tut, sondern auch, wann es nicht verwendet werden soll – query_database gibt an, dass es Prosa statt Werte zurückgibt, Geld kostet und zwei LLM-Aufrufe macht, und verweist für alles, was der Agent selbst berechnen möchte, auf execute_sql. Beide Tools geben das Zeilenlimit und die Umsatzkonvention direkt an, sodass der Agent sie nicht durch Ausprobieren herausfinden muss.

Beispiel: describe_table

// describe_table { "table_name": "orders" } — abridged
{
  "table": "orders",
  "purpose": "Order headers — one row per order placed by a customer, carrying its date, lifecycle status and total.",
  "rowCount": 750,
  "columns": [
    { "name": "status", "type": "TEXT", "primaryKey": false, "notNull": true, "default": null,
      "description": "Lifecycle stage, one of: new, processing, shipped, completed, cancelled. Determines whether the order counts as revenue." }
  ],
  "foreignKeys": [
    { "column": "customer_id", "referencesTable": "customers", "referencesColumn": "id", "onDelete": "CASCADE" }
  ],
  "notes": ["Revenue convention: count every order whose status is not 'cancelled' …"],
  "dataCoverage": { "order_date": { "min": "2026-02-17 18:53:30", "max": "2026-08-22 17:06:30" } },
  "createStatement": "CREATE TABLE orders ( … )"
}

dataCoverage ist vorhanden, damit ein Agent ein leeres Ergebnis von einer Frage außerhalb des Bereichs unterscheiden kann: Eine Frage zu 2025 liefert „die Daten reichen von … bis …“ anstatt einer nackten Null, die wie ein Fehler wirkt.


📄 Paginierung großer Ergebnisse

Jedes Ergebnis ist begrenzt – auf DATABASE_MAX_ROWS (Standard 100) oder auf ein kleineres limit, das Sie übergeben. Ein größeres limit wird abgeschnitten statt abgelehnt, sodass ein Aufrufer immer Zeilen zurückbekommt.

execute_sql akzeptiert limit und offset und teilt Ihnen mit, ob es mehr gibt:

// execute_sql { "sql": "SELECT id, name FROM products ORDER BY id", "limit": 2, "offset": 2 }
{
  "columns": ["id", "name"],
  "rows": [
    { "id": 3, "name": "Ноутбук UltraBook 15" },
    { "id": 4, "name": "Умные часы FitWatch" }
  ],
  "rowCount": 2,
  "offset": 2,
  "hasMore": true,
  "nextOffset": 4,
  "note": "More rows matched than were returned. Call again with offset=4 for the next page.",
  "executionTimeMs": 0.09
}

Rufen Sie weiter mit offset: nextOffset auf, bis hasMore false ist. Wenn ein Ergebnis in eine Seite passt, ist hasMore false und totalAvailableRows meldet die tatsächliche Gesamtzahl.

Das Limit wird während des Durchlaufens der Anweisung durchgesetzt, nicht durch Abschneiden eines fertigen Ergebnisses: Der Server stoppt eine Zeile über dem Limit und materialisiert den Rest nie. Das SQL ist modellgeneriert, sodass ein versehentlicher Cross Join sonst Millionen von Zeilen in den Speicher ziehen würde, bevor irgendwelche verworfen würden. Die Paginierung erfolgt ebenfalls während der Iteration und nicht durch Anhängen von LIMIT/OFFSET an das SQL, was überleben müsste, womit auch immer die generierte Anweisung bereits endet.

query_database teilt das Zeilenlimit, paginiert aber nicht – es fasst in Prosa zusammen, wo eine Seitennummer nichts zu befestigen hat. Verwenden Sie execute_sql für alles, was größer als eine Seite ist.


🚦 Wie ein Fehler aussieht

Fehler kommen als normale MCP-Toolergebnisse mit isError: true und einer Meldung zurück, auf die der aufrufende Agent reagieren kann, und nicht als Transportfehler.

Sie senden

Sie erhalten

SELECT nope FROM products

Query execution failed: no such column: nope

DELETE FROM orders

Only read-only queries are permitted. A statement must begin with SELECT, WITH or VALUES, but this one begins with "DELETE".

SELECT 1; SELECT 2

Only a single SQL statement may be executed. Multiple statements were provided.

describe_table {"table_name": "custmers"}

No table named "custmers". Available tables: customers, order_items, orders, products.

Eine Anfrage in natürlicher Sprache zum Löschen von Daten

This request asks to modify the database, which is not permitted … No changes were made. You can still ask about the same records: …

Zwei Regeln bestimmen diesen Text:

  • SQLites eigene Meldung bleibt erhalten. „no such column: nope“ ist die nützlichste Information, die einem Agenten gegeben werden kann, weil sie ausreicht, um die Abfrage neu zu schreiben und erneut zu versuchen. Sie wird nie zu „Abfrage fehlgeschlagen“ vereinfacht.

  • Host-Details entkommen nie. Unerkannte Fehler – die einen Stacktrace enthalten können – werden auf eine generische Zeile reduziert, und alles, was nach außen geht, wird von Datenbankpfad, Projektstamm und Home-Verzeichnis bereinigt. Vollständige Details bleiben in den Server-Logs. Dies wird durch eine eigene Testdatei abgedeckt.


🧪 Automatisierte Tests

npm test          # 74 tests across 4 files, runs in well under a second
npm run test:watch
npm run typecheck

Einfaches node --test mit tsx – keine Test-Framework-Abhängigkeit. Die Suiten laufen gegen die echte db/shop.db, nicht gegen einen Mock, sodass sie fehlschlagen, wenn Schema und Dokumentation auseinanderdriften.

Datei

Abdeckung

tests/sql-guard.test.ts

Jede Möglichkeit, wie ein Schreibvorgang am Schreibschutz vorbeigeschmuggelt werden könnte: führende Kommentare, WITH x AS (…) DELETE, gestapelte Anweisungen, Markdown-umrandetes DML. Plus das Gegenteil – dass replace(), ein Schlüsselwort innerhalb eines String-Literals und ein in Anführungszeichen gesetzter Bezeichner, der nach einem Schlüsselwort benannt ist, nicht abgelehnt werden.

tests/database.test.ts

Zeilenbegrenzung, offset-Paginierung, ein Offset über das Ende hinaus, ein außer Kontrolle geratener Cross Join, der nicht materialisiert werden darf, Spaltennamen bei leerem Ergebnis, verweigerte Schreibvorgänge, die die Datenbank unverändert lassen, SQLites Meldung überlebt.

tests/errors.test.ts

Was ein Aufrufer sehen darf: umsetzbare Meldungen kommen durch, unbekannte Fehler werden reduziert, und Datenbankpfad / Projektstamm / Home-Verzeichnis werden aus beiden entfernt.

tests/schema-metadata.test.ts

Dass jede Tabelle und jede Spalte in der Live-Datenbank eine schriftliche Beschreibung hat, dass keine Beschreibung auf eine Tabelle verweist, die nicht mehr existiert, und dass die Umsatzkonvention angegeben ist.

Die Guard-Suite ist die wichtigste: Sie ist die Grenze, die „schreibgeschützt“ wahr macht und nicht nur beabsichtigt, und einer ihrer Fälle ist ein echter Fehlalarm, den sie während der Entwicklung aufgedeckt hat.


🐳 Docker

docker build -t sql-mcp .

Das Image enthält die Datenbank, benötigt also kein Volume-Mount. Da dies ein Stdio-Server ist, muss er mit -i und ohne TTY ausgeführt werden – die Standardeingabe und Standardausgabe des Containers transportieren den JSON-RPC-Stream:

docker run -i --rm -e ANTHROPIC_API_KEY sql-mcp

Binden Sie ihn mit examples/claude_desktop_config.docker.json in einen Client ein. Entfernen Sie -e ANTHROPIC_API_KEY, um ohne Anmeldedaten zu laufen – list_tables, describe_table und execute_sql funktionieren ohne Anbieter.

Der Build ist mehrstufig: TypeScript wird in einem node:24-alpine-Builder kompiliert, und nur dist/, db/ und Produktionsabhängigkeiten werden in das Laufzeitimage kopiert. Es läuft als unprivilegierter node-Benutzer, es wird nie eine .env-Datei hineinkopiert (Anmeldedaten kommen über -e), und es gibt keine nativen Addons zu kompilieren, weil SQLite in Node selbst enthalten ist.


🔌 Verbindung zu MCP-Clients

Gebrauchsfertige Konfigurationsdateien finden Sie in examples/ – kopieren Sie die zu Ihrem Client passende und ersetzen Sie den Pfad. examples/claude_desktop_config.no-api-key.json führt den Server ohne Anmeldedaten aus, was für list_tables, describe_table und execute_sql ausreicht.

Claude-Desktop-Konfiguration

Fügen Sie diesen Server zu Ihrer Claude-Desktop-Konfigurationsdatei (claude_desktop_config.json) hinzu:

  • macOS: ~/Library/Application Support/Claude/claude_desktop_config.json

  • Windows: %APPDATA%\Claude\claude_desktop_config.json

(Stellen Sie sicher, dass Sie vor dem Verbinden einmal npm run build ausführen)

Beispiel 1: Anthropic Claude (Standard)

{
  "mcpServers": {
    "sql-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/sql-mcp/dist/index.js"],
      "env": {
        "ANTHROPIC_API_KEY": "sk-ant-api03-your-key-here",
        "ANTHROPIC_MODEL": "claude-opus-5"
      }
    }
  }
}

Beispiel 2: Lokales Ollama (Kostenlos & Offline)

{
  "mcpServers": {
    "sql-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/sql-mcp/dist/index.js"],
      "env": {
        "OLLAMA_BASE_URL": "http://localhost:11434",
        "OLLAMA_MODEL": "llama3.2"
      }
    }
  }
}

Beispiel 3: OpenAI

{
  "mcpServers": {
    "sql-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/sql-mcp/dist/index.js"],
      "env": {
        "OPENAI_API_KEY": "sk-proj-your-key-here",
        "OPENAI_MODEL": "gpt-4o-mini"
      }
    }
  }
}

Beispiel 4: Benutzerdefiniert / Groq / OpenRouter / DeepSeek

{
  "mcpServers": {
    "sql-mcp": {
      "command": "node",
      "args": ["/absolute/path/to/sql-mcp/dist/index.js"],
      "env": {
        "OPENAI_API_KEY": "gsk_your_groq_api_key",
        "OPENAI_BASE_URL": "https://api.groq.com/openai/v1",
        "OPENAI_MODEL": "llama-3.3-70b-versatile"
      }
    }
  }
}

Der Server löst db/shop.db relativ zu seinem eigenen Speicherort auf, sodass DATABASE_PATH in keiner dieser Konfigurationen benötigt wird – MCP-Clients starten Server aus einem Arbeitsverzeichnis ihrer eigenen Wahl, und der Server hängt nicht davon ab.


🔎 Lokal ausprobieren

Sofortiger Terminal-Test

Sie können Fragen in natürlicher Sprache direkt in Ihrem Terminal testen:

npm run query -- "Show top 3 products by price"

Visueller Web-Inspektor

Testen Sie Tools interaktiv in Ihrem Browser mit dem offiziellen MCP-Inspektor:

npm run inspect:dev
  1. Öffnen Sie die Inspektor-URL in Ihrem Browser (z. B. http://localhost:5173).

  2. Klicken Sie auf Connect.

  3. Wählen Sie unter Tools die Option query_database, geben Sie Ihre Frage ein und klicken Sie auf Run Tool.

Alle npm-Skripte

Script

Funktion

npm run build / npm run clean

Nach dist/ kompilieren · entfernen

npm start

Den gebauten Server über stdio ausführen

npm run dev

Aus dem Quellcode mit Reload ausführen (tsx watch)

npm test / npm run test:watch

Automatisierte Tests

npm run typecheck

tsc --noEmit

npm run query -- "…"

Eine Frage vom Terminal aus stellen

npm run inspect / npm run inspect:dev

MCP Inspector gegen dist/ · gegen den Quellcode


🔧 Konfigurationsreferenz

Jede Variable ist optional; die Standardwerte greifen, wenn nichts gesetzt ist.

Variable

Standard

Zweck

DATABASE_PATH

db/shop.db

Datenbankpfad. Absolut oder relativ zum Projektstamm – niemals zum Arbeitsverzeichnis.

DATABASE_MAX_ROWS

100

Harte Obergrenze für Zeilen pro Aufruf und für an das LLM gesendete Zeilen. limit in execute_sql kann sie nur senken.

LLM_TIMEOUT_MS

60000

Zeitlimit pro Anfrage für LLM-Aufrufe. Eine Frage macht zwei sequenzielle Aufrufe, daher hängt ein blockierter Provider ohne dies den Tool-Aufruf auf.

LLM_PROVIDER

automatisch erkannt

anthropic | ollama | openai | custom. Normalerweise aus den gesetzten Schlüsseln abgeleitet.

ANTHROPIC_API_KEY / ANTHROPIC_MODEL

— / claude-opus-5

Anthropic-Provider.

OPENAI_API_KEY / OPENAI_MODEL / OPENAI_BASE_URL

— / gpt-4o-mini / OpenAI

OpenAI und jeder OpenAI-kompatible Endpunkt.

OLLAMA_BASE_URL / OLLAMA_MODEL

http://localhost:11434 / llama3.2

Lokales Ollama.

DEBUG

nicht gesetzt

sql-mcp:* oder ein einzelner Namespace: server, query-engine, database, llm, tools.

Ein fehlerhafter Wert wird auf stderr gemeldet und fällt auf den Standardwert zurück, anstatt stillschweigend akzeptiert zu werden – ein Tippfehler im env-Block eines Clients zeigt sich beim Start, statt sich so zu verhalten, als wäre die Variable nie gesetzt worden. DEBUG-Logs enthalten jede gestellte Frage und jede generierte Anweisung, und unter einem MCP-Client landen sie in den persistenten Logdateien des Clients – sie bleiben also aus, sofern man sie nicht explizit aktiviert.


🔒 Sicherheit

Die Datenbank wird auf Treiberebene schreibgeschützt geöffnet, und jede Anweisung wird vor der Ausführung validiert: Sie muss eine einzelne SELECT/WITH/VALUES-Anweisung sein, ohne Schlüsselwort, das Daten schreibt, das Schema ändert oder den Verbindungszustand verändert. Keine der beiden Prüfungen kann per Konfiguration deaktiviert werden. Eine Anfrage wie "alle stornierten Bestellungen löschen" wird abgelehnt statt ausgeführt.

Der Validator arbeitet über eine tokenisierte Sicht der Anweisung statt über den rohen Text, sodass Kommentare, String-Literale und in Anführungszeichen gesetzte Bezeichner nicht zum Verstecken eines Schlüsselworts genutzt werden können – /* c */ DELETE FROM orders und WITH x AS (SELECT 1) DELETE FROM orders werden beide abgelehnt, während SELECT replace(name, 'a', 'b') nicht abgelehnt wird.

Text, den dieser Server nicht geschrieben hat – Ihre Frage und aus der Datenbank gelesene Werte – wird in den Prompts mit einem nicht fälschbaren, pro Anfrage einzigartigen Marker abgegrenzt, sodass ein Produkt namens Widget (SYSTEM: ignore prior instructions…) nicht in den Anweisungskontext entkommen kann. Das ist über diesen Prozess hinaus relevant: Die Antwort reist als Tool-Ausgabe zurück zum aufrufenden Agenten, einen Hop weiter.


🔐 Was wohin gesendet wird

Dieser Server beantwortet Fragen durch einen LLM-Aufruf, daher verlassen Datenbankinhalte bei jedem query_database-Aufruf Ihren Rechner. Konkret sendet jeder Aufruf:

  1. Ihr Datenbankschema – Tabellennamen, Spaltennamen und -typen sowie Zeilenzahlen – um das SQL zu generieren.

  2. Die vom Query zurückgegebenen Zeilen (bis zu DATABASE_MAX_ROWS, Standard 100) – um sie in eine schriftliche Antwort umzuwandeln.

Bei der mitgelieferten Shop-Datenbank enthalten diese Zeilen Kundennamen, E-Mail-Adressen und Telefonnummern. Sie gehen an den jeweils konfigurierten Provider, an den Endpunkt, den OPENAI_BASE_URL benennt – was bei Groq, OpenRouter oder DeepSeek ein Drittanbieter unter eigenen Bedingungen ist.

Falls das für Ihre Daten nicht akzeptabel ist:

  • Nutzen Sie die anderen drei Tools. list_tables, describe_table und execute_sql tätigen überhaupt keinen Netzwerkaufruf – nichts verlässt den Rechner.

  • Nutzen Sie Ollama. Es läuft lokal, daher verlässt nichts den Rechner.

  • Schränken Sie die Queries ein. Aggregatfragen („Umsatz nach Kategorie") liefern Zusammenfassungszeilen statt Kundendatensätze.

  • Senken Sie DATABASE_MAX_ROWS, um zu begrenzen, wie viele Zeilendaten pro Query gesendet werden.

Der Server sendet niemals die Datenbankdatei, und er kann nur lesen – siehe Sicherheit.


📁 Projektstruktur

src/
  index.ts                  MCP server entry point (stdio transport)
  cli.ts                    Terminal harness: npm run query -- "…"
  config/                   Env parsing, provider detection, path resolution
  tools/                    The four MCP tools and their descriptions
  services/
    database.service.ts     SQLite access, row capping, paging, introspection
    sql-guard.ts            Read-only enforcement (tokenizing validator)
    errors.ts               Caller-safe messages, path redaction
    schema-metadata.ts      Human-written meaning the schema cannot record
    query-engine.service.ts NL → SQL → execute → prose pipeline
    llm/                    Anthropic / OpenAI / Ollama behind one interface
  prompts/                  SQL generation, humanization, untrusted-input framing
tests/                      node --test suites (see Automated Tests)
db/                         shop.db and its schema documentation
docs/                       Architecture and sequence diagrams
examples/                   Ready-to-paste client configurations

📚 Technische Dokumentation

Install Server
F
license - not found
A
quality
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables natural-language sales queries against a SQLite database, generating and executing read-only SQL through a secure MCP server with table listing, schema description, and query execution.
  • F
    license
    Not graded
    quality
    C
    maintenance
    Enables safe, read-only analysis of an online store's SQLite database, providing schema introspection, restricted SELECT queries, and specialized analytics tools through MCP.
  • F
    license
    A
    quality
    C
    maintenance
    Enables read-only interaction with an online store's SQLite database over MCP stdio, including table listing, schema inspection, safe read-only SQL execution, and sales analytics. It rejects mutating SQL operations to keep data intact.
    4
  • F
    license
    A
    quality
    C
    maintenance
    Enables AI agents to read-only query an online store's SQLite database, listing tables, inspecting schemas, and running SELECT queries over customers, products, orders, and order items.
    3

View all related MCP servers

Related MCP Connectors

  • Connect e-commerce and marketing data to AI assistants via MCP.

  • Analytical memory for AI agents: a real Postgres queried in plain English over MCP. One command.

  • GibsonAI MCP server: manage your databases with natural language

View all MCP Connectors

Latest Blog Posts

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/harutlc/sql-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server