ecommerce-mcp-server
by PUSHPIT1357
README.md
# ecommerce-mcp-server
An MCP (Model Context Protocol) server exposing e-commerce customer support
tools to LLM agents: product catalog search (hybrid full-text + vector
retrieval with cross-encoder reranking), order status/tracking, cart
management, a FAQ knowledge base, and human escalation via support tickets.
Built on FastAPI + the official `mcp` Python SDK, served over Streamable
HTTP, with API-key auth and per-client rate limiting applied as middleware.
Retrieval runs on Postgres + pgvector -- no separate vector database to run
or pay for. See [`SYSTEM_DESIGN.md`](./SYSTEM_DESIGN.md) for the reasoning
behind that and the retrieval pipeline design (RRF fusion + cross-encoder
rerank -- the same pattern used in the author's "Ledger" RAG project). See
[`HLD_LLD.md`](./HLD_LLD.md) for the full system design -- high-level
component/deployment views and low-level module, data-model, and
state-machine detail across the whole project.
## Architecture
```
Client (LLM agent / chat app)
│ HTTP + X-API-Key
▼
ApiKeyAuthMiddleware → RateLimitMiddleware → RequestLoggingMiddleware
│
▼
FastAPI app (src/mcp/server.py)
│ mounted at /mcp
▼
FastMCP server (src/mcp/registry.py)
│ tool calls
▼
src/tools/* → src/services/* → Postgres (products, FAQ)
│ + in-memory (cart, orders, tickets)
▼
src/rag/* (hybrid search: Postgres full-text search +
pgvector, RRF fusion, cross-encoder rerank)
```
Each layer has one job:
| Layer | Responsibility |
|---|---|
| `src/mcp/` | MCP server setup, tool registration, session helpers |
| `src/tools/` | Thin, testable functions with the docstrings/signatures the agent sees as tool schemas |
| `src/services/` | Business logic + data access, written against a small repository-style interface |
| `src/rag/` | Hybrid (Postgres full-text + pgvector) search with cross-encoder reranking |
| `src/db/` | SQLAlchemy async engine/session, ORM models, seed script |
| `src/models/` | Pydantic schemas shared across the app |
| `src/middleware/` | Auth, rate limiting, request logging |
| `src/core/` | Config, logging setup, exceptions, seed data |
**What's Postgres-backed vs. still in-memory, and why:** `products` and
`faq_entries` are real Postgres tables (see `migrations/versions/`) because
those are exactly the two things the RAG layer searches over, and search
quality is the part of this project meant to demonstrate real retrieval
engineering. `cart`, `order`, and `ticket` services are intentionally still
in-memory -- they're written against the same small async interface
(`get_by_id`, `list_all`, ...) the product service used to use, so
Postgres-backing them later is adding a new implementation and swapping an
import, not a redesign. That seam is deliberate, not an oversight; see
`src/services/cart_service.py`'s docstring.
## Tools exposed
| Tool | Description |
|---|---|
| `search_products` | Hybrid search over the catalog (name, description, tags) with category/price/stock filters |
| `get_product_details` | Full details for a single product by ID |
| `check_order_status` | Current status of an order |
| `track_shipment` | Carrier + tracking number + ETA for a shipped order |
| `cancel_order` | Cancel an order still in a cancellable state |
| `request_order_return` | Request a return for a delivered order |
| `view_cart` / `add_to_cart` / `remove_from_cart` / `update_cart_quantity` | Session-scoped cart management |
| `answer_faq` | Hybrid search over the FAQ knowledge base |
| `escalate_to_human` | Create a support ticket for human follow-up |
## Getting started
**With Docker Compose** (Postgres + Redis provisioned for you):
```bash
cp .env.example .env # edit at minimum: MCP_API_KEYS, GROQ_API_KEY
docker compose up -d postgres redis
docker compose run --rm app alembic upgrade head
docker compose run --rm app python -m src.db.seed
docker compose up app
```
**Without Docker** (Python 3.11+, and a Postgres instance with the
`vector` extension installable -- e.g. `CREATE EXTENSION vector;` once as
a superuser):
```bash
pip install -e ".[dev]"
cp .env.example .env
# point DATABASE_URL at your Postgres instance
alembic upgrade head # creates products/faq_entries with FTS + HNSW indexes
python -m src.db.seed # loads src/core/mock_data.py + computes embeddings
python server.py
# -> FastAPI on http://localhost:8000
# health check: GET /health (no auth required)
# MCP endpoint: POST /mcp (requires X-API-Key header)
```
The first call that touches search (`search_products` / `answer_faq`) will
lazily download the embedding and reranker models
(`sentence-transformers/all-MiniLM-L6-v2` and
`cross-encoder/ms-marco-MiniLM-L-6-v2` by default, both configurable via
`.env`) -- expect a one-time delay on cold start in a fresh environment.
`python -m src.db.seed` also needs these models, since it computes each
row's embedding before writing it.
## Testing
```bash
pytest # full suite
pytest tests/unit # fast, no DB or model downloads
pytest --cov=src --cov-report=term-missing
```
`tests/unit/test_pg_search.py` covers the Reciprocal Rank Fusion logic in
isolation (pure functions, no DB). The retrieval SQL itself (full-text
search, pgvector distance queries, `filter_products`) is covered against a
real Postgres instance rather than mocked -- `tsvector`/`vector` query
behavior isn't meaningfully testable without one. This was verified during
development against a live Postgres 16 + pgvector 0.6 instance: the
migration applied cleanly, the generated `search_vector` columns and HNSW
indexes were created as expected, and `search_products`/`answer_faq`
returned correctly ranked results end-to-end.
## Roadmap / not yet implemented
- Postgres-backed cart/order/ticket services (see the "what's Postgres-backed"
note above -- same seam the product service used before this pass)
- Redis-backed rate limiting for multi-instance deployments (currently
in-process token buckets)
- Groq-powered intent routing / query rewriting ahead of the MCP tool layer
- Session hardening (auth token expiry, per-session tool scoping)
- Kubernetes manifests (`deploy/k8s/`) -- Dockerfile + Compose exist,
k8s is the next step once there's a cluster to target
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues