Skip to main content
Glama

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.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.statusnew, 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

구성

데이터베이스 경로는 소스에 하드코딩되지 않습니다. 다음과 같이 결정됩니다:

  1. SHOP_DB_PATH 환경 변수가 설정된 경우 그 값;

  2. 그렇지 않으면 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/list

AI 에이전트에 연결

대부분의 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 ... SELECT CTE, 날짜 필터링(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.pyserver.py실제 하위 프로세스로 실행하고 실제 MCP 클라이언트 SDK를 통해 stdio로 구동합니다(initializelist_toolscall_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를 지원합니다. limit1..500(기본값 100)으로 제한됩니다. 더 큰 결과를 페이지로 나누려면 offset을 사용하세요. total_matching_rowstruncated는 현재 페이지가 전체 결과인지 아니면 더 가져올 것이 있는지 호출자에게 알려줍니다. 오류(잘못된 구문, 알 수 없는 테이블/열, 거부된 쓰기 시도)는 짧고 구체적인 메시지로 발생합니다 — 원시 Python traceback이 아닙니다.

보안: 읽기 전용이 어떻게 강제되는가

과제는 단일 정규식/키워드 검사에 의존하지 말 것을 명시적으로 요구하므로, 이 서버는 네 가지 독립적인 방어 계층을 사용합니다 — tests/test_server.py에서 검증됨:

  1. OS 수준 읽기 전용 파일 핸들. SQLite 파일은 URI file:<path>?mode=ro로 열립니다. SQLite 자체는 어떤 SQL이 실행되든 쓰기를 거부합니다(OperationalError: attempt to write a readonly database) — 아래의 모든 검사에 버그가 있어도 유지됩니다.

  2. PRAGMA query_only = ON 은 모든 연결에 설정되어 쓰기에 대한 두 번째 독립적인 SQLite 수준 가드 역할을 합니다.

  3. 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 ...도 잡아냅니다.

  4. 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.dbcustomers에는 country/위치 열이 없으므로 "독일 고객"과 같은 질문은 이 데이터로 답할 수 없습니다 — 스키마 도구가 서버가 열을 임의로 만들지 않고 이 사실을 표면화합니다.

  • 제공된 데이터의 모든 주문은 2026년 날짜입니다. 2025년 매출 쿼리는 오류가 아닌 0을 올바르게 반환합니다.

  • query_databasetotal_matching_rows는 동일한 쿼리를 감싸는 두 번째 COUNT(*)로 계산되므로, 매우 비싼 쿼리의 경우 작업량이 약 두 배가 됩니다. 이 데이터베이스의 크기(테이블당 수백에서 수천 행)를 고려하면 실질적인 문제는 아닙니다.

-
license - not tested
Not graded
quality - not tested
C
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 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.

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/AndrewKonst/shop-mcp'

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