shop-mcp
shop-mcp
로컬 전용 읽기 전용 MCP(Model Context Protocol) 서버로, AI 에이전트가 stdio 전송을 통해 SQLite 전자상거래 데이터베이스(shop.db) — 고객, 제품, 주문 및 주문 항목 — 를 분석할 수 있게 해줍니다. HTTP 서버나 별도의 데이터베이스 프로세스가 없습니다. 서버는 shop.db를 직접 열고, 에이전트가 스키마를 탐색하고 자체 분석 SQL을 실행할 수 있는 두 개의 작은 범용 도구를 노출합니다.
공식 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.mdRelated MCP server: shop-db MCP Server
데이터베이스 스키마(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)
하나의 읽기 전용 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 traceback이 아닙니다.
보안: 읽기 전용이 어떻게 강제되는가
과제는 단일 정규식/키워드 검사에 의존하지 말 것을 명시적으로 요구하므로, 이 서버는 네 가지 독립적인 방어 계층을 사용합니다 — tests/test_server.py에서 검증됨:
OS 수준 읽기 전용 파일 핸들. SQLite 파일은 URI
file:<path>?mode=ro로 열립니다. SQLite 자체는 어떤 SQL이 실행되든 쓰기를 거부합니다(OperationalError: attempt to write a readonly database) — 아래의 모든 검사에 버그가 있어도 유지됩니다.PRAGMA query_only = ON은 모든 연결에 설정되어 쓰기에 대한 두 번째 독립적인 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는 두 개의 실행된 문이 아니라 단순한 SQL 구문 오류가 됩니다.
계층 1(mode=ro)은 SQLite/OS가 이 서버의 자체 로직과 독립적으로 강제하므로, 계층 2-4에 버그가 있더라도 shop.db는 이 서버를 통해 수정될 수 없습니다.
알려진 제한 사항
제공된
shop.db의customers에는country/위치 열이 없으므로 "독일 고객"과 같은 질문은 이 데이터로 답할 수 없습니다 — 스키마 도구가 서버가 열을 임의로 만들지 않고 이 사실을 표면화합니다.제공된 데이터의 모든 주문은 2026년 날짜입니다. 2025년 매출 쿼리는 오류가 아닌 0을 올바르게 반환합니다.
query_database의total_matching_rows는 동일한 쿼리를 감싸는 두 번째COUNT(*)로 계산되므로, 매우 비싼 쿼리의 경우 작업량이 약 두 배가 됩니다. 이 데이터베이스의 크기(테이블당 수백에서 수천 행)를 고려하면 실질적인 문제는 아닙니다.
This server cannot be deployed
Maintenance
Related MCP Connectors
Query 40 databases from Claude, ChatGPT, or Cursor — on any device. Read-only, encrypted, audited.
Safe, read-only Postgres and MySQL access for AI agents. Audit log + column-level controls.
Text-to-SQL MCP server: read-only queries on PostgreSQL, MySQL and SQL Server with your real schema
Ask questions across Shopify, Klaviyo, GA4 and 20+ e-commerce sources in plain English.
Related MCP Servers
- FlicenseNot gradedqualityCmaintenanceProvides AI agents read-only analytical access to a SQLite database over stdio, with tools for listing tables, describing schemas, and running paginated SQL queries.-
- FlicenseAqualityBmaintenanceGives AI agents read-only analytical access to an e-commerce SQLite database (customers, orders, order_items, products) via SQL queries, table listing, and schema inspection.3-
- FlicenseAqualityCmaintenanceEnables AI agents to analyze an SQLite e-commerce database via secure read-only SQL queries, providing tools for table inspection and analytical requests.2-
- FlicenseNot gradedqualityCmaintenanceEnables AI agents to connect to a read-only SQLite e-commerce database via stdio, safely executing SELECT queries with schema exploration, sample data, pagination, and self-correcting error messages.-