shop-mcp
shop-mcp
Ein lokaler, schreibgeschützter MCP-Server (Model Context Protocol), der es einem KI-Agenten ermöglicht, eine SQLite-E-Commerce-Datenbank (shop.db) zu analysieren – Kunden, Produkte, Bestellungen und Bestellpositionen – über den stdio-Transport. Kein HTTP-Server, kein separater Datenbankprozess: Der Server öffnet shop.db direkt und stellt zwei kleine, allgemein einsetzbare Tools bereit, mit denen ein Agent das Schema erkunden und eigene analytische SQL-Abfragen ausführen kann.
Erstellt mit dem offiziellen Python-MCP-SDK (mcp auf PyPI).
Projektstruktur
mcp-sql/
├── server.py # the MCP server (stdio transport)
├── shop.db # SQLite database (not modified by this project)
├── requirements.txt
├── .env.example
├── mcp-config.example.json
├── tests/
│ ├── conftest.py
│ ├── test_server.py # unit tests (call tool functions directly)
│ └── test_stdio_integration.py# protocol-level test (spawns server.py over stdio)
└── README.mdDatenbankschema (wie tatsächlich in shop.db vorgefunden)
customers(id PK, first_name, last_name, email UNIQUE, phone, created_at)
products(id PK, name, category, price, stock_quantity, created_at)
orders(id PK, customer_id -> customers.id, order_date, status, total_amount)
order_items(id PK, order_id -> orders.id, product_id -> products.id, quantity, unit_price)orders.status ist auf folgende Werte beschränkt: new, processing, shipped, completed, cancelled. products.category hat derzeit 5 verschiedene Werte. Fremdschlüssel: orders.customer_id → customers.id, order_items.order_id → orders.id, order_items.product_id → products.id. Der Server leitet all dies zur Abfragezeit aus der Live-Datenbank ab (über sqlite_master / PRAGMA table_info / PRAGMA foreign_key_list) – nichts davon ist fest codiert. Wenn shop.db also durch eine andere Datei mit einem anderen Schema ersetzt wird, spiegelt get_database_schema dies automatisch wider.
Bekannte Datenmerkmale der bereitgestellten shop.db: customers hat keine Spalte country, daher können Fragen wie „Kunden aus Deutschland“ nicht beantwortet werden – das Schema-Tool macht dies erkennbar, und query_database gibt einen klaren Fehler no such column: country zurück, anstatt zu raten. Alle 750 derzeit in der Datenbank vorhandenen Bestellungen sind auf 2026 datiert (keine im Jahr 2025), sodass eine Abfrage nach „Umsatz 2025“ korrekt 0/null zurückgibt, keinen Fehler.
Installation
cd mcp-sql
python3 -m venv .venv
source .venv/bin/activate # on Windows: .venv\Scripts\activate
pip install -r requirements.txtKonfiguration
Der Datenbankpfad ist im Quellcode nie fest codiert. Er wird wie folgt aufgelöst:
die Umgebungsvariable
SHOP_DB_PATH, falls gesetzt;andernfalls
shop.dbnebenserver.py.
Kopieren Sie .env.example nach .env und bearbeiten Sie es, wenn Sie den Server auf eine andere Datenbankdatei verweisen möchten (Sie müssen es selbst in Ihre Shell/Agenten-Startumgebung laden, z. B. export $(cat .env | xargs), oder einfach SHOP_DB_PATH direkt setzen):
cp .env.example .env
# edit .env, or simply:
export SHOP_DB_PATH=/absolute/path/to/shop.dbAusführen
source .venv/bin/activate
python server.pyDer Prozess spricht MCP über stdio und wartet auf einen Client – er wirkt „hängend“ ohne Ausgabe, was erwartet ist: Verbinden Sie einen MCP-Client (einen KI-Agenten oder mcp-inspector, siehe unten), anstatt ihn eigenständig in einem Terminal auszuführen.
Schnelle manuelle Überprüfung mit dem offiziellen MCP Inspector (keine Installation erforderlich):
npx @modelcontextprotocol/inspector --cli .venv/bin/python server.py --method tools/listMit einem KI-Agenten verbinden
Die meisten MCP-kompatiblen Clients (Claude Desktop, Claude Code usw.) lesen einen JSON-Konfigurationsblock wie mcp-config.example.json:
{
"mcpServers": {
"shop-mcp": {
"command": "/absolute/path/to/mcp-sql/.venv/bin/python",
"args": ["/absolute/path/to/mcp-sql/server.py"],
"env": {
"SHOP_DB_PATH": "/absolute/path/to/mcp-sql/shop.db"
}
}
}
}Hinweise:
Verwenden Sie den absoluten Pfad zum Python-Interpreter der venv (wie oben), damit das Paket
mcpgefunden wird, ohne die venv manuell zu aktivieren; ein nacktespython3funktioniert ebenfalls, wennmcpin der Umgebung installiert ist, auf die es aufgelöst wird.SHOP_DB_PATHist optional – weglassen, um die mitgelieferteshop.dbzu verwenden.Absolute Pfade gehören in diese Konfigurationsdatei, die von demjenigen bereitgestellt wird, der den Server verbindet – niemals in
server.pyselbst.Die client-spezifische Platzierung dieses Blocks variiert (z. B. verwendet Claude Desktop
claude_desktop_config.jsonmit derselbenmcpServers-Form; andere Clients möchten möglicherweise nur das innere Objekt{"command": ..., "args": ..., "env": ...}). Überprüfen Sie die Dokumentation Ihres Clients, wo die Datei liegt.
Testen
source .venv/bin/activate
python -m pytest tests/ -vDies führt 48 Tests aus, darunter:
Schema-Erkennung (Tabellen, Spalten, PK/FK, Beziehungen, Zeilenanzahlen);
SELECT,JOIN,WHERE,GROUP BY,ORDER BY, Aggregatfunktionen (COUNT/SUM/AVG/MIN/MAX), Unterabfragen, ein sicheresWITH ... SELECT-CTE und Datumsfilterung (strftime);Begrenzung der Zeilenanzahl und Offset-basierte Paginierung;
verständliche Fehlerbehandlung für ungültiges SQL, unbekannte Tabellen/Spalten, eine leere Abfrage und eine fehlende Datenbankdatei;
Schreibschutz-Sicherheit: Jeder in der Aufgabenstellung aufgeführte Anweisungstyp (
DELETE,UPDATE,DROP,CREATE,INSERT, plusALTER,REPLACE,TRUNCATE,ATTACH,DETACH,VACUUM,REINDEX, ein destruktivesPRAGMA, ein gestapeltesSELECT 1; DROP TABLE ...und ein als CTE getarntesWITH x AS (...) DELETE ...) wird abgelehnt, und die Zeilenanzahlen sowie der SHA-256-Hash der Datenbankdatei werden danach als unverändert bestätigt;tests/test_stdio_integration.pystartetserver.pyals echten Subprozess und steuert ihn über das tatsächliche MCP-Client-SDK über stdio (initialize→list_tools→call_tool), anstatt Python-Funktionen direkt aufzurufen – dies ist derselbe Pfad, den ein echter Agent verwendet.
MCP-Tools
get_database_schema()
Keine Parameter. Rufen Sie dies zuerst auf, wenn Sie die genauen Tabellen-/Spaltennamen nicht bereits kennen – raten Sie nicht. Gibt pro Tabelle zurück: row_count, columns (Name, SQLite-Typ, not_null, default_value, is_primary_key), primary_key, foreign_keys (Spalte, referenzierte Tabelle/Spalte, ON DELETE/ON UPDATE) sowie einige sample_rows, damit der Agent echte Datumsformate, Statuswerte, Preisgrößen usw. sehen kann. Eine Liste relationships auf oberster Ebene gibt Zeichenfolgen der Form table.column -> other_table.column an, die aus den Live-Fremdschlüsseln abgeleitet werden.
query_database(sql, limit=100, offset=0)
Führt eine einzelne schreibgeschützte SQL-Anweisung aus (SELECT oder WITH ... SELECT) und gibt {columns, rows, row_count, limit, offset, truncated, total_matching_rows} zurück. Unterstützt JOIN, WHERE, GROUP BY, ORDER BY, Aggregatfunktionen, Unterabfragen und CTEs. limit wird auf 1..500 begrenzt (Standard 100); verwenden Sie offset, um durch größere Ergebnisse zu blättern. total_matching_rows und truncated teilen dem Aufrufer mit, ob die aktuelle Seite das gesamte Ergebnis ist oder ob weitere Daten abgerufen werden müssen. Fehler (falsche Syntax, unbekannte Tabelle/Spalte oder ein abgelehnter Schreibversuch) werden als kurze, spezifische Meldung ausgegeben – niemals als roher Python-Traceback.
Sicherheit: Wie der Schreibschutz durchgesetzt wird
Die Aufgabenstellung verlangt ausdrücklich, sich nicht auf eine einzelne Regex-/Schlüsselwortprüfung zu verlassen. Daher schichtet dieser Server vier unabhängige Verteidigungslinien – verifiziert in tests/test_server.py:
Schreibgeschützter Dateihandle auf Betriebssystemebene. Die SQLite-Datei wird mit der URI
file:<path>?mode=rogeöffnet. SQLite selbst verweigert dann jeden Schreibzugriff (OperationalError: attempt to write a readonly database), unabhängig davon, welches SQL ausgeführt wird – dies gilt selbst dann, wenn jede der folgenden Prüfungen einen Fehler aufweist.PRAGMA query_only = ONwird auf jeder Verbindung als zweite, unabhängige SQLite-Ebene gegen Schreibzugriffe gesetzt.Ein
sqlite3-Autorisierungs-Callback (Connection.set_authorizer) erlaubt nur die AktionenSELECT/READ/FUNCTION/RECURSIVEauf SQLite-Engine-Ebene und verweigert alles andere –INSERT,UPDATE,DELETE,DROP,ALTER,CREATE,REPLACE,TRUNCATE,ATTACH,DETACH,VACUUM,REINDEX,PRAGMA, Transaktionen usw. Dies läuft auf der geparsten Anweisung, sodass es auch den klassischen CTE-BypassWITH x AS (SELECT 1) DELETE FROM ...abfängt, den eine naive Textprüfung „muss mit SELECT beginnen“ übersehen würde.Anweisungsform-Prüfungen in
server.py: Der übermittelte Text muss mitSELECT/WITHbeginnen (schnelle, verständliche Ablehnung vor dem Zugriff auf SQLite), und jede Abfrage wird alsSELECT * FROM (<query>) LIMIT :limit OFFSET :offsetausgeführt – für das Parsen ist genau eine Anweisung erforderlich, sodass ein gestapeltesSELECT 1; DROP TABLE customerszu einem einfachen SQL-Syntaxfehler wird, anstatt zwei Anweisungen auszuführen.
Da Ebene 1 (mode=ro) von SQLite/Betriebssystem unabhängig von der eigenen Logik des Servers durchgesetzt wird, kann shop.db über diesen Server nicht verändert werden, selbst wenn in den Ebenen 2–4 ein Fehler existierte.
Bekannte Einschränkungen
customershat in der bereitgestelltenshop.dbkeine Spaltecountry/Standort, sodass Fragen wie „Kunden aus Deutschland“ aus diesen Daten nicht beantwortet werden können – das Schema-Tool macht dies sichtbar, anstatt dass der Server eine Spalte erfindet.Alle Bestellungen in den bereitgestellten Daten sind auf 2026 datiert; eine Umsatzabfrage für 2025 gibt korrekt 0 zurück, keinen Fehler.
total_matching_rowsinquery_databasewird mit einem zweitenCOUNT(*)berechnet, das dieselbe Abfrage umschließt; bei sehr teuren Abfragen verdoppelt dies den Aufwand ungefähr. Angesichts der Größe dieser Datenbank (Hunderte bis wenige Tausend Zeilen pro Tabelle) ist dies kein praktisches Problem.
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 Connectors
Run AI customer support from your terminal: conversations, knowledge base, and chat widget.
Read-only bank access for your AI agent. Connects Claude, ChatGPT, Cursor, Gemini, Codex.
Query PostgreSQL databases in plain English — LLM-generated, safety-validated SQL.
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/AndrewKonst/shop-mcp'
If you have feedback or need assistance with the MCP directory API, please join our Discord server