abdussamadbello/meridian-support-chatbot
0
Meridian Electronics — AI Support Chatbot
A production-ready prototype of a customer-support chatbot for Meridian Electronics — a retailer of monitors, keyboards, printers, networking gear, and accessories. Built with Chainlit + LangGraph + MCP, deployable to HuggingFace Spaces and AWS Fargate.
Live Demo
- HuggingFace Spaces: https://huggingface.co/spaces/abdussamadbello/meridian-support-chatbot
- AWS (ALB): see
aws cloudformation describe-stacks --stack-name ChainlitBaseService --query 'Stacks[0].Outputs[?OutputKey==\AlbDnsName\]'aftermake deploy
<!-- TODO: add screenshot of chat after auth + create_order approval card -->
What it does
- Authenticate the customer in-conversation via email + 4-digit PIN, calling
verify_customer_pinon the MCP server. - Browse products (
list_products,search_products,get_product) across monitors, keyboards, printers, networking gear, and accessories. - Place orders via
create_order— gated by an explicit Approve/Reject card (LangGraph HITL) before any mutation reaches the backend. - Look up orders (
list_orders,get_order) for the authenticated customer.
Test customers
Architecture
Browser ─ WebSocket ─► Chainlit (Docker) ─► LangGraph
│
┌───────────────┴────────────────┐
▼ ▼
litellm → OpenRouter Streamable-HTTP MCP
(Gemini 2.5 Flash) order-mcp-74afyau24q-uc.a.run.appLangGraph workflow: intent → rag (short-circuited) → tool_approval ⟂ mcp_execution → final_response. The tool_approval node uses LangGraph's interrupt() for human-in-the-loop confirmation on mutating tools.
Decisions worth calling out
- App-owned MCP session, not Chainlit's panel UI: the order MCP is opened in
on_chat_startand stored incl.user_session. Users don't have to paste a URL. - Auto-approve allowlist for read-only MCP tools (
verify_customer_pin,list_products,search_products,get_product,get_customer,list_orders,get_order). The mutating tool (create_order) hits the HITL gate. Seeapp/graph/nodes/tool_approval.py. - No RAG in the demo: the MCP server is the source of truth for products and orders. Adding a retrieval layer would introduce a second secret (embeddings) and risk stale answers. The
ragnode short-circuits viaDISABLE_RAG=1. - Open access on HF Spaces: customer identity is established by the in-chat email+PIN flow, not a Chainlit login wall. To enable a shared password gate, set
APP_PASSWORD_HASH+CHAINLIT_AUTH_SECRET.
Limitations / what I'd improve
- PINs travel through chat history (SQLite). Production needs a separate auth modal or tokenized session cookies.
- Tests for the new intent labels were not updated within the time budget. The original 19-test scaffold validates the agentic mechanics; a follow-up should re-align test fixtures.
- A curated FAQ corpus + retrieval (re-enabling RAG) would reduce MCP roundtrips on common questions.
- Cognito + ALB OIDC for the AWS deploy.
- Observability: hook up LangSmith / structured logs to monitor tool-call success rates and authentication friction.
Local dev
cp .env.example .env
# put your OPENROUTER_API_KEY in .env
make install
make dev # → http://localhost:8000Deploy
HuggingFace Spaces (primary)
- Create a Docker Space.
- Push this repo as the Space repo.
- In Settings → Variables and secrets, add:
OPENROUTER_API_KEY(secret)LITELLM_MODEL=openrouter/google/gemini-2.5-flash- Wait for build, open the URL.
The Space picks up app_port: 7860 from this README's frontmatter; the Dockerfile honors ${PORT:-7860} so no extra config is required.
AWS (CDK)
cd infra && cdk bootstrap # one-time per account/region
make deploy # ~30 min, ~$42/mo idle
# populate Secrets Manager with OPENROUTER_API_KEY + LITELLM_MODEL
aws ecs update-service --force-new-deployment ...See CLAUDE.md for the full architecture notes.
