Skip to main content
Glama
Khushboo-Mishra

SQL-MCP-101

SQL-MCP-101

Neu bei MCP? Beginnen Sie mit dem interaktiven Tutorial, einem Klick-für-Klick-Durchgang durch Tools, Ressourcen und Prompts und wie man entscheidet, welches davon für ein Feature geeignet ist.

Ein kleiner, stark kommentierter MCP-Server für MySQL, der alle drei Model-Context-Protocol-Primitive (Tools, Ressourcen und Prompts) in etwa 1.100 Zeilen Python demonstriert, plus eine Browser-UI zum Erkunden.

Dieses Repository existiert, um gelesen zu werden, nicht nur ausgeführt. Wenn Sie MCP erwähnt gesehen haben und verstehen möchten, was der Bau eines Servers tatsächlich beinhaltet, ist dies ein vollständiges, funktionierendes Beispiel, das klein genug ist, um es in einem Durchgang zu lesen: ein Primitive pro Datei, Kommentare, die warum statt was erklären, und eine Demo-Datenbank mit absichtlichen Fehlern, damit die Beispiele echte Probleme finden statt Spielzeugprobleme.

mcp_server/
├── database.py    read-only introspection; the only file not about MCP
├── execution.py   running queries and writes, plus every safety control
├── tools.py       6 TOOLS      inspect structure, cannot read or change a row
├── data_tools.py  6 TOOLS      read rows, and insert / update / delete / alter
├── resources.py   4 RESOURCES  content the APPLICATION attaches (+2 templates)
├── prompts.py     6 PROMPTS    workflows the USER invokes
└── server.py      wires them together, about 10 meaningful lines

Der Server ist lese-schreibend: Er beantwortet Fragen zu den Daten, indem er echte Abfragen ausführt, und er kann Daten und Schema ändern. Er ist auf eine einzige Wegwerf-Demo-Datenbank beschränkt, und die Kontrollen, die das sicher machen, befinden sich in execution.py und werden unten erklärt. Dieses Design ist selbst Teil der Lektion.


Die eine Idee, die man mitnehmen sollte

Die meisten MCP-Tutorials behandeln nur Tools, was den Eindruck hinterlässt, MCP sei Tools. Es sind drei Primitive, und sie unterscheiden sich darin, wer die Kontrolle hat:

Primitive

Wer entscheidet

Wann es passiert

Analogie

Tool

das Modell

mitten im Gespräch, autonom

eine Funktion, die das Modell aufrufen darf

Ressource

die Anwendung

im Voraus, von einem Menschen gewählt

eine Datei, die man anhängt

Prompt

der Benutzer

explizit, über ein Menü

eine gespeicherte Expertenfrage

Dieselben Daten können als mehr als eines erscheinen. In diesem Repo ist get_table_ddl ein Tool und schema://table/{name}/ddl eine Ressource. Dieselben Bytes, auf zwei verschiedene Arten erreicht, weil „das Modell holt es, wenn es entscheidet, dass es es braucht“ und „ein Mensch hängt es vor dem Start an“ wirklich unterschiedliche Bedürfnisse sind.


Related MCP server: mysql-mcp-server

Schnellstart

git clone https://github.com/Khushboo-Mishra/SQL-MCP-101.git
cd SQL-MCP-101
bash scripts/setup.sh

setup.sh prüft Voraussetzungen, erstellt die virtuelle Umgebung, installiert die beiden Abhängigkeiten, erstellt die Demo-Datenbank und verifiziert den Server Ende-zu-Ende. Es stoppt mit einer spezifischen Meldung beim ersten fehlenden Element.

Dann sehen Sie alle drei Primitive in einem Durchgang:

bash scripts/run_explorer.sh

Voraussetzungen

  • Python 3.10+

  • MySQL 8.x, lokal ausgeführt (brew services start mysql)

  • Node.js: optional, nur für den MCP Inspector

  • Ollama: optional, nur für das Chat-Panel der UI

Standardmäßig wird root auf 127.0.0.1:3306 ohne Passwort verwendet, was der Homebrew-Standard ist, sodass die meisten nichts ändern müssen. Andernfalls exportieren Sie MYSQL_USER, MYSQL_PASSWORD, MYSQL_HOST, MYSQL_PORT.


Was gebaut wird

12 Tools, 4 Ressourcen + 2 URI-Vorlagen und 6 Prompts, über eine Demo-Datenbank mit sechs Tabellen.

Tools: Diese ruft das Modell auf

