shop-mcp

shop-mcp

A read-only MCP server that lets AI agents run safe, specialized analytics over an internet shop's SQLite database, covering customers, products, orders, and revenue. It exposes no generic SQL or write tools, so agents can answer questions without modifying data.

Category
访问服务器

README

shop-mcp

A read-only Model Context Protocol server that exposes analytics tools over the shop.db SQLite database of an internet shop (customers, products, orders, order items). It is designed to be connected to an AI agent so the agent can answer analytical questions about the data without ever being able to modify it.

The server speaks MCP over stdio, opens the database in read-only mode, and exposes a small set of specialised, parameterised tools whose descriptions encode the domain rules (which order statuses count as revenue, how a customer's country is derived, where money comes from). There is no generic SQL tool and no write tool — a destructive prompt such as "Delete all cancelled orders" cannot be executed.

The MCP server code in this repository was produced by an AI coding agent (Cursor), per the homework constraint that the server must not be written by hand.

Requirements

  • Python 3.11 or newer
  • The shop.db SQLite database (committed at database/shop.db)
  • uv (recommended) — runs the server in an isolated project environment with no global install. Install it with brew install uv (macOS) or curl -LsSf https://astral.sh/uv/install.sh | sh.

Install

With uv (recommended) — no manual venv or pip needed, uv resolves the project and its dependencies from pyproject.toml on first run:

uv sync          # create / refresh the project's .venv from pyproject.toml

Without uv — create a virtualenv and install the package yourself:

python3 -m venv .venv
source .venv/bin/activate        # Windows: .venv\Scripts\activate
pip install -e .

This installs the mcp SDK and the shop-mcp package (which provides the python -m shop_mcp entry point and the shop-mcp console script).

Configure

The server opens the database at database/shop.db relative to the process working directory (ProjectRoot). No environment variables are required.

When launched via uv run --directory <project> (see the client configs below), uv sets the working directory to the project root, so the committed database is found automatically.

If database/shop.db is missing, the server exits at startup with a clear configuration error that includes the current working directory (no stack trace, no silent fallback). Ensure your MCP client config sets cwd to the repository root.

Run

uv run python -m shop_mcp

or, with the package installed in an active venv:

python -m shop_mcp

or, equivalently:

shop-mcp

The server reads JSON-RPC over stdin and writes to stdout. You normally do not run it directly — your AI agent launches it for you (see below).

Connect to an agent

Ready-to-use MCP client configs are committed under examples/mcp/ and run with no setup beyond installing uv:

Client Config file
Cursor examples/mcp/cursor.json
Claude Desktop examples/mcp/claude_desktop.json
Generic stdio examples/mcp/generic_stdio.json
Canonical/default examples/mcp/shop.json
Docker examples/mcp/docker.json

Each config looks like this (replace the --directory path with the absolute path of this repo on your machine):

{
  "mcpServers": {
    "shop": {
      "command": "uv",
      "args": ["run", "--directory", "/path/to/internet-shop-mcp", "python", "-m", "shop_mcp"]
    }
  }
}

uv run --directory <project> sets the working directory to the project root and uses the project's .venv, so the server finds database/shop.db automatically. The same config is portable across machines (only the --directory path changes).

If you prefer not to use uv, install the package into a venv yourself (see Install), use command: "python", and set cwd to the repository root in your MCP client config.

  • Cursor: open Settings → MCP → Add MCP Server and paste the contents of examples/mcp/cursor.json (or use the Project MCP scope and commit it).
  • Claude Desktop: copy the contents of examples/mcp/claude_desktop.json into claude_desktop_config.json (macOS: ~/Library/Application Support/Claude/claude_desktop_config.json).
  • Generic stdio client: use examples/mcp/generic_stdio.json with any client that speaks MCP over stdio.

After connecting, the agent sees eight tools: list_tables, describe_table, count_customers_by_country, rank_countries_by_customers, top_customers, top_products, revenue_by_category, revenue_by_year.

Tools

Tool Answers
list_tables Task 1 — list tables and what each contains
describe_table(table) schema of one table
count_customers_by_country(country?) Task 2 — customers from a country
rank_countries_by_customers(limit) Task 3 — country with the most customers
top_customers(by, limit, offset) Tasks 4 & 8 — top spender / most orders
top_products(limit, metric, offset) Task 5 — top best-selling products
revenue_by_category(limit, offset) Task 6 — top categories by revenue
revenue_by_year(year) Task 7 — revenue for a year

Domain rules baked into the tool descriptions (see CONTEXT.md and docs/adr/ for the full rationale):

  • Country is derived from the customer's phone-number prefix (E.164). There is no country column. +49 → Germany, +7 → Russia. An unrecognised prefix maps to unknown. The tool accepts a full name ("Germany") or an ISO alpha-2 code ("DE") and returns both.
  • Revenue / spend count only completed and shipped orders.
  • Most orders counts every order status except cancelled.
  • Best-selling ranks products by units sold; revenue is a secondary field.
  • Money comes from orders.total_amount for order/customer/year rollups and from SUM(order_items.quantity * order_items.unit_price) for product/category rollups (the actual sale price, not the current products.price).
  • Limits default to 100 and are clamped to a maximum of 1000; offset paginates.
  • Errors are returned to the agent as short plain messages (e.g. Invalid year: must be a 4-digit integer); stack traces go to stderr only.

Safety

The database is read-only by construction:

  • SQLite is opened with file:<path>?mode=ro (uri=True), so any write attempt raises sqlite3.OperationalError: attempt to write a readonly database.
  • PRAGMA query_only = 1 is set as defense in depth.
  • No write or generic-SQL tool is exposed. The only tools are the eight read-only analytics tools above.

A test (tests/test_safety.py) asserts that a write attempt raises, that no write tool is advertised, and that the database file is byte-for-byte unchanged after every tool runs.

End-to-end verification

The eight homework tasks were verified against a connected AI agent. Expected results on the committed data (150 customers, all with +7 numbers; 750 orders, all dated 2026):

  1. List all tables — list_tables returns customers, products, orders, order_items with a description each.
  2. How many customers are from Germany? — count_customers_by_country("Germany") → 0 (honest zero; no customer has a +49 number).
  3. Which country has the most customers? — rank_countries_by_customers → Russia (RU), 150 customers.
  4. Who spent the most money? — top_customers(by="spend", limit=1) → Полина Козлов, polina.kozlov340@icloud.com, total spend 531810.0.
  5. Top 5 best-selling products — top_products(limit=5) → ranked by units sold (Эспандер плечевой, Планшет Tab 10, …) with revenue alongside.
  6. Top 3 categories by revenue — revenue_by_category(limit=3) → Электроника, Бытовая техника, Одежда и обувь.
  7. Revenue in 2025 — revenue_by_year(2025) → 0 with the note no orders in 2025 (no year substitution; all orders are 2026).
  8. Most orders — top_customers(by="order_count", limit=1) → София Яковлев, sofiya.yakovlev284@yandex.ru, 15 orders.

The destructive prompt "Delete all cancelled orders" is refused: there is no tool that accepts it, and the read-only connection rejects any write at the SQLite level.

Tests

uv run --extra dev pytest
# or, with the package installed in an active venv:
pip install -e ".[dev]"
python -m pytest

The suite covers: the smoke test (server starts over stdio and answers a handshake/list_tools), every tool's happy path, the domain rules (revenue excludes non-earned statuses, order count excludes cancelled, products rank by units), edge cases (Germany → 0, 2025 → 0 with note, unknown country, invalid year/metric/by, limit clamping, pagination), and the safety guarantees (write attempt raises, no write tools, database file unchanged).

Docker (bonus)

See the "Docker" section below for a containerised run.

Project layout

internet-shop-mcp/
├── database/
│   └── shop.db                  # the read-only database
├── pyproject.toml               # package + dependency declaration
├── README.md
├── CONTEXT.md                   # domain glossary
├── docs/adr/                    # ADR-0001..0005
├── src/shop_mcp/
│   ├── __main__.py              # `python -m shop_mcp`
│   ├── main.py                  # server wiring + tool registration
│   ├── config.py                # database/shop.db resolution
│   ├── db.py                    # read-only SQLite connection
│   ├── country.py               # phone-prefix → country mapping
│   └── tools.py                 # tool implementations
├── tests/                       # pytest suite mirroring src
├── examples/mcp/                # agent connection configs
├── Dockerfile
└── .dockerignore

Docker

Build and run the server in a container. The database is copied into the image at /app/database/shop.db (same convention as local dev).

docker build -t shop-mcp .
docker run --rm -i shop-mcp

A matching MCP client config using Docker:

{
  "mcpServers": {
    "shop": {
      "command": "docker",
      "args": ["run", "--rm", "-i", "shop-mcp"]
    }
  }
}

To mount your own database instead of the bundled one:

docker run --rm -i -v "$PWD/database:/app/database:ro" shop-mcp

The read-only guarantees are preserved inside the container: the connection uses mode=ro and query_only=1, and a destructive prompt is still refused.

推荐服务器

Baidu Map

Baidu Map

百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。

官方
精选
JavaScript
Playwright MCP Server

Playwright MCP Server

一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。

官方
精选
TypeScript
Magic Component Platform (MCP)

Magic Component Platform (MCP)

一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。

官方
精选
本地
TypeScript
Audiense Insights MCP Server

Audiense Insights MCP Server

通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。

官方
精选
本地
TypeScript
VeyraX

VeyraX

一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。

官方
精选
本地
graphlit-mcp-server

graphlit-mcp-server

模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。

官方
精选
TypeScript
Kagi MCP Server

Kagi MCP Server

一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。

官方
精选
Python
e2b-mcp-server

e2b-mcp-server

使用 MCP 通过 e2b 运行代码。

官方
精选
Neon MCP Server

Neon MCP Server

用于与 Neon 管理 API 和数据库交互的 MCP 服务器

官方
精选
Exa MCP Server

Exa MCP Server

模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。

官方
精选