Skip to main content
Glama
AndiAtom

MariaDB MCP Server

by AndiAtom

MariaDB MCP Server mit streamable HTTP für Open-WebUI

Ein read-only MCP Server, der als Schnittstelle zwischen einer MariaDB Datenbank und Open-WebUI dient. Der Server erlaubt ausschließlich lesende Abfragen und blockiert alle Schreiboperationen wie INSERT, UPDATE, DELETE, CREATE, ALTER, DROP usw.

Hinweis: Der Server verwendet mysql-connector-python, der vollständig mit MariaDB kompatibel ist und keine externen Systembibliotheken benötigt. Der Server ist MCP-kompatibel und implementiert die notwendigen Endpunkte für Open-WebUI. Aktuellste Version verwendet Python 3.12 als Base Image.


:rocket: Schnellstart

Mit Docker (empfohlen)

# Klone das Repository
git clone https://github.com/AndiAtom/mariadb-mcp-strhttp.git
cd mariadb-mcp-strhttp

# Starte mit Docker Compose (enthält MariaDB + MCP Server)
docker-compose up -d

# Der Server ist jetzt unter http://localhost:8000 verfügbar

Ohne Docker

# Installiere Abhängigkeiten
pip install -r requirements.txt

# Starte den Server
python -m src.server

# Oder direkt
python src/server.py

Related MCP server: tusk-mcp

:gear: Konfiguration

Umgebungsvariablen

Der Server wird über Umgebungsvariablen konfiguriert. Die mitgelieferte config.json dient als Referenz für die möglichen Werte und wird nicht automatisch vom Server eingelesen.

Datenbank-Konfiguration

Variable

Beschreibung

Standardwert

Beispiel

DB_HOST

MariaDB Hostname

localhost

192.168.1.100

DB_PORT

MariaDB Port

3306

3306

DB_USER

MariaDB Benutzername

mcpuser

mcp_user

ALLOW_DB_ROOT

DB_USER=root beim Start erlauben (nur lokale Entwicklung)

false

true

DB_PASSWORD

MariaDB Passwort

""

securepassword

DB_DATABASE

Standard-Datenbank

None

mydatabase

DB_TIMEOUT

Timeout für Datenbankabfragen (Sekunden)

30

60

Server-Konfiguration

Variable

Beschreibung

Standardwert

Beispiel

SERVER_HOST

Server Host

0.0.0.0

0.0.0.0

SERVER_PORT

Server Port

8000

8000

LOG_LEVEL

Log-Level

info

debug

API-Token-Authentifizierung

Variable

Beschreibung

Standardwert

Beispiel

API_TOKEN

Einzelner API-Token

None

my-secret-token

API_TOKENS

Mehrere API-Tokens (komma-separiert)

None

token1,token2

API_TOKEN_FILE

Pfad zur Token-Datei

None

/app/tokens.json

DISABLE_API_AUTH

Authentifizierung deaktivieren

false

true

API_HEADER_NAME

Name des Authorization Headers

Authorization

X-API-Key

API_QUERY_PARAM

Name des Query-Parameters

api_key

token

Hinweis: Der Token wird nicht mehr aus dem Request-Body extrahiert. Dies verhindert einen Doppelkonsum des Bodies durch die Auth-Middleware. Verwende stattdessen den Authorization-Header oder den api_key-Query-Parameter.

CORS

Variable

Beschreibung

Standardwert

Beispiel

CORS_ALLOWED_ORIGINS

Erlaubte CORS-Origins (komma-separiert)

"" (keine)

https://openwebui.example.com

Sicherheit: allow_origins=["*"] mit allow_credentials=True ist eine bekannte Fehlkonfiguration. Ohne Konfiguration von CORS_ALLOWED_ORIGINS sind keine Cross-Origin-Requests mit Credentials möglich.

Datenbank-Zugriffskontrolle

Variable

Beschreibung

Standardwert

Beispiel

ALLOWED_DATABASES

Positiv-Liste erlaubter Datenbanken (komma-separiert)

"" (nicht gesetzt)

testdb,analytics

Sicherheit: System-Schemata (mysql, information_schema, performance_schema, sys) sind immer gesperrt. Ohne ALLOWED_DATABASES sind alle nicht-System-Schemata erlaubt; mit gesetzter Variable nur die gelisteten.

API-Dokumentation

Variable

Beschreibung

Standardwert

Beispiel

PUBLIC_DOCS

/docs und /redoc ohne Auth freischalten

false

true

