A full-stack application that lets users upload documents, chat with an AI agent that retrieves relevant information from those documents, and manage data categories.
| Feature | Description |
|---|---|
| Upload Files | Upload .txt documents and assign them to a category (cars or addresses) |
| Chat | Ask questions — the AI agent retrieves relevant chunks from your uploaded documents and answers using GPT-4.1 |
| Remove Category | Delete all vector data stored under a specific namespace/category |
┌──────────────────────────────────────────────────┐
│ Frontend (React 19 + Vite) │
│ │
│ ┌────────────┐ ┌──────────┐ ┌───────────────┐ │
│ │ Upload │ │ Chat │ │ Remove │ │
│ │ File │ │ Page │ │ Category │ │
│ └────────────┘ └──────────┘ └───────────────┘ │
└───────────────────────┬──────────────────────────┘
│ HTTP / REST
▼
┌──────────────────────────────────────────────────┐
│ FastAPI Backend (port 8000) │
│ │
│ POST /api/v1/upload │
│ DELETE /api/v1/delete-namespace │
│ POST /api/v1/agent-response │
│ │
│ ┌────────────────────────────────────────────┐ │
│ │ LangGraph Agent (GPT-4.1 via OpenAI) │ │
│ │ • Loads conversation history (Postgres) │ │
│ │ • Connects to MCP Server for tools │ │
│ │ • ContentFilter middleware (security) │ │
│ └────────────────────┬───────────────────────┘ │
└───────────────────────┼──────────────────────────┘
┌─────────────┼────────────────┐
▼ ▼ ▼
┌─────────────┐ ┌──────────┐ ┌──────────────┐
│ MCP Server │ │Postgres │ │ Celery │
│ (port 9000)│ │(memory) │ │ Worker │
│ │ │ │ │ │
│ Tools: │ │ Thread │ │ Async file │
│ • namespaces│ │ checkpoint│ │ processing │
│ • search_ │ │ storage │ │ & embedding │
│ cars │ └──────────┘ └──────┬───────┘
│ • search_ │ │
│ addresses │ ┌──────────────┘
└──────┬──────┘ ▼
│ ┌──────────┐
│ │ Redis │
│ │ (broker) │
│ └──────────┘
▼
┌─────────────┐
│ Pinecone │
│ (vectors) │
│ │
│ Embedding: │
│ llama-text- │
│ embed-v2 │
└─────────────┘
| Layer | Technology |
|---|---|
| API Framework | FastAPI |
| AI Agent | LangChain + LangGraph |
| LLM | OpenAI GPT-4.1 |
| Vector Store | Pinecone (llama-text-embed-v2 embeddings, cosine similarity) |
| Conversation Memory | LangGraph Postgres Checkpointer |
| Async Tasks | Celery + Redis |
| MCP Server | FastMCP (port 9000) |
| Database | PostgreSQL 17 |
| Message Broker | Redis 7 |
| Layer | Technology |
|---|---|
| Framework | React 19 |
| Routing | React Router 7 |
| Styling | Tailwind CSS 4 |
| Build Tool | Vite |
| Language | TypeScript |
- User sends a question from the Chat page
- Frontend
POST /api/v1/agent-response?question=...&thread_id=default - Backend loads conversation history from PostgreSQL (by
thread_id) - LangGraph agent initialises with GPT-4.1 and connects to the MCP Server
- Agent calls
retrive_all_name_spaces()to discover available categories - Agent decides which category the question is about (cars or addresses)
- Agent calls
search_cars_vectors()orsearch_addresses_vectors()→ Pinecone returns top 3 semantic matches - GPT-4.1 generates a final answer using the retrieved context
- Conversation state saved back to PostgreSQL
{ "answer": "..." }returned to the frontend
- User selects a file and category in the Upload page
- Frontend
POST /api/v1/upload?category=carswithmultipart/form-data - FastAPI enqueues a Celery task (via Redis broker)
- Celery worker processes the file:
- Splits text into ~200-character chunks
- Embeds each chunk with Pinecone's
llama-text-embed-v2 - Stores vectors under the matching namespace (
carsoraddresses)
- Success response returned
mcp_server/
├── backend/
│ ├── app/
│ │ ├── main.py # FastAPI app + CORS + router
│ │ ├── routes.py # 3 API endpoints
│ │ ├── agent_logic.py # LangGraph agent, upload logic, namespace removal
│ │ ├── mcp_server.py # FastMCP server with 3 tools
│ │ ├── celery_tasks.py # Async Celery tasks for file processing
│ │ ├── pinecone_client.py # Pinecone connection + embedding
│ │ ├── schemas.py # Pydantic request/response models
│ │ ├── middleware.py # ContentFilterMiddleware
│ │ ├── logger.py # Coloured logging
│ │ └── aws_secretes.py # AWS Secrets Manager integration
│ ├── docker-compose.yml # PostgreSQL + Redis + FastAPI + Celery + MCP
│ ├── Dockerfile
│ └── pyproject.toml
├── frontend/
│ ├── src/
│ │ ├── App.tsx # BrowserRouter + route definitions
│ │ ├── pages/
│ │ │ ├── UploadFilePage.tsx
│ │ │ ├── ChatPage.tsx
│ │ │ └── RemoveCategoryPage.tsx
│ │ └── components/
│ │ ├── Nav.tsx # Hamburger sidebar navigation
│ │ ├── Layout.tsx
│ │ └── UploadFile.tsx
│ ├── .env # VITE_SERVER_URL=http://localhost:8000
│ └── vite.config.ts
└── README.md
cd backend
docker compose up --buildThis starts 5 services:
fastapi— API server on port 8000mcp_server— MCP tool server on port 9000celery_worker— async task processorpostgres— PostgreSQL 17 on port 5432redis— Redis 7 on port 6379
cd frontend
npm install
npm run devApp runs on http://localhost:5173.
Backend (via Docker or .env):
| Variable | Description |
|---|---|
OPENAI_API_KEY |
OpenAI API key |
PINECONE_API_KEY |
Pinecone API key |
POSTGRES_USER |
PostgreSQL username |
POSTGRES_PASSWORD |
PostgreSQL password |
POSTGRES_HOST |
PostgreSQL host |
POSTGRES_PORT |
PostgreSQL port |
POSTGRES_DB |
PostgreSQL database name |
Frontend (.env):
| Variable | Description |
|---|---|
VITE_SERVER_URL |
Backend base URL (default: http://localhost:8000) |
Upload a file and embed it into the vector store.
| Parameter | Type | Location | Description |
|---|---|---|---|
user_file |
file | form-data | The file to upload |
category |
cars | addresses |
query | Target namespace |
Response: { "success": "..." }
Send a question to the AI agent.
| Parameter | Type | Location | Description |
|---|---|---|---|
question |
string (max 100) | query | The user's question |
thread_id |
string | query | Conversation ID for memory (default: "default") |
Response: { "answer": "..." }
Remove all vectors stored under a category.
| Parameter | Type | Location | Description |
|---|---|---|---|
category |
string (max 50) | query | Namespace to delete |
Response: { "response": "..." }