ecommerce-mcp
# E-commerce MCP Server
Enterprise-ready [Model Context Protocol](https://modelcontextprotocol.io) server exposing catalog, cart, and checkout tools over FastMCP, backed by the public [Fake Store API](https://fakestoreapi.com).
## Features
- **8 MCP tools** — catalog search, cart lifecycle, and checkout with order confirmation
- **Strict Pydantic contracts** — validated inputs (range/length constraints) and structured outputs, never raw strings
- **Async everywhere** — `httpx.AsyncClient` with retry + exponential backoff for connection errors and `5xx`
- **Typed error taxonomy** — upstream failures surface as structured, human-readable tool errors
- **Fake Store adapter** — transparently maps Fake Store's native payloads (plain arrays, `title`/`category`/`image`, no pagination, no order endpoint) onto the project's schemas
- **Session-persistent carts** — lock-protected in-memory store, safe under concurrent tool calls
- **Layered architecture** — thin FastMCP entrypoint over isolated `models`, `services`, and `tools` layers
## Architecture
```
src/
├── server.py # Thin entrypoint: DI wiring + FastMCP registration (stdio + HTTP)
├── models/ # Strict Pydantic data contracts
│ ├── product.py # Product, ProductSummary, ProductListResponse
│ ├── cart.py # Cart, CartItem
│ └── checkout.py # CheckoutRequest, OrderConfirmation, pricing helpers
├── services/ # External I/O and mutable state
│ ├── store_api.py # Typed async client w/ retry, error taxonomy, Fake Store adapter
│ └── cart_store.py # Lock-protected, session-persistent cart store
└── tools/ # Class-based FastMCP tool handlers
├── catalog.py # list_products, get_product
├── cart.py # create_cart, get_cart, add_to_cart, update_cart_item, remove_cart_item
└── checkout.py # checkout
tests/
├── test_models.py # Model + pricing unit tests
├── test_server.py # Tool-surface integration tests (respx-mocked upstream)
└── test_fakestore_adapter.py # Fake Store payload adaptation tests
```
## Requirements
- Python >= 3.11
- [uv](https://docs.astral.sh/uv/) (package manager)
## Setup
```bash
uv sync # install deps (incl. dev group)
# .env is tracked; edit STORE_API_* values if you target a different upstream
uv run pytest # 57 tests
uv run ruff check . # lint
uv run mypy src tests # typecheck
```
## Configuration
`.env` is loaded by `pydantic-settings` at server start:
| Variable | Default | Description |
| --- | --- | --- |
| `STORE_API_BASE_URL` | `https://fakestoreapi.com` | Upstream store API base URL |
| `STORE_API_TIMEOUT_SECONDS` | `10` | Per-request read/connect timeout |
| `STORE_API_MAX_RETRIES` | `2` | Retries for connection errors and `5xx` |
When the base URL points at `fakestoreapi.com`, the client auto-adapts:
`title` → name, float `price` → decimal string, `category` → categories, `image` → image URL, `rating.count` → stock approximation; catalog pages are paginated locally; checkout submits to `POST /carts` (Fake Store has no order endpoint) and returns a locally-computed `OrderConfirmation`. Any other base URL is consumed as-is (paginated `{items, total, limit, offset}` listing and `POST /orders`).
## Running the server
### stdio (default MCP transport)
```bash
uv run python -c "import sys; sys.path.insert(0, 'src'); from server import main; main()"
```
### HTTP (Streamable HTTP, for Postman / remote clients)
```bash
uv run python -c "import sys; sys.path.insert(0, 'src'); from server import main_http; main_http()"
```
Serves `POST http://127.0.0.1:8765/mcp`.
## Claude Desktop
Add to `~/Library/Application Support/Claude/claude_desktop_config.json`:
```json
{
"mcpServers": {
"ecommerce-mcp": {
"command": "uv",
"args": [
"--directory",
"/absolute/path/to/ecommerce-mcp",
"run",
"python",
"-c",
"import sys; sys.path.insert(0, 'src'); from server import main; main()"
]
}
}
}
```
Restart Claude Desktop, then try: *"List products"*, *"Add 2 of product 1 to a cart"*, *"Checkout with Ada Lovelace, ada@example.com, London GB, card"*.
## Testing with Postman
The HTTP transport is session-based MCP. Send every request to `POST http://127.0.0.1:8765/mcp` with headers:
```
Content-Type: application/json
Accept: application/json, text/event-stream
```
**1. Initialize** (capture the `mcp-session-id` response header, then send it on all later requests):
```json
{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2025-06-18","capabilities":{},"clientInfo":{"name":"postman","version":"1.0"}}}
```
**2. List tools:**
```json
{"jsonrpc":"2.0","id":2,"method":"tools/list","params":{}}
```
**3. Call a tool:**
```json
{"jsonrpc":"2.0","id":3,"method":"tools/call","params":{"name":"list_products","arguments":{"limit":5,"offset":0}}}
```
Suggested demo flow: `list_products` → `create_cart` → `add_to_cart` → `get_cart` → `checkout`.
## Tools
| Tool | Description |
| --- | --- |
| `list_products` | Paginated catalog search (`limit` 1–100, `offset` ≥ 0) |
| `get_product` | Single product by id (≥ 1) |
| `create_cart` | New empty cart |
| `get_cart` | Snapshot of a cart |
| `add_to_cart` | Add/merge a product line (max 999 units/line) |
| `update_cart_item` | Overwrite a line quantity |
| `remove_cart_item` | Remove a line entirely |
| `checkout` | Place an order; returns `OrderConfirmation` with computed shipping/tax/total |
TDQS
Scored across 8 tools
Each tool targets a distinct action-resource pair: products (list/get), cart operations (create/get/add/update/remove), and checkout. No two tools overlap in purpose, making selection unambiguous.
All tools follow a consistent verb_noun pattern (list_products, get_product, create_cart, update_cart_item, remove_cart_item). 'checkout' is a clear, standard verb for the action, and the overall naming is predictable and readable.
With 8 tools, the server is well-scoped for ecommerce cart and catalog management. Each tool covers a necessary operation without redundancy or bloat, fitting the typical ideal range.
The tool set covers the full lifecycle of a cart (create, read, add/update/remove items, checkout) and product browsing (list, get). Minor gaps include no explicit delete-cart or order-history tool, but these are not critical for the core shopping flow.