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 linesDer 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.shsetup.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.shVoraussetzungen
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 |
| jede Tabelle und Sicht, mit Zeilenschätzungen |
| Spalten, Typen, Schlüssel, Indizes, Fremdschlüssel |
| das exakte |
| jeder deklarierte Fremdschlüssel |
| Spalten, deren Name auf PII oder Geheimnisse hindeutet |
| 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 |
| eine SELECT-Abfrage ausführen und die Zeilen zurückbekommen; das beantwortet Datenfragen |
| INSERT / UPDATE / DELETE / CREATE / ALTER / DROP / TRUNCATE |
| strukturiertes Einfügen, Werte als gebundene Parameter gesendet |
| strukturiertes Update, |
| strukturiertes Löschen, |
| 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 |
| JSON | Tabelleninventar |
| SQL | DDL für das gesamte Schema |
| JSON | alle Fremdschlüssel |
| Markdown | menschenlesbare Zusammenfassung |
| JSON | eine Tabelle (vorlagenbasiert) |
| 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 |
| keine | fünfstufiger Gesundheitscheck: Schlüssel, Beziehungen, PII, Benennung |
|
| erklärt eine Tabelle in einfacher Sprache |
|
| schreibt die Abfrage, führt sie aus und antwortet in einfacher Sprache |
|
| Vorschau → Bestätigen → Anwenden → Verifizieren, für Änderungen |
| keine | generiert Referenzdokumentation |
|
| 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 |
|
|
|
|
| (sauber, das Referenzbeispiel) |
|
|
| überhaupt keinen Primärschlüssel |
|
|
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.shGibt 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.shVier 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:7bSetzen 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: Tools → describe_table mit ORDERS; Resources →
schema://overview; Prompts → audit_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 anywhereadd_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.
--desktopmuss 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:
schemaals Tool-Argument übernehmen, anstattMYSQL_DEMO_SCHEMAzu 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. NurSELECTerzwingen, einLIMITeinfü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_tablegreift 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 |
|
Zeilenbegrenzung | ein breites |
Prüfprotokoll | jede Anweisung wird aufgezeichnet und ist über |
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 %sist kein gültiges SQL, daher müssen Bezeichner interpoliert werden — eine echte Injection-Stelle.database.safe_identifierist 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.
This server cannot be installed
Maintenance
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
- AlicenseNot gradedqualityDmaintenanceEnables interaction with MySQL databases through MCP, supporting query execution, table operations (insert, update, delete), and schema inspection for natural language database management.121MIT
- AlicenseNot gradedqualityDmaintenanceEnables MySQL database operations through MCP, including executing SQL queries, listing databases and tables, and describing table structures.4545MIT
- AlicenseNot gradedqualityDmaintenanceEnables natural language interaction with MySQL databases through MCP, supporting SQL execution, schema exploration, and database management via tools, resources, and prompts.5MIT
- AlicenseNot gradedqualityCmaintenanceEnables 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.454MIT
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.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
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