shop-mcp
shop-mcp
ローカルで動作する読み取り専用のMCP(Model Context Protocol)サーバーです。AIエージェントがSQLiteのeコマースデータベース(shop.db)— 顧客、商品、注文、注文明細 — をstdioトランスポート経由で分析できるようにします。HTTPサーバーも別のデータベースプロセスも不要で、サーバーはshop.dbを直接開き、エージェントがスキーマを調査して独自の分析SQLを実行するための、小さく汎用的な2つのツールを公開します。
公式Python MCP SDK(PyPIのmcp)で構築されています。
プロジェクト構造
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.mdデータベーススキーマ(shop.dbで実際に確認される内容)
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はnew、processing、shipped、completed、cancelledに制約されています。products.categoryには現在5つの異なる値があります。外部キー:orders.customer_id → customers.id、order_items.order_id → orders.id、order_items.product_id → products.id。サーバーはこれらすべてをクエリ時にライブデータベースから取得します(sqlite_master / PRAGMA table_info / PRAGMA foreign_key_list経由)— ここにハードコードされたものは何もないため、shop.dbが別のスキーマを持つ別のファイルに置き換えられた場合、get_database_schemaは自動的にそれを反映します。
提供されたshop.dbの既知のデータ特性: customersにはcountry列がないため、「ドイツの顧客」のような質問には答えられません — スキーマツールでそれが判明し、query_databaseは推測する代わりに明確なno such column: countryエラーを返します。現在データベースにある750件の注文はすべて2026年の日付です(2025年はありません)。そのため「2025年の売上」クエリはエラーではなく、正しく0/nullを返します。
インストール
cd mcp-sql
python3 -m venv .venv
source .venv/bin/activate # on Windows: .venv\Scripts\activate
pip install -r requirements.txt設定
データベースパスはソースにハードコードされていません。次のように解決されます:
SHOP_DB_PATH環境変数が設定されている場合はそれを使用。それ以外の場合は
server.pyの隣のshop.db。
サーバーを別のデータベースファイルに向けたい場合は、.env.exampleを.envにコピーして編集します(シェル/エージェントランチャーに自分で読み込む必要があります。例:export $(cat .env | xargs)、またはSHOP_DB_PATHを直接設定します):
cp .env.example .env
# edit .env, or simply:
export SHOP_DB_PATH=/absolute/path/to/shop.db実行
source .venv/bin/activate
python server.pyプロセスはstdio上でMCPを話し、クライアントを待ちます — 出力がなく「固まっている」ように見えますが、これは想定どおりです。ターミナルで単独で実行するのではなく、MCPクライアント(AIエージェント、またはmcp-inspector、下記参照)を接続してください。
公式MCP Inspectorを使った簡単な手動確認(インストール不要):
npx @modelcontextprotocol/inspector --cli .venv/bin/python server.py --method tools/listAIエージェントに接続
ほとんどのMCP互換クライアント(Claude Desktop、Claude Codeなど)は、mcp-config.example.jsonのような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"
}
}
}
}注意:
venvのPythonインタープリタへの絶対パスを使用してください(上記のように)。これにより、venvを手動でアクティベートしなくても
mcpパッケージが見つかります。mcpが解決先の環境にインストールされていれば、素のpython3でも動作します。SHOP_DB_PATHはオプションです — 省略すると同梱のshop.dbが使用されます。絶対パスはこの設定ファイルに属します。これはサーバーを接続する人が提供するもので、
server.py自体には決して入れないでください。このブロックの配置場所はクライアントによって異なります(例:Claude Desktopは同じ
mcpServers構造のclaude_desktop_config.jsonを使用します。他のクライアントは内側の{"command": ..., "args": ..., "env": ...}オブジェクトだけを必要とする場合があります)。ファイルの場所についてはクライアントのドキュメントを確認してください。
テスト
source .venv/bin/activate
python -m pytest tests/ -vこれにより48のテストが実行されます。含まれるもの:
スキーマ検出(テーブル、列、PK/FK、リレーションシップ、行数);
SELECT、JOIN、WHERE、GROUP BY、ORDER BY、集計(COUNT/SUM/AVG/MIN/MAX)、サブクエリ、安全なWITH ... SELECTCTE、日付フィルタリング(strftime);行数制限のクランプとオフセットベースのページネーション;
無効なSQL、不明なテーブル/列、空のクエリ、データベースファイルの欠落に対する親切なエラー処理;
読み取り専用の安全性:課題に記載されたすべてのステートメントタイプ(
DELETE、UPDATE、DROP、CREATE、INSERT、さらにALTER、REPLACE、TRUNCATE、ATTACH、DETACH、VACUUM、REINDEX、破壊的なPRAGMA、スタックされたSELECT 1; DROP TABLE ...、WITH x AS (...) DELETE ...CTEで偽装された削除)が拒否され、データベースファイルの行数とSHA-256ハッシュがその後も変更されていないことが検証されます;tests/test_stdio_integration.pyはserver.pyを実際のサブプロセスとして起動し、実際のMCPクライアントSDKをstdio経由で駆動します(initialize→list_tools→call_tool)。Python関数を直接呼び出すのではなく、実際のエージェントが使用するのと同じ経路です。
MCPツール
get_database_schema()
パラメータなし。正確なテーブル/列名をまだ知らない場合は、まずこれを呼び出してください — 推測しないでください。テーブルごとにrow_count、columns(名前、SQLite型、not_null、default_value、is_primary_key)、primary_key、foreign_keys(列、参照先テーブル/列、ON DELETE/ON UPDATE)、およびエージェントが実際の日付形式、ステータス値、価格の規模などを確認できるようにするいくつかのsample_rowsを返します。トップレベルのrelationshipsリストは、ライブの外部キーから導出されたtable.column -> other_table.column文字列を提供します。
query_database(sql, limit=100, offset=0)
1つの読み取り専用SQLステートメント(SELECT、またはWITH ... SELECT)を実行し、{columns, rows, row_count, limit, offset, truncated, total_matching_rows}を返します。JOIN、WHERE、GROUP BY、ORDER BY、集計関数、サブクエリ、CTEをサポートします。limitは1..500にクランプされます(デフォルト100)。offsetを使用して大きな結果をページングします。total_matching_rowsとtruncatedは、現在のページが結果全体なのか、さらに取得するものがあるのかを呼び出し元に伝えます。エラー(構文エラー、不明なテーブル/列、拒否された書き込み試行)は、生のPythonトレースバックではなく、短く具体的なメッセージとして発生します。
セキュリティ:読み取り専用の強制方法
課題では単一の正規表現/キーワードチェックに依存しないことが明示的に求められているため、このサーバーは4つの独立した防御策を重ねています — tests/test_server.pyで検証済み:
OSレベルの読み取り専用ファイルハンドル。 SQLiteファイルはURI
file:<path>?mode=roで開かれます。SQLite自体がその後、実行されるSQLに関係なく、あらゆる書き込みを拒否します(OperationalError: attempt to write a readonly database)— これは以下のすべてのチェックにバグがあったとしても成立します。PRAGMA query_only = ONがすべての接続で設定され、書き込みに対する2番目の独立したSQLiteレベルのガードとなります。sqlite3オーソライザコールバック(Connection.set_authorizer)は、SQLiteエンジンレベルでSELECT/READ/FUNCTION/RECURSIVEアクションのみを許可リストに登録し、それ以外のすべてを拒否します —INSERT、UPDATE、DELETE、DROP、ALTER、CREATE、REPLACE、TRUNCATE、ATTACH、DETACH、VACUUM、REINDEX、PRAGMA、トランザクションなど。これは解析されたステートメントに対して実行されるため、素朴な「SELECTで始まる必要がある」テキストチェックでは見逃される古典的なCTEバイパスWITH x AS (SELECT 1) DELETE FROM ...も捕捉します。server.pyでのステートメント形状チェック:送信されたテキストはSELECT/WITHで始まる必要があり(SQLiteに触れる前の高速で親切な拒否)、すべてのクエリはSELECT * FROM (<query>) LIMIT :limit OFFSET :offsetとしてラップされて実行されます — これが解析されるには単一のステートメントが必要なため、スタックされたSELECT 1; DROP TABLE customersは2つの実行ステートメントではなく、単純なSQL構文エラーになります。
レイヤー1(mode=ro)はSQLite/OSによってこのサーバー自身のロジックとは独立に強制されるため、レイヤー2〜4にバグがあったとしても、このサーバーを通じてshop.dbを変更することはできません。
既知の制限
提供された
shop.dbのcustomersにはcountry/場所の列がないため、「ドイツの顧客」のような質問はこのデータからは答えられません — スキーマツールがこれを明らかにし、サーバーが列をでっち上げることはありません。提供されたデータのすべての注文は2026年の日付です。2025年の売上クエリはエラーではなく正しく0を返します。
query_databaseのtotal_matching_rowsは、同じクエリをラップする2番目のCOUNT(*)で計算されます。非常に高価なクエリの場合、作業がほぼ2倍になります。このデータベースのサイズ(テーブルあたり数百〜数千行)を考えると、これは実際的な問題ではありません。
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