Skip to main content
Glama
maevelynz

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

![AMIRI MCP architecture](docs/architecture.svg)

```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.