Sicherheit: Die API-Dokumentation ist standardmäßig auth-pflichtig, um kein Informationsleck zu erzeugen. Nur in vertrauenswürdigen internen Umgebungen auf true setzen.

Request-Limitierung & Security-Header

Variable

Beschreibung

Standardwert

Beispiel

MAX_REQUEST_BODY_BYTES

Maximale Request-Body-Größe in Bytes (DoS-Schutz)

1048576 (1 MiB)

2097152

Sicherheit: Der Server setzt zusätzlich Standard-Security-Header auf jede Antwort: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: no-referrer, Cache-Control: no-store. Strict-Transport-Security (HSTS) wird nur bei HTTPS-Requests gesetzt. Ein DB_USER=root wird beim Start abgewiesen (außer ALLOW_DB_ROOT=true); Auth aktiviert ohne konfigurierte Tokens führt zu einem Startabbruch (Fail-Closed).

Rate Limiting

Variable

Beschreibung

Standardwert

Beispiel

RATE_LIMITING_ENABLED

Rate Limiting aktivieren

true

false

RATE_LIMIT_REQUESTS_PER_MINUTE

Anfragen pro Minute

100

200

RATE_LIMIT_BURST_REQUESTS

Burst-Anfragen

10

20

RATE_LIMIT_WHITELIST

Whitelisted Pfade

/health,/, etc.

/health,/info

Referenzkonfiguration (config.json)

Die folgende config.json zeigt die Struktur der Konfigurationswerte. Sie wird nicht vom Server automatisch geladen; alle Werte werden stattdessen über die oben genannten Umgebungsvariablen gesetzt.

{
  "server": {
    "host": "0.0.0.0",
    "port": 8000,
    "log_level": "info"
  },
  "database": {
    "host": "localhost",
    "port": 3306,
    "user": "mcpuser",
    "password": "securepassword",
    "database": "mydatabase",
    "timeout": 30
  },
  "security": {
    "read_only": true,
    "block_write_operations": true,
    "validate_queries": true
  },
  "authentication": {
    "enabled": true,
    "type": "api_token",
    "tokens": ["token1", "token2"],
    "token_file": null,
    "header_name": "Authorization",
    "query_param_name": "api_key"
  },
  "rate_limiting": {
    "enabled": true,
    "requests_per_minute": 100,
    "burst_requests": 10,
    "whitelist": ["/health", "/", "/docs", "/openapi.json", "/redoc"]
  }
}

Hinweis: Maßgeblich sind die Umgebungsvariablen aus den Tabellen oben. Diese config.json ist lediglich eine Referenz.


:key: API-Token-Authentifizierung

Der Server unterstützt optionale API-Token-Authentifizierung, um den Zugriff auf die API zu schützen.

Token-Generierung

Das Projekt enthält ein Skript generate_token.py zur Generierung sicherer API-Tokens:

# Einzelnen Token generieren
python generate_token.py

# Mehrere Tokens generieren
python generate_token.py --num 5

# Token mit bestimmter Länge generieren (Standard: 32 Zeichen)
python generate_token.py --length 64

# Token in Datei speichern
python generate_token.py --file tokens.json

# Tokens nur anzeigen (nicht speichern)
python generate_token.py --no-file

Authentifizierung aktivieren

Es gibt mehrere Möglichkeiten, die Authentifizierung zu konfigurieren:

1. Einzelner Token über Umgebungsvariable

# In docker-compose.yml oder beim Starten
API_TOKEN=your-secure-token-here

2. Mehrere Tokens über Umgebungsvariable (komma-separiert)

API_TOKENS=token1,token2,token3

3. Token aus Datei laden

Erstelle eine JSON-Datei tokens.json:

{
  "tokens": [
    "your-secure-token-1",
    "your-secure-token-2"
  ]
}

Oder eine einfache Textdatei (ein Token pro Zeile):

token1
token2
token3

Dann in docker-compose.yml:

environment:
  - API_TOKEN_FILE=/app/tokens.json
volumes:
  - ./tokens.json:/app/tokens.json:ro

Hot-Reload: Eine über API_TOKEN_FILE eingebundene Token-Datei wird bei Änderung (mtime) automatisch beim nächsten Request neu geladen. Token-Rotation ist damit ohne Server-Restart möglich. Die Prüfung erfolgt über stat und ist sehr billig; nur bei tatsächlicher Änderung wird die Datei gelesen.

Fail-Closed-Startup: Ist die Authentifizierung aktiviert (Standard), aber es sind keine Tokens konfiguriert (API_TOKEN/API_TOKENS/API_TOKEN_FILE), bricht der Server den Start mit einem Fehler ab. Das verhindert sowohl einen versehentlich offenen als auch einen "abgeriegelten" (Silent-Death) Server. Für lokale Entwicklung DISABLE_API_AUTH=true setzen.

Konstanter Token-Vergleich: Tokens werden über secrets.compare_digest validiert (konstante Zeit), um Timing-Seitenkanäle bei der Token-Enumeration zu vermeiden.

4. Authentifizierung deaktivieren (nur für lokale Entwicklung)

DISABLE_API_AUTH=true

Token verwenden

Es gibt drei Möglichkeiten, den Token zu übergeben:

1. Authorization Header (empfohlen)

curl -X POST http://localhost:8000/query \
  -H "Authorization: Bearer your-secure-token" \
  -H "Content-Type: application/json" \
  -d '{"query": "SELECT * FROM customers LIMIT 10"}'

2. Query Parameter

curl -X POST http://localhost:8000/query?api_key=your-secure-token \
  -H "Content-Type: application/json" \
  -d '{"query": "SELECT * FROM customers LIMIT 10"}'

Hinweis: Die Token-Übertragung im Request-Body wird aus Sicherheitsgründen nicht mehr unterstützt (Doppelkonsum des Bodies). Verwende Header oder Query-Parameter.

Öffentliche Endpunkte

Die folgenden Endpunkte benötigen keine Authentifizierung:

  • GET / - Server-Informationen

  • GET /health - Health-Check

  • GET /openapi.json - OpenAPI-Spezifikation (für Clients wie Open-WebUI)

Hinweis: /docs und /redoc sind standardmäßig auth-pflichtig und können über PUBLIC_DOCS=true freigeschaltet werden.

Alle anderen Endpunkte erfordern einen gültigen API-Token, wenn die Authentifizierung aktiviert ist.


:plug_socket: Standard-MCP-Clients (Spec 2026-07-28)

Seit v1.4.0 spricht POST /mcp zusätzlich zum Open-WebUI-Legacy-Format das offizielle MCP-Protokoll nach Spec 2026-07-28 (stateless core, JSON-RPC 2.0). Beide Generationen bedient derselbe Endpunkt — ein valider JSON-RPC-2.0-Envelope wandert in den Spec-Pfad, alles andere in den Legacy-Pfad.

Unterstützte RPCs: server/discover, tools/list, tools/call, ping. Header-Pflichten: MCP-Protocol-Version (muss mit _meta['io.modelcontextprotocol/protocolVersion'] übereinstimmen) und Mcp-Method; für tools/call zusätzlich Mcp-Name (Base64-Sentinel =?base64?...?= wird dekodiert). Fehler: -32020 HeaderMismatch, -32022 UnsupportedProtocolVersion, -32601 mit HTTP 404 für unbekannte Methoden, 202 Accepted für Notifications. Tool-Fehler kommen als Tool-Result mit isError: true (HTTP 200), Parameterfehler als -32602.

Beispiel mit dem offiziellen Python-SDK:

from mcp.client.streamable_http import streamable_http_client
from mcp.client.session import ClientSession

async with streamable_http_client("http://localhost:8000/mcp") as streams:
    async with ClientSession(*streams) as session:
        result = await session.discover()   # statt initialize()
        session.adopt(result)
        tools = await session.list_tools()
        r = await session.call_tool("execute_query", {"query": "SELECT 1"})

REST-Endpunkte (/query, /tables, /databases, /schema/{table}, ...) bleiben unverändert; die Authentifizierung (API-Token via Header/Query) gilt weiterhin für alle Pfade.


:desktop_computer: Open-WebUI Integration