Auf zwei Dateien verteilt nach Wirkungsradius, nicht nach Subsystem. Das ist eine bewusste Designentscheidung, die es wert ist, übernommen zu werden: Sie hält die riskante Oberfläche klein und offensichtlich für jeden, der den Server überprüft oder sein Datenbank-GRANT schreibt.

tools.py: Struktur untersuchen. Kann keine Zeile lesen, kann nichts ändern.

Tool

Zweck

list_tables

jede Tabelle und Sicht, mit Zeilenschätzungen

describe_table(table)

Spalten, Typen, Schlüssel, Indizes, Fremdschlüssel

get_table_ddl(table)

das exakte CREATE TABLE

list_relationships

jeder deklarierte Fremdschlüssel

find_sensitive_columns

Spalten, deren Name auf PII oder Geheimnisse hindeutet

search_columns(keyword)

eine Spalte finden, wenn man vergisst, in welcher Tabelle sie ist

data_tools.py: Zeilen lesen und Daten ändern. Das ist die Hälfte mit Konsequenzen.

Tool

Zweck

run_query(sql, limit)

eine SELECT-Abfrage ausführen und die Zeilen zurückbekommen; das beantwortet Datenfragen

execute_statement(sql)

INSERT / UPDATE / DELETE / CREATE / ALTER / DROP / TRUNCATE

insert_row(table, values)

strukturiertes Einfügen, Werte als gebundene Parameter gesendet

update_rows(table, changes, where)

strukturiertes Update, where erforderlich

delete_rows(table, where)

strukturiertes Löschen, where erforderlich

show_audit_log(limit)

jede Anweisung, die der Server ausgeführt hat

Warum sowohl ein allgemeines execute_statement als auch strukturierte Wrapper? Strukturierte Tools sind sicherer: Argumente sind typisiert und Werte werden gebunden, sodass das Modell nie SQL-Text schreibt und nichts Fehlerhaftes erzeugen kann. Aber sie tun nur, was Sie vorhergesehen haben. Eine allgemeine SQL-Tür behandelt den langen Schwanz: Fensterfunktionen, ein ALTER, das Sie nicht vorhergesehen haben. Die meisten echten Server liefern aus genau diesem Grund beides aus.

Ressourcen: Diese hängt die Anwendung an

URI

Typ

Inhalt

schema://tables

JSON

Tabelleninventar

schema://ddl

SQL

DDL für das gesamte Schema

schema://relationships

JSON

alle Fremdschlüssel

schema://overview

Markdown

menschenlesbare Zusammenfassung

schema://table/{name}

JSON

eine Tabelle (vorlagenbasiert)

schema://table/{name}/ddl

SQL

DDL einer Tabelle (vorlagenbasiert)

Eine statische Ressource hat eine feste URI und erscheint in resources/list, sodass ein Client sie in einer Auswahl anzeigen kann. Eine vorlagenbasierte Ressource hat {Platzhalter} und erscheint stattdessen in resources/templates/list. Es gibt keine feste Liste zum Anzeigen, also füllt der Client die Lücke aus.

Prompts: Diese ruft der Benutzer auf

Prompt

Argumente

Was es tut

audit_schema

keine

fünfstufiger Gesundheitscheck: Schlüssel, Beziehungen, PII, Benennung

explain_table

table

erklärt eine Tabelle in einfacher Sprache

ask_data

question

schreibt die Abfrage, führt sie aus und antwortet in einfacher Sprache

modify_data

request

Vorschau → Bestätigen → Anwenden → Verifizieren, für Änderungen

document_schema

keine

generiert Referenzdokumentation

onboarding_tour

role

ein geführter erster Blick, zugeschnitten auf eine Rolle


Entscheiden: Tool, Ressource oder Prompt?

Die Frage, an der Menschen hängen bleiben. Gehen Sie sie in dieser Reihenfolge durch.

1. Führt es eine Aktion aus oder holt es etwas, das das Modell wählt?Tool. Alles, was das Modell selbst entscheiden können sollte.

2. Ist es ein Dokument, das ein Mensch sinnvollerweise vor dem Start anhängen würde?Ressource. Referenzmaterial, Gesamtschema-Kontext, alles Stabile.

3. Ist es eine Aufgabe, die jemand wiederholt, bei der die Art der Frage das Fachwissen ist?Prompt. Liefern Sie die gute Frage, statt Wiederentdeckung zu erwarten.

Zwei Heuristiken, die die meisten verbleibenden Zweifel auflösen:

Wer initiiert? Modell → Tool. Anwendung → Ressource. Benutzer → Prompt.

Möchten Sie das in einem Menü? Wenn ja, ist es ein Prompt. Menüs sind für Menschen, und nur Prompts werden Menschen als Befehle angezeigt.

Durchgearbeitete Beispiele aus diesem Repo

Feature

Wahl

Warum

Struktur einer Tabelle abrufen

Tool

das Modell braucht es mitten in der Argumentation, unvorhersehbar

Gesamtschema-DDL

beides

Tool für das Modell; Ressource für einen Menschen, um es im Voraus anzuhängen

Schema-Audit

Prompt

eine wiederholbare Aufgabe, bei der das Wissen, was man fragt, der Wert ist

Nach einer Spalte suchen

Tool

nimmt ein Argument, das das Modell zur Aufrufzeit wählt

Markdown-Übersicht

Ressource

passive Referenz, keine Entscheidung erforderlich

Wo Menschen es falsch machen

  • Alles als Tools. Funktioniert, aber das Modell verbrennt Aufrufe, um Kontext zu holen, den ein Mensch einmal anhängen könnte, und Benutzer erhalten keine auffindbaren Einstiegspunkte.

  • Ressourcen für Dinge, die Argumente benötigen, die das Modell wählt. Wenn das Modell den Parameter entscheidet, ist es ein Tool.

  • Prompts, die Arbeit erledigen. Ein Prompt gibt Text zurück. Wenn Sie sich dabei ertappen, die Datenbank in einem Prompt abzufragen, wollten Sie ein Tool.


Die Demo-Datenbank

mcp_demo, sechs Tabellen, absichtlich unvollkommen, damit die Beispiele echte Probleme finden:

Tabelle

Absichtlicher Fehler

CUSTOMERS

EMAIL, PHONE, der Scan für sensible Spalten schlägt an

PRODUCTS

SKU ist UNIQUE, aber nicht der Primärschlüssel, ein natürlicher Schlüssel, der diskussionswürdig ist

ORDERS

(sauber, das Referenzbeispiel)

ORDER_ITEMS

PRODUCT_ID sieht wie ein Fremdschlüssel aus, hat aber keine Einschränkung

AUDIT_LOG

überhaupt keinen Primärschlüssel

legacy_notes

snake_case, während alles andere UPPER_CASE ist

Führen Sie audit_schema dagegen aus, und jeder dieser Punkte sollte auftauchen. Das ist die Demo: Die Tools finden echte Probleme, keine Spielzeugprobleme.


Ausführen

Der Explorer: jedes Primitive in einem Durchgang

bash scripts/run_explorer.sh

Gibt den initialize-Handshake aus, listet dann Tools, Ressourcen (statisch und vorlagenbasiert) und Prompts auf und übt sie. Führen Sie dies zuerst aus; es bestätigt, dass das Setup funktioniert, und zeigt die gesamte Protokolloberfläche auf einem Bildschirm.

Die Web-UI: alle drei Primitive im Browser

bash scripts/run_ui.sh          # http://127.0.0.1:8000
PORT=9000 bash scripts/run_ui.sh

Vier Panels, eines pro Sache, die es zu zeigen lohnt:

Panel

Was es demonstriert

Chat

in einfachem Englisch fragen; jedes Tool, das das Modell gewählt hat, wird inline über der Antwort aufgelistet

Tools

alle 12, gruppiert nach Wirkungsradius, jedes aus einem Formular aufrufbar

Ressourcen

statisch und vorlagenbasiert, direkt lesbar

Prompts

eines erweitern, um den Text zu sehen, oder direkt an den Chat senden

Ein Live-Aktivitäts-Streifen unten zeigt das echte JSON-RPC darunter, tools/call, resources/read, prompts/get, sodass das Protokoll die ganze Zeit sichtbar ist.

Die Seite ist selbst ein MCP-Client: Sie hat keinen eigenen Zugriff auf MySQL. Alles auf dem Bildschirm kam über dasselbe Protokoll, das Claude Desktop verwendet.

Chat benötigt ein lokales LLM über Ollama, kostenlos, ohne API-Schlüssel, und nichts verlässt die Maschine:

brew install ollama && ollama serve
ollama pull qwen2.5:7b

Setzen Sie stattdessen ANTHROPIC_API_KEY und es wechselt automatisch zur Claude-API. Die Panels Tools, Ressourcen und Prompts funktionieren ganz ohne LLM.

Der MCP Inspector: Anhtropic's eigener Client

bash scripts/run_inspector.sh

Öffnen Sie die gedruckte URL http://localhost:6274?...; das Token wird benötigt. Sie hat separate Registerkarten für Tools, Resources und Prompts, was die überzeugendste Art ist, alle drei zu zeigen: Nichts davon ist unser Code. Wenn der Inspector also den Server steuert, ist der Server wirklich spezifikationskonform.

Empfohlener Rundgang: Toolsdescribe_table mit ORDERS; Resourcesschema://overview; Promptsaudit_schema.

Claude Desktop / Claude Code

bash scripts/add_to_claude_desktop.sh    # Claude Desktop, run from Terminal.app
bash scripts/install_claude.sh           # Claude Code, safe to run anywhere

add_to_claude_desktop.sh sichert Ihre Konfiguration, erhält bereits registrierte Server, validiert das JSON, testet den exakten Startbefehl probehalber und startet die App neu. Wenn es fertig ist, gibt es ein vorgeschlagenes Demo-Skript aus.

Fragen Sie dann: "Audit this database", oder verwenden Sie den Prompt audit_schema aus dem Menü, wo Prompts endlich sichtbar werden.

--desktop muss aus Terminal.app heraus ausgeführt werden, nicht aus Claude Desktop heraus. Claude Desktop hält seine Konfiguration im Speicher und schreibt die Datei aus dieser Kopie neu, sodass eine Bearbeitung, die vorgenommen wird, während es läuft, stillschweigend verworfen wird. Das Skript beendet die App, bearbeitet und startet neu, was die Sitzung beenden würde, aus der es gestartet wurde.


Den Code lesen

Roughly eine Stunde für alles. Diese Reihenfolge baut ohne Vorwärtsverweise auf:

1. mcp_server/server.py: Fangen Sie hier an. Zehn aussagekräftige Zeilen, und die gesamte Architektur passt auf einen Bildschirm: Server erstellen, die drei Primitive registrieren, ausführen. Alles andere ist Detail.

2. mcp_server/database.py: Gewöhnlicher MySQL-Code ohne jegliches MCP. Es lohnt sich, das früh zu lesen, weil es zeigt, wie dünn die MCP-Schicht wirklich ist: Wenn Sie bereits eine Datenzugriffsschicht haben, sind Sie schon fast am Ziel.

Schauen Sie sich safe_identifier genau an. MySQL erlaubt es nicht, einen Tabellennamen als Parameter zu binden (SHOW CREATE TABLE %s ist kein gültiges SQL), daher müssen Bezeichner in den String interpoliert werden. Das ist ein echtes Injectionsrisiko, und diese eine kleine Funktion ist das, was es sicher macht.

3. mcp_server/tools.py: Der @mcp.tool()-Dekorator und die Idee, die in diesem gesamten Projekt die meiste Arbeit leistet: Der Docstring ist der Prompt. Er ist das Einzige, was das Modell liest, wenn es entscheidet, ob es ein Tool aufrufen soll, und ist daher für das Modell geschrieben und nicht für einen Menschen, der den Quellcode liest.

4. mcp_server/resources.py: Statische URIs gegenüber templatierten, und warum get_table_ddl sowohl als Tool als auch als Resource existiert. Diese Duplizierung ist bewusst gewählt und ist die klarste Veranschaulichung der Idee von Wer-steuert-was.

5. mcp_server/prompts.py: Prompts geben Text zurück, keine Daten. Der Text ist eine Anweisung, die dem Modell normalerweise sagt, welche Tools es verwenden soll. Kurze Datei und die, die die meisten Menschen noch nie gesehen haben.

6. mcp_server/execution.py: Lesen Sie dies, sobald Sie wissen möchten, wie Schreibzugriff sicher gemacht werden kann. Fünf Kontrollen, jede mit einem Kommentar, der erklärt, was sie verhindert.

7. examples/explore_server.py: Die andere Seite des Protokolls. Ein minimaler Client, der alles auflistet und aufruft, sodass Sie sehen können, was tatsächlich über die Leitung geht.


Weiterführendes

Dieser Server ist auf eine Datenbank beschränkt, um die Beispiele kurz zu halten. Um ihn weiterzuführen:

  • Mehrere Schemas: schema als Tool-Argument übernehmen, anstatt MYSQL_DEMO_SCHEMA zu lesen. Eine Whitelist hinzufügen, damit ein Agent nicht an die Produktion gelangen kann.

  • Abfrageausführung: Ein run_query-Tool. Machbar, aber es verändert die Sicherheitslage vollständig: Der Server benötigt dann Anmeldedaten, die Ihre Tabellen lesen können, und Ergebnisse gelangen in den Kontext des Modells. Nur SELECT erzwingen, ein LIMIT einfügen und einen schreibgeschützten Datenbankbenutzer verwenden.

  • Remote-Transport: mcp.run(transport="streamable-http"). Gleiche Tools, gleicher Code, andere Leitung. Authentifizierung hinzufügen, bevor Sie es offenlegen.

  • Caching: describe_table greift bei jedem Aufruf auf die Datenbank zu. Ein kurzer TTL-Cache lohnt sich, sobald ein Modell beginnt, es in einer Schleife aufzurufen.


