Skip to main content
Glama
NyokolodiK

ecommerce-mcp

by NyokolodiK
README.md
# 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

A3.9/5.0

Scored across 8 tools

Disambiguation5/5

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.

Naming Consistency5/5

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.

Tool Count5/5

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.

Completeness4/5

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.

Maintenance

ActivitySlowing
ResponsivenessNo issues