MCP Server in Open-WebUI hinzufügen

  1. Öffne Open-WebUI (z.B. http://localhost:8080)

  2. Gehe zu Einstellungen --> MCP Server oder Externe Tool-Server

  3. Klicke auf "Add MCP Server" oder "Neuer Server"

  4. Füge folgende Konfiguration ein:

{
  "name": "MariaDB Read-Only",
  "type": "http",
  "url": "http://localhost:8000",
  "readOnly": true,
  "headers": {
    "Authorization": "Bearer your-api-token-here"
  },
  "capabilities": {
    "query": true,
    "stream": true,
    "validate": true,
    "list_resources": false,
    "read_resource": false
  },
  "timeout": 60
}

:bulb: Hinweis: Open-WebUI erkennt automatisch den MCP-kompatiblen Endpunkt. Die URL kann einfach http://localhost:8000 sein, der Server hat sowohl den Standard- als auch den /mcp-Endpunkt.

Verbindung testen

Frage Open-WebUI:

"Was sind die Tabellen in der Datenbank?"

Erwartete Antwort: Eine Liste aller Tabellen aus deiner MariaDB.


:shield: Sicherheitsfeatures

Read-Only Implementierung

Der Server implementiert mehrere Ebenen von Read-Only-Schutz:

  1. DB-User-Ebene (primär): Verwende einen dedizierten DB-User ohne Schreibrechte (GRANT SELECT ON ...). Dies ist die wichtigste Schutzmaßnahme.

  2. Session-Ebene: SET SESSION read_only=ON wird auf jeder Verbindung des Pools gesetzt (Defense-in-Depth)

  3. Abfrage-Ebene: Jede Abfrage wird vor der Ausführung auf Schreiboperationen geprüft (is_read_only_query)

  4. Identifier-Validierung: Tabellen- und Datenbanknamen werden per Regex (^[A-Za-z0-9_]+$) validiert, bevor sie in SQL eingefügt werden (SQL-Injection-Schutz)

  5. Kommentar-Stripping: Vor der Prüfung werden SQL-Kommentare entfernt. Dabei kommt ein stack-basiertes Verfahren zum Einsatz, das auch verschachtelte/gestaffelte Blockkommentare (/* a /* b */ INSERT ... */) korrekt nach MariaDB-Semantik entfernt. Ein nicht-greedy Regex würde hier das INSERT übersehen.

Hinweis: Die frühere einzelne, global geteilte Verbindung wurde durch einen Connection-Pool ersetzt, der pro Request eine isolierte Verbindung öffnet. Das verhindert Race Conditions durch USE-Wechsel auf geteilten Verbindungen.

Query Timeout Schutz

  • Standard-Timeout: Alle Datenbankabfragen haben einen Standard-Timeout von 30 Sekunden

  • Individueller Timeout: Kann pro Abfrage über den timeout-Parameter angepasst werden

  • Streaming-Limit: Streaming-Abfragen sind auf 10.000 Zeilen begrenzt, um sehr große Resultsets zu verhindern

  • Konfigurierbar: Timeout kann über die Umgebungsvariable DB_TIMEOUT oder in der Konfigurationsdatei angepasst werden

Audit-Logging

Der Server schreibt strukturierte Audit-Ereignisse in den separaten Logger audit (unabhängig vom Anwendungs- und Access-Log, z. B. in eine Datei oder ein SIEM weiterleitbar). Jedes Ereignis ist eine JSON-Zeile mit:

  • event: Art (query.executed, query.denied, query.error)

  • client_ip: direkter Peer (nicht X-Forwarded-For, vertraut nur direkter Verbindung)

  • token_index: Index des Tokens in der konfigurierten Menge (kein Token-Wert!)

  • database, query_preview (max. 80 Zeichen), valid, row_count, status_code, error

Sicherheit: Es werden keine vollständigen Queries und keine Token-Werte protokolliert. Der token_index ermöglicht eine eindeutige Client-Zuordnung ohne Token-Leak. Audit-Ereignisse werden im /query-Endpunkt bei Erlaubnis, Ablehnung und Fehler geschrieben.

Blockierte Befehle

Der Server blockiert alle Schreiboperationen, einschließlich:

DDL (Data Definition Language)

  • CREATE - Tabellen, Datenbanken, Indizes erstellen

  • ALTER - Objekte ändern

  • DROP - Objekte löschen

  • TRUNCATE - Tabellen leeren

  • RENAME - Objekte umbenennen

DML (Data Manipulation Language)

  • INSERT - Daten einfügen

  • UPDATE - Daten aktualisieren

  • DELETE - Daten löschen

  • REPLACE - Daten ersetzen

  • LOAD - Daten laden

  • MERGE - Daten zusammenführen

DCL (Data Control Language)

  • GRANT - Berechtigungen erteilen

  • REVOKE - Berechtigungen entziehen

  • DENY - Berechtigungen verweigern

Transaktionssteuerung

  • COMMIT - Transaktionen bestätigen

  • ROLLBACK - Transaktionen zurücksetzen

  • SAVEPOINT - Speicherpunkte erstellen

  • RELEASE - Speicherpunkte freigeben

Administrative Befehle

  • SHUTDOWN - Server herunterfahren

  • KILL - Verbindungen beenden

  • PURGE - Logs bereinigen

  • RESET - Zurücksetzen

  • FLUSH - Caches leeren

  • SET PASSWORD - Passwort ändern

  • SET GLOBAL - Globale Variablen setzen

  • SET SESSION - Sitzungsvariablen setzen (außer read_only)

Replikation

  • CHANGE MASTER - Master ändern

  • START SLAVE - Slave starten

  • STOP SLAVE - Slave stoppen

MariaDB/MySQL-spezifische Befehle

  • OPTIMIZE TABLE - Tabellen defragmentieren (Schreiboperation)

  • REPAIR TABLE - Tabellen reparieren (Schreiboperation)

  • ANALYZE TABLE - Statistiken aktualisieren (Schreiboperation)

  • CHECK TABLE - Tabellen prüfen (kann Reparaturen auslösen)

  • CHECKSUM TABLE - Prüfsummen berechnen

Erlaubte Befehle

Nur folgende Befehle sind erlaubt:

Datenabfragen

  • SELECT - Daten abfragen

  • WITH / CTE - Common Table Expressions

Metadaten-Abfragen

  • SHOW - Informationen anzeigen (TABLES, DATABASES, COLUMNS, INDEX, etc.)

  • DESCRIBE / DESC - Tabellenstruktur anzeigen

  • EXPLAIN - Ausführungsplan anzeigen

Informationsschema

  • INFORMATION_SCHEMA - Metadaten abfragen

Transaktionssteuerung (nur lesend)

  • START TRANSACTION READ ONLY - Read-Only Transaktion starten

  • BEGIN READ ONLY - Read-Only Transaktion beginnen

  • SET TRANSACTION READ ONLY - Transaktion als read-only setzen

Sonstige

  • HELP - Hilfe anzeigen

Hinweis: USE ist nicht mehr als direkte Abfrage erlaubt. Ein Datenbankwechsel erfolgt über den database-Parameter der Endpunkte (z. B. {"query": "...", "database": "mydb"}). System-Schemata wie mysql oder information_schema sind gesperrt.


:satellite: API Endpunkte

MCP Endpunkte (für Open-WebUI)

Methode

Endpunkt

Beschreibung

GET

/mcp

MCP Server Information (Tools, Capabilities)

POST

/mcp

MCP Anfragen verarbeiten

Standard API Endpunkte (für direkte Nutzung)

Methode

Endpunkt

Beschreibung

Parameter

GET

/

Server-Informationen

-

GET

/health

Health-Check

-

POST

/query

SQL-Abfrage ausführen

query, database (optional), timeout (optional)

GET

/query/validate

SQL-Abfrage validieren

query

POST

/query/validate

SQL-Abfrage validieren

query

GET

/query/stream

SQL-Abfrage mit Streaming

query, timeout (optional)

GET

/tables

Alle Tabellen auflisten

database (optional)

GET

/databases

Alle Datenbanken auflisten

-

GET

/schema/{table}

Schema einer Tabelle abrufen

table

GET

/columns/{table}

Spalten einer Tabelle abrufen

table

GET

/query/examples

Beispiele für erlaubte Abfragen

-

GET

/openapi.json

OpenAPI-Spezifikation (öffentlich)

-

GET

/docs

Swagger UI Dokumentation (auth-pflichtig¹)

-

GET

/redoc

ReDoc Dokumentation (auth-pflichtig¹)

-

¹ Auth-pflichtig, außer PUBLIC_DOCS=true ist gesetzt.


:computer: API Beispiele

Einfache Abfrage mit Authentifizierung

# Mit Authorization Header
curl -X POST http://localhost:8000/query \
  -H "Authorization: Bearer your-api-token" \
  -H "Content-Type: application/json" \
  -d '{"query": "SELECT * FROM customers LIMIT 10"}'

# Mit Query Parameter
curl -X POST http://localhost:8000/query?api_key=your-api-token \
  -H "Content-Type: application/json" \
  -d '{"query": "SELECT * FROM customers LIMIT 10"}'

# Mit Datenbank-Angabe
curl -X POST http://localhost:8000/query \
  -H "Authorization: Bearer your-api-token" \
  -H "Content-Type: application/json" \
  -d '{"query": "SELECT * FROM mails LIMIT 5", "database": "tanss"}'

MCP Endpunkt testen

# MCP Server Info abrufen (keine Authentifizierung nötig)
curl http://localhost:8000/mcp

# MCP Anfrage ausführen (mit Authentifizierung)
curl -X POST http://localhost:8000/mcp \
  -H "Authorization: Bearer your-api-token" \
  -H "Content-Type: application/json" \
  -d '{"method": "execute_query", "params": {"query": "SELECT * FROM customers LIMIT 5"}}'

Streaming Abfrage

curl -H "Authorization: Bearer your-api-token" \
  http://localhost:8000/query/stream?query=SELECT%20*%20FROM%20large_table

Antwort (Server-Sent Events):

data: {"type": "metadata", "columns": ["id", "name"], "query": "SELECT * FROM large_table"}

data: {"type": "row", "data": {"id": 1, "name": "Row 1"}}

data: {"type": "row", "data": {"id": 2, "name": "Row 2"}}

data: {"type": "complete", "total_rows": 1000}

Abfrage validieren

curl -X POST http://localhost:8000/query/validate \
  -H "Authorization: Bearer your-api-token" \
  -H "Content-Type: application/json" \
  -d '{"query": "INSERT INTO users VALUES (1, \"test\")"}'

Antwort:

{
  "valid": false,
  "error": "Abfrage enthält Schreiboperationen. Nur lesende Abfragen sind erlaubt.",
  "blocked_keywords": ["INSERT"]
}

Tabellen auflisten

# Alle Tabellen in der aktuellen Datenbank
curl -H "Authorization: Bearer your-api-token" \
  http://localhost:8000/tables

# Tabellen in einer bestimmten Datenbank
curl -H "Authorization: Bearer your-api-token" \
  http://localhost:8000/tables?database=tanss

Schema einer Tabelle abrufen

curl -H "Authorization: Bearer your-api-token" \
  http://localhost:8000/schema/customers

:hourglass: Rate Limiting

Der Server implementiert Rate Limiting, um die API vor übermäßiger Nutzung zu schützen.

Standard-Konfiguration

  • Aktiviert: Ja (standardmäßig)

  • Anfragen pro Minute: 100

  • Burst-Anfragen: 10

  • Whitelist: /, /health, /docs, /openapi.json, /redoc

Rate Limit Header

Jede Antwort enthält folgende Header:

  • X-RateLimit-Limit: Maximale Anfragen pro Minute

  • X-RateLimit-Remaining: Verbleibende Anfragen

  • X-RateLimit-Reset: Zeitstempel, wann das Limit zurückgesetzt wird

Fehlerbehandlung

Bei Überschreitung des Rate Limits:

  • HTTP Status: 429 Too Many Requests

  • Header: Retry-After: 60 (Sekunden bis zum nächsten Versuch)

  • Body:

    {
      "error": "Too Many Requests",
      "detail": "Rate Limit überschritten. Maximale Anfragen: 100 pro Minute",
      "retry_after": 60
    }

:test_tube: Testen

Automatisierte Tests

# Installiere Test-Abhängigkeiten
pip install pytest httpx

# Führe Tests aus
pytest tests/

Manuelles Testen

  1. Verbindung testen:

    curl http://localhost:8000/health
  2. MCP Endpunkt testen:

    curl http://localhost:8000/mcp
  3. Erlaubte Abfrage testen:

    curl -X POST http://localhost:8000/query \
      -H "Authorization: Bearer your-token" \
      -d '{"query": "SELECT 1"}'
  4. Blockierte Abfrage testen:

    curl -X POST http://localhost:8000/query \
      -H "Authorization: Bearer your-token" \
      -d '{"query": "INSERT INTO test VALUES (1)"}'

    --> Sollte Fehler 403 zurückgeben

  5. Authentifizierung testen:

    # Ohne Token (sollte 401 zurückgeben, wenn Auth aktiviert)
    curl -X POST http://localhost:8000/query \
      -d '{"query": "SELECT 1"}'
    
    # Mit falschem Token (sollte 401 zurückgeben)
    curl -X POST http://localhost:8000/query \
      -H "Authorization: Bearer wrong-token" \
      -d '{"query": "SELECT 1"}'
    
    # Mit richtigem Token (sollte funktionieren)
    curl -X POST http://localhost:8000/query \
      -H "Authorization: Bearer your-correct-token" \
      -d '{"query": "SELECT 1"}'

:wrench: Fehlerbehebung

Häufige Probleme und Lösungen

1. Open-WebUI erkennt den MCP Server nicht

  • Ursache: Falsche URL oder Server nicht erreichbar

  • Lösung:

    • URL in Open-WebUI auf http://localhost:8000 setzen

    • Server-Status prüfen: curl http://localhost:8000/health

    • MCP-Endpunkt testen: curl http://localhost:8000/mcp

2. "Leere Abfrage" Fehler

  • Ursache: Open-WebUI sendet die Abfrage in einem anderen Format

  • Lösung: Der Server unterstützt jetzt:

    • JSON Body: {"query": "SELECT ..."}

    • Formular-Daten: query=SELECT ...

    • Alternative Feldnamen: query, sql, q

    • Datenbank-Angabe: {"query": "...", "database": "tanss"}

3. Verbindung zur Datenbank scheitert

  • Ursache: Falsche Credentials oder MariaDB nicht für Remote-Zugriff konfiguriert

  • Lösung:

    • Prüfe DB_HOST, DB_USER, DB_PASSWORD in docker-compose.yml

    • MariaDB für Remote-Zugriff konfigurieren:

      # In /etc/mysql/mariadb.conf.d/50-server.cnf
      bind-address = 0.0.0.0
    • Benutzer berechtigen:

      GRANT SELECT ON *.* TO 'mcp_user'@'%';
      FLUSH PRIVILEGES;
    • network_mode: host in docker-compose.yml verwenden

4. Server nicht erreichbar

  • Ursache: Port Konflikt oder Firewall

  • Lösung:

    • Prüfe mit curl http://localhost:8000/health

    • Port 8000 freigeben: sudo ufw allow 8000

    • Andere Dienste auf Port 8000 beenden: sudo lsof -i :8000

5. Docker-Container startet nicht

  • Ursache: Berechtigungsprobleme oder fehlende Abhängigkeiten

  • Lösung:

    docker-compose down
    docker-compose up -d --build
    docker-compose logs mariadb-mcp-server

6. Abfragen werden blockiert

  • Ursache: Abfrage enthält Schreiboperationen

  • Lösung:

    • Validierung prüfen: curl -X POST http://localhost:8000/query/validate -d '{"query": "DEINE_ABFRAGE"}'

    • Nur lesende Abfragen verwenden (SELECT, SHOW, DESCRIBE, etc.)

7. 401 Unauthorized Fehler

  • Ursache: API-Token-Authentifizierung aktiviert, aber kein oder falscher Token angegeben

  • Lösung:

    • Token in Authorization Header angeben: -H "Authorization: Bearer your-token"

    • Token als Query Parameter angeben: ?api_key=your-token

    • Authentifizierung deaktivieren: DISABLE_API_AUTH=true

Hinweis: Die Token-Übertragung im Request-Body wird nicht mehr unterstützt (kein Doppelkonsum des Bodies). Verwende Header oder Query-Parameter.


:package: Abhängigkeiten

Der Server verwendet folgende Python-Pakete:

Paket

Version

Zweck

fastapi

>=0.104.0

Web-Framework für die API

uvicorn

>=0.24.0

ASGI-Server

mysql-connector-python

>=8.0.0

MariaDB/MySQL Connector

sse-starlette

>=1.6.0

Server-Sent Events Unterstützung

pydantic

>=2.5.0

Datenvalidierung

python-multipart

>=0.0.6

Formular-Daten Unterstützung

:bulb: Hinweis: Wir verwenden mysql-connector-python statt mariadb, da dieser Connector keine externen Systembibliotheken benötigt und damit Docker-freundlicher ist. Er ist vollständig kompatibel mit MariaDB.


:bookmark: Versionshistorie

Version

Datum

Änderungen

v1.0.0

2026-07-30

Erste stabile Version

Read-only SQL-Validierung

Streaming-Unterstützung

Docker-Unterstützung

Wechsel zu mysql-connector-python

MCP-kompatibler Endpunkt

v1.0.1

2026-08-03

Bugfixes

Behebe "Leere Abfrage" Fehler

Behebe TRANSACTION READ ONLY Fehler

Unterstützung für alternative Anfrage-Formate

Verbesserte Docker-Netzwerk-Konfiguration

v1.1.0

2026-08-05

API-Token-Authentifizierung

Unterstützung für einzelne und mehrere Tokens

Token aus Datei laden

Flexible Token-Übertragung (Header, Query)

Benutzerdefinierte Header/Parameter Namen

Öffentliche Endpunkte ohne Authentifizierung

v1.2.0

2026-08-13

Erweiterte Sicherheit

Thread-sicheres Rate Limiting

Korrigierte asyncio-Probleme

Verbesserte Fehlerbehandlung

Aktualisierte Dokumentation

v1.3.0

2026-08-14

Sicherheits-Härtung

SQL-Injection-Schutz: Identifier-Validierung, parametrisierte Queries

USE blockiert, Datenbank-Allow-Liste (ALLOWED_DATABASES)

Connection-Pool statt globaler Verbindung (Race Condition)

Auth-Middleware liest Request-Body nicht mehr (kein Doppelkonsum)

CORS restriktiviert (CORS_ALLOWED_ORIGINS)

/docs, /redoc auth-pflichtig (PUBLIC_DOCS); /openapi.json öffentlich

Fehlermeldungen leaken keine DB-Interna

Testsuite repariert (119 Tests)

v1.3.1

2026-08-14

Weitere Sicherheits-Mechanismen

Konstanter Token-Vergleich (Timing-Seitenkanal)

Stack-basiertes Kommentar-Stripping (verschachtelte/gestaffelte Kommentare)

Request-Body-Größenbegrenzung (MAX_REQUEST_BODY_BYTES)

Security-Headers (nosniff, DENY, no-store, HSTS bei HTTPS)

Fail-Closed-Startup: Auth ohne Tokens bricht den Start ab

Token-Datei-Hot-Reload (Rotation ohne Restart)

DB_USER=root-Startup-Guard (ALLOW_DB_ROOT)

Strukturiertes Audit-Logging (Token-Index statt Token-Wert)

.dockerignore + Container-Härtung (cap_drop, read_only, no-new-privileges)

config.json-Passwort-Feld als Platzhalter

v1.4.0

2026-09-17

MCP-Spec 2026-07-28 (stateless core)

JSON-RPC 2.0 auf POST /mcp (Dual-Era: Spec + Open-WebUI-Legacy)

server/discover (Pflicht-Methode, ersetzt initialize-Handshake)

tools/list mit ttlMs/cacheScope, deterministische Tool-Reihenfolge

tools/call mit content + structuredContent, isError-Semantik

Header-Routing/Validierung: MCP-Protocol-Version, Mcp-Method, Mcp-Name (-32020)

Base64-Sentinel-Dekodierung für Mcp-Name

-32022 UnsupportedProtocolVersion, 404+-32601 für unbekannte Methoden

Notifications: 202 Accepted

Mit offiziellem Python-MCP-SDK verifiziert (discover→adopt→tools)

48 neue Tests (167 gesamt)


:busts_in_silhouette: Mitwirken

  1. Fork das Repository

  2. Erstelle einen Feature-Branch (git checkout -b feature/AmazingFeature)

  3. Commit deine Änderungen (git commit -m 'Add some AmazingFeature')

  4. Push zum Branch (git push origin feature/AmazingFeature)

  5. Öffne einen Pull Request


:memo: Lizenz

Dieses Projekt ist unter der MIT-Lizenz lizenziert - siehe LICENSE für Details.


:email: Kontakt


Hinweis: Dieser Server ist ausschließlich für lesende Abfragen konzipiert. Alle Versuche, Schreiboperationen auszuführen, werden blockiert und führen zu einem Fehler.

Technischer Hinweis: Der Server verwendet mysql-connector-python, der vollständig mit MariaDB kompatibel ist und keine externen C-Bibliotheken benötigt, was die Docker-Installation deutlich vereinfacht. Der Server implementiert einen MCP-kompatiblen Endpunkt (/mcp) für nahtlose Integration mit Open-WebUI und unterstützt sowohl JSON- als auch Formular-Daten-Anfragen. Die Read-Only-Funktionalität wird auf Session-Ebene (SET SESSION read_only=ON) und auf Abfrage-Ebene (Validierung) sichergestellt. Die API-Token-Authentifizierung bietet eine zusätzliche Sicherheitsebene für den Zugriff auf die API.

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    A read-only PostgreSQL MCP server that enables AI agents to perform schema introspection and execute SELECT-only queries. It supports secure database connections through SSL and SSH tunnels while offering a structure-only mode to restrict query access.
    8 npm
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    A lightweight MCP server providing safe, read-only access to MySQL databases. It enables users to query multiple MySQL instances securely while preventing write operations.
    633 npm
    MIT
  • A
    license
    A
    quality
    C
    maintenance
    Read-only MySQL/MariaDB MCP server for running SELECT queries safely, with automatic read-only enforcement and query limits.
    3
    6 npm
    MIT