AMIRI Commercial Analytics MCP
by maevelynz
README.md
# AMIRI Commercial Analytics MCP
A local-first, interview-ready **Model Context Protocol (MCP)** server for a luxury fashion commercial analytics team.
It turns executive questions such as:
> “SS26 is six weeks old. What should we chase, what is becoming markdown risk, and is wholesale demand actually healthy?”
into calls to **governed, deterministic analytics tools** over a synthetic DTC + owned-retail + wholesale data model.
> **Important:** every row in this repository is synthetic. This is a methodology demonstration shaped like a modern luxury-commerce analytics environment; it is not AMIRI internal data or a claim about AMIRI's actual KPIs.
## Live Executive Demo
**[Launch the SS26 Executive Review →](https://claude.ai/code/artifact/91b7347e-4cb8-4195-911c-b0b4c4fc81e5)**
Explore the interactive executive experience for commercial performance, sell-through, returns, wholesale health, inventory, and decision support.
> All company, customer, product, and transaction data shown in the demo is synthetic and created solely for demonstration purposes.
## Why this project exists
The role is not just “build dashboards.” It is an operating-model problem: move from ad-hoc reporting toward a disciplined commercial analytics rhythm, give executives a consistent view across retail/e-commerce/wholesale/client data, define KPI frameworks, and pilot AI-assisted analytics with transparency and measurable value.
This project is deliberately designed around that job:
- **Executive rhythm:** weekly flash, exceptions, and decision prompts.
- **Merchandising:** aligned-week sell-through, chase vs hold vs markdown risk.
- **E-commerce:** return-rate root cause with metric-validation and cohort discipline.
- **Retail:** comparable-store growth vs total growth so new doors cannot hide comp softness.
- **Wholesale:** sell-in vs sell-through, reorder health, stuffing warning.
- **Clienteling/marketing:** adjusted descriptive clienteling read + causal warning; promo pull-forward check.
- **Finance:** channel-specific P&L instead of one misleading blended margin.
- **Governance:** named metrics, provenance, explicit caveats, synthetic-data flag, no unrestricted `run_sql` tool.
## Architecture

```text
synthetic source-shaped CSVs -> governed analytics -> FastMCP tools -> MCP host / LLM
^ ^
manifest + SHA256 metric_catalog.csv
```
The design deliberately separates **reasoning** from **calculation**. The host LLM decides which tool to call and how to synthesize the evidence; `analytics.py` owns the governed math. See [`docs/CODE_WALKTHROUGH.md`](docs/CODE_WALKTHROUGH.md) for the file-by-file explanation.
Production evolution would be:
```text
Shopify / POS / wholesale / clienteling sources
-> Airbyte / ingestion
-> BigQuery
-> dbt staging -> intermediate -> marts
-> tested semantic metrics
-> MCP analytics service
-> authorized AI host / internal UI
```
The MCP server does **not** call an LLM. The host LLM decides which tool to call; the analytics layer computes the numbers. This keeps reasoning and metric computation separate.
See [`docs/PROBLEM_MAP.md`](docs/PROBLEM_MAP.md) for the stakeholder-by-stakeholder problem/decision map.
## Tools
| Tool | Executive question it answers |
|---|---|
| `exec_flash_summary` | What changed commercially this week, and what needs a decision? |
| `sell_through_tracker` | What should we chase, hold, or move toward markdown? |
| `return_rate_rootcause` | Is the return spike real, where is it localized, and what likely changed? |
| `data_quality_checks` | Can I trust today's numbers before I diagnose them? |
| `channel_pnl` | Which channel is actually attractive after channel-specific economics? |
| `wholesale_health` | Is strong wholesale sell-in translating into consumer sell-through and reorders? |
| `comp_store_sales` | Are stores improving, or are new doors masking comp softness? |
| `markdown_risk` | Where are weeks-of-cover and inventory dollars becoming dangerous? |
| `customer_analytics` | Is clienteling associated with better customer economics after reducing obvious selection bias? |
| `promo_pullforward_check` | Did a promotion create incremental demand or pull full-price demand forward? |
| `cannibalization_check` | How would we test whether a new owned store hurts a nearby wholesale partner? |
| `executive_decision_room` | Which governed tools answer each executive stakeholder's recurring questions? |
| `list_metrics` | What definitions, grains, owners, and caveats govern the KPIs? |
| `suggest_questions` | What should I ask in a demo? |
## Seeded stories you can demonstrate
The generator is deterministic **and byte-verifiable**. It uses seed `260829`, writes `data/manifest.json` with SHA-256 hashes, and ships `src/verify_reproducibility.py`, which generates two independent temporary copies and compares both with the checked-in CSVs. A fresh rebuild intentionally creates several cases the tools should uncover:
1. **Return anomaly:** SS26 `MX1 Hero Denim`, DTC, late in the drop, with sizing dominating the reason mix and the largest seeded deterioration in `US_West`. The tool uses a non-overlapping 3-week recent / 4-week prior baseline, a minimum-volume gate, geography drill-down, suggested actions, and a fixed-cohort measurement plan.
2. **Pipeline bug:** six duplicated return rows that `data_quality_checks` catches; governed return-rate math dedupes first.
3. **Chase vs markdown:** fast hero styles and slow styles inside the same current collection.
4. **Wholesale sell-in trap:** synthetic partner `Northstar Luxury` has high sell-in, ~25% sell-through, and no reorders.
5. **Retail mix trap:** total retail is much healthier than comp-store growth because a new Milan door adds revenue.
6. **Promo pull-forward:** a private-client event spikes the promo week and softens the next two weeks.
These are not random Easter eggs. Each corresponds to a real analytical judgment an interviewer can probe.
## Quick start — local analytics first
### Preferred: `uv`
```bash
cd amiri_commercial_analytics_mcp
uv sync # first run resolves dependencies; if uv.lock exists, it uses it
uv run python src/make_data.py
uv run python src/verify_reproducibility.py
uv run python -m unittest discover -s tests -v
uv run python src/cli.py all
```
Or run the one-command health check:
```bash
./scripts/setup_and_test.sh
```
### Pip fallback
```bash
python3 -m venv .venv
source .venv/bin/activate
pip install -r requirements.txt
python src/make_data.py
python src/verify_reproducibility.py
python -m unittest discover -s tests -v
python src/cli.py all
```
**Dependency-lock note:** `pyproject.toml` is included and FastMCP is pinned to the current stable `3.4.6`. This build environment has no package-registry network access, so I could not honestly generate a resolved `uv.lock` here. On the first networked local `uv sync`, uv will create it; commit that file before publishing. Do not use `--frozen` until the lock exists.
If the generator, reproducibility check, tests, and CLI all pass, the business logic is working independently of the MCP host.
## Start the MCP server
```bash
python src/mcp_server.py
```
The process uses stdio and waits for an MCP client.
### MCP Inspector
If Node/npm is installed:
```bash
npx @modelcontextprotocol/inspector .venv/bin/python src/mcp_server.py
```
Invoke the tools manually in Inspector before debugging an AI host. That isolates “analytics problem” from “MCP connection problem.”
## Claude Desktop configuration
macOS configuration file:
```text
~/Library/Application Support/Claude/claude_desktop_config.json
```
Example:
```json
{
"mcpServers": {
"amiri-commercial-analytics": {
"command": "/ABSOLUTE/PATH/amiri_commercial_analytics_mcp/.venv/bin/python",
"args": [
"/ABSOLUTE/PATH/amiri_commercial_analytics_mcp/src/mcp_server.py"
],
"env": {
"AMIRI_DATA_DIR": "/ABSOLUTE/PATH/amiri_commercial_analytics_mcp/data"
}
}
}
}
```
Restart Claude Desktop after saving the config.
## Five-minute interview demo
Use this sequence rather than clicking around randomly:
1. **Trust first:** “Before we diagnose anything, run the data-quality checks.”
2. **Ambiguous case:** “Our return rate spiked. Prove it's real, then localize the root cause.”
3. **Commercial decision:** “SS26 is six weeks old. What should we chase vs mark down?”
4. **Cross-channel trap:** “Wholesale shipments look strong. Is consumer demand actually strong by partner?”
5. **Executive synthesis:** “Give me the weekly commercial flash and the decisions leadership should discuss.”
The interview point is not “look, AI.” The point is: **the same business definitions are reusable, tested, source-tagged, and callable from a natural-language interface.**
## Guardrails that are intentional
- No unrestricted `run_sql(sql)` tool for the LLM.
- Every tool response includes a `trust` block.
- Return rates are cohorted to **order date**, not return date.
- Duplicate return IDs are detected and deduped before rate math.
- Sell-through comparisons use **aligned weeks of life**.
- Retail comp growth excludes new stores.
- Wholesale sell-in is explicitly separated from sell-through.
- Clienteling output contains a **causal-selection warning**.
- Cannibalization uses a difference-in-differences framing and calls out its assumptions.
- Scenario/teaching assumptions are labeled rather than presented as facts.
## Repository layout
```text
amiri_commercial_analytics_mcp/
├── README.md
├── LICENSE
├── pyproject.toml
├── requirements.txt
├── .gitignore
├── config/
│ └── metric_catalog.csv
├── data/
│ ├── dim_product.csv
│ ├── dim_customer.csv
│ ├── dim_store.csv
│ ├── fct_orders.csv
│ ├── fct_order_lines.csv
│ ├── fct_returns.csv
│ ├── fct_inventory_snapshot.csv
│ ├── fct_wholesale_sellthrough.csv
│ └── dim_promo.csv
├── src/
│ ├── analytics.py
│ ├── cli.py
│ ├── make_data.py
│ ├── verify_reproducibility.py
│ └── mcp_server.py
├── tests/
│ └── test_analytics.py
├── scripts/
│ ├── setup_and_test.sh
│ └── run_inspector.sh
└── docs/
├── ARCHITECTURE.md
├── CODE_WALKTHROUGH.md
├── DEMO_QUESTIONS_DEEP_DIVE.md
├── INTERVIEW_DEMO.md
├── PROBLEM_MAP.md
├── LOCAL_SETUP.md
├── GOLDEN_QUESTIONS.md
├── architecture.svg
├── return_rootcause.svg
└── GITHUB_PUBLISH.md
```
## What I would say in the interview
> “I treated this as an operating-system problem, not a chatbot project. I modeled the commercial questions the role is responsible for — sell-through, markdown exposure, returns, comp stores, wholesale sell-through, clienteling, channel economics — as governed tools. The LLM can decide which tool to call, but it cannot invent a KPI definition or silently query arbitrary raw data. The demo uses synthetic data, but the production pattern is the same one I would put over tested dbt marts in BigQuery.”
MIT licensed.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues