Frontline Copilot MCP Server
by miguelpomarm
README.md
# Frontline Copilot
**AI-powered review triage for retail store managers.**
An always-on system that ingests customer reviews from any source, uses Claude
to classify them by category and severity, and routes actionable ones to the
store manager's Airtable task list — with real-time Slack alerts for critical
issues (food safety, staff conduct, health risks).
Also ships as an **MCP server** so store managers can query and triage
conversationally from Claude Desktop.
> Inspired by the emerging category of AI copilots for store operations.
---
## The problem
Store managers at multi-location retail chains drown in signal from customer
reviews. Most are noise (praise or minor grumbles). A few are urgent (food
safety, discrimination, injury risk). Most tools require the manager to *read*
everything to find the few that matter — a losing battle at scale.
Frontline Copilot inverts this. Claude reads everything; the manager only sees
what needs action.
---
## How it works
```
┌────────────┐ ┌──────────────┐ ┌────────────┐ ┌────────────┐
│ Reviews │──▶│ Classifier │──▶│ Airtable │──▶│ Slack │
│ (JSON / │ │ (Claude API, │ │ (task │ │ (critical │
│ Google) │ │ tool use) │ │ tracker) │ │ alerts) │
└────────────┘ └──────────────┘ └────────────┘ └────────────┘
│
▼
┌──────────────┐
│ MCP server │◀── Claude Desktop, Cursor, ...
│ (3 tools) │
└──────────────┘
```
Each review is classified into one of nine categories with a severity from
1 (positive) to 5 (critical). Reviews at severity ≥ 3 become Airtable tasks;
severity ≥ 4 additionally fire a Slack alert.
---
## Screenshots
### End-to-end pipeline run
21 reviews processed in ~60 seconds. 7 tasks created, 4 real-time critical alerts.

### Airtable — task board
Tasks sorted by severity, colored by category. This is what a store manager sees.

### Airtable — Kanban view
Same data, grouped by category. Distribution of issues at a glance.

### Slack — real-time critical alerts
Block Kit cards with action-first layout and direct link to the Airtable task.

---
## Tech stack
- **Python 3.10+** — dataclasses, `str | None` union types, pathlib
- **Anthropic Claude API** — classification via tool use (`claude-haiku-4-5`)
- **Airtable REST API** — task tracker, called with raw `requests`
- **Slack Incoming Webhooks** — Block Kit for rich alert cards
- **MCP (Model Context Protocol)** — conversational interface via FastMCP
- **Adapter pattern** for review sources (Mock ships; Google Places stubbed)
Only three third-party deps: `anthropic`, `requests`, `mcp`. Everything else
is standard library.
---
## Quick start
```bash
# 1. Clone and install
git clone https://github.com/miguelpomarm/frontline-copilot
cd frontline-copilot
python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt
# 2. Configure secrets
cp .env.example .env
# ... edit .env with your keys (see setup section below)
# 3. Run the pipeline
python triage.py
# 4. Launch as an MCP server (optional)
python mcp_server.py
```
---
## Setup (one-time, ~10 minutes)
### 1. Anthropic API key
Get one at <https://console.anthropic.com/>. The free tier is enough for demo
runs — 21 reviews cost ~$0.03.
### 2. Airtable base
Create a new base with a table named `Tasks` and these fields (exact names):
| Field | Type |
|---|---|
| Review ID | Single line text (primary field) |
| Store | Single line text |
| Category | Single select — populate with the 9 taxonomy values |
| Severity | Number (integer) |
| Summary | Long text |
| Review Text | Long text |
| Author | Single line text |
| Date | Date |
| Status | Single select — `Open`, `In Progress`, `Resolved` |
Then generate a personal access token at <https://airtable.com/create/tokens>
with `data.records:read` and `data.records:write` scopes on your base. Copy
the token and the base ID (starts with `app...`, found in the URL of your base).
### 3. Slack Incoming Webhook
Create a Slack app at <https://api.slack.com/apps>. Enable Incoming Webhooks,
add a new webhook pointing to whichever channel should receive critical
alerts, and copy the webhook URL.
### 4. Fill in `.env`
```bash
ANTHROPIC_API_KEY=sk-ant-...
AIRTABLE_API_KEY=pat...
AIRTABLE_BASE_ID=app...
AIRTABLE_TABLE_NAME=Tasks
SLACK_WEBHOOK_URL=https://hooks.slack.com/services/...
```
### 5. First run
```bash
python triage.py --limit 3 --dry-run # sanity check, no side effects
python triage.py --limit 3 # small live run
python triage.py # full 21 reviews
```
---
## MCP integration (Claude Desktop)
Add this to
`~/Library/Application Support/Claude/claude_desktop_config.json` (macOS) and
restart Claude Desktop:
```json
{
"mcpServers": {
"frontline-copilot": {
"command": "python",
"args": ["/absolute/path/to/frontline-copilot/mcp_server.py"]
}
}
}
```
Then, inside Claude Desktop:
> *"How is Aurora Times Square doing right now?"*
Claude will invoke `get_store_health("times_square")`, hit Airtable, and
respond with the current snapshot — open tasks, critical count, top category.
---
## Design decisions
Deliberate choices worth calling out to a reviewer:
**Closed taxonomy + `Other` bucket**
Categories are a fixed enum, not free-form. This guarantees consistent routing
and metrics. `Other` is the escape hatch — reviewed periodically to expand the
taxonomy based on real data instead of upfront guessing.
**Tool use over prompt engineering**
Claude returns structured output via a tool schema with enum enforcement.
This eliminates parsing bugs and prevents the LLM from hallucinating a
category outside the taxonomy.
**Haiku 4.5 as the default model**
For a well-scoped classification task, Haiku is fast (sub-second), cheap
(~$0.001 per review), and accurate enough. In production this decision alone
saves thousands of dollars/month at moderate volume.
**Adapter pattern for review sources**
`ReviewSource` is an abstract interface. Ships with `MockSource` and a
documented `GooglePlacesSource` stub. Swapping to Yelp, TrustPilot, or a
proprietary feed is a new subclass — the rest of the pipeline is untouched.
**Idempotency by review ID**
Reprocessing the same reviews doesn't create duplicate tasks. Airtable is
checked before every create.
**Severity thresholds as tunable constants**
`ACTION_THRESHOLD` and `ALERT_THRESHOLD` are module-level. Customers with
different tolerances change two numbers, not code.
**Sync over async for the MVP**
Processes 21 reviews sequentially in ~40s. The async variant is ~15 lines to
swap (`AsyncAnthropic` + `asyncio.gather` with a semaphore for rate limits).
For this volume, readability wins over speed.
**Text over stars**
The prompt explicitly tells Claude to weigh the review text over the star
rating. A 4-star review mentioning food safety is severity 5, not 2.
---
## Roadmap (not implemented)
- **FastAPI webhook endpoint** (`POST /webhook/review`) for real-time ingestion
instead of batch runs.
- **`GooglePlacesSource`** — the adapter interface is done, live implementation
is ~1 hour of API integration + retry logic.
- **Rate-limit-aware async batching** for high-volume production.
- **End-to-end tests** (Playwright / pytest with recorded API interactions)
verifying the Airtable/Slack side effects.
- **Per-customer configurable thresholds** via `config.yaml`.
---
## License
MIT — see [LICENSE](LICENSE).
---
Built by [Miguel Pomar Martínez](https://linkedin.com/in/miguelpomarm) as a
technical portfolio piece.
This server cannot be deployed
Maintenance
ActivityMaintained
ResponsivenessNo issues