Sicherheitshinweise

Dieser Server kann Ihre Daten ändern. Das ist beabsichtigt: „Kann ein Agent in meine Datenbank schreiben?" ist die Frage, die jedes Team stellt, und ein funktionierendes Beispiel dafür, wie es sicher geht, ist nützlicher als eines, das das Thema vermeidet. Aber es bedeutet auch, dass die Kontrollen wichtig sind.

Die fünf Kontrollen, alle in execution.py

Kontrolle

Was sie unterbindet

Schema-Sperre

jede Anweisung läuft auf einer Verbindung, die an die Demo-Datenbank gebunden ist; ein Verweis auf eine andere Datenbank wird verweigert

Eine Anweisung pro Aufruf

eine zweite Anweisung kann nicht auf einer legitimen mitfahren

Getrennte Lese-/Schreibtüren

run_query verweigert das Schreiben und execute_statement verweigert das Lesen, sodass keines zu der Aufgabe des anderen überredet werden kann

Zeilenbegrenzung

ein breites SELECT kann den Kontext des Modells nicht überfluten

Prüfprotokoll

jede Anweisung wird aufgezeichnet und ist über show_audit_log lesbar

Eine Denylist verweigert außerdem Anweisungen, die der Schema-Sperre entkommen würden, auf das Dateisystem zugreifen oder serverweiten Zustand ändern würden, sowie Rechteänderungen, Benutzerverwaltung, Dateiimport/-export und Datenbankebenen-Operationen.

Eine Feinheit, weil es ein Fehler ist, den man leicht wiederholt: Die Schema-Sperre kann nicht allein über Muster funktionieren. In SQL ist a.b normalerweise Alias.Spalte (SELECT c.NAME FROM CUSTOMERS c), nicht Schema.Tabelle, sodass das Ablehnen jedes Punktnamens gewöhnliche Joins bricht — genau der Fehler, den die erste Version davon hatte. Sie vergleicht nun jeden Qualifizierer mit der tatsächlichen Liste der Datenbanken auf dem Server: Ein echter Datenbankname wird verweigert, ein Tabellenalias passiert unverändert.

Auf einen eingeschränkten Benutzer zeigen

Die obigen Kontrollen sind Verteidigung in der Tiefe, nicht die Verteidigung. Verwenden Sie jenseits einer Demo einen MySQL-Benutzer, dessen Grant nur das Schema abdeckt, das Sie offenlegen möchten. Wenn die Anmeldedaten die Produktion nicht erreichen können, kann es auch eine Prompt-Injection oder ein Modellfehler nicht.

Zwei weitere Dinge, die klar ausgesprochen werden sollten:

  • Tabellennamen können keine gebundenen Parameter sein. SHOW CREATE TABLE %s ist kein gültiges SQL, daher müssen Bezeichner interpoliert werden — eine echte Injection-Stelle. database.safe_identifier ist das, was es sicher macht, und es ist die mit Abstand wichtigste Funktion im Projekt.

  • Der verbindende MySQL-Benutzer ist die eigentliche Grenze. Geben Sie ihm ein schreibgeschütztes GRANT, das auf die Schemas beschränkt ist, die Sie offenlegen möchten. Die Schreibgeschütztheit des Codes ist Verteidigung in der Tiefe, nicht die Verteidigung.


Lizenz

MIT, siehe LICENSE.

A
license - permissive license
Not graded
quality - not tested
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

  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables interaction with MySQL databases through MCP, supporting query execution, table operations (insert, update, delete), and schema inspection for natural language database management.
    121
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables MySQL database operations through MCP, including executing SQL queries, listing databases and tables, and describing table structures.
    454
    5
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables natural language interaction with MySQL databases through MCP, supporting SQL execution, schema exploration, and database management via tools, resources, and prompts.
    5
    MIT
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables natural language interaction with MySQL databases through MCP tools for querying, executing DDL/DML, listing databases/tables, and describing table schemas, with parameterized queries and read-only mode.
    454
    MIT

View all related MCP servers

Related MCP Connectors

  • GibsonAI MCP server: manage your databases with natural language

  • Connect to PlanetScale databases, branches, schema, query insights, and execute SQL

  • MCP server for managing Prisma Postgres.

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/Khushboo-Mishra/SQL-MCP-101'

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