A production-style Agentic🤖 Retrieval-Augmented Generation system exposed through the Model Context Protocol.
This project is an end-to-end RAG assistant that can be connected to MCP-compatible clients such as Cursor. It takes a user question, rewrites it into a better retrieval query, searches a Qdrant vector database using BGE-small embeddings, reranks the retrieved chunks with a cross-encoder, generates a grounded answer with Gemini, verifies the answer against evidence, and selectively falls back to live web search through Bright Data when local evidence is weak or the question needs freshness.
- MCP server development with FastMCP
- Agentic RAG orchestration across retrieval, reranking, generation, and verification
- Semantic search using Qdrant and BGE-small embeddings
- Cross-encoder reranking for higher-quality evidence selection
- Gemini-powered query rewriting, answer generation, and evidence checking
- Selective Bright Data web fallback for recent or low-confidence questions
- Modular Python architecture with testable components
- Environment-based configuration and local Qdrant indexing
| Layer | Technology |
|---|---|
| Language | Python 3.10+ |
| MCP Server | FastMCP |
| Vector Database | Qdrant |
| Embedding Model | BAAI/bge-small-en-v1.5 |
| Embedding Library | Sentence Transformers |
| Similarity Search | Cosine distance |
| Reranker | cross-encoder/ms-marco-MiniLM-L-6-v2 |
| LLM | Google Gemini, default gemini-2.5-flash-lite |
| Web Fallback | Bright Data proxy search |
| Configuration | .env with python-dotenv |
| Testing | Pytest |
| Local Infrastructure | Docker for Qdrant |
flowchart TD
A[User asks a question in an MCP client] --> B[FastMCP server receives tool call]
B --> C{Tool selected}
C -->|search_knowledge| D[Rewrite query with Gemini]
C -->|answer_with_rag| D
C -->|web_search| W[Bright Data web search]
C -->|rebuild_knowledge_index| X[Rebuild Qdrant collection]
D --> E[Embed rewritten query with BGE-small]
E --> F[Search Qdrant collection]
F --> G[Return top semantic candidates]
G --> H[Cross-encoder reranking]
H --> I[Select strongest evidence chunks]
I --> J{Need web fallback?}
J -->|Recent/current query| W
J -->|Low or missing evidence| W
J -->|Evidence is enough| K[Generate grounded answer with Gemini]
W --> L[Convert web results into evidence]
L --> K
K --> M[Verify answer against evidence with Gemini]
M --> N{Fully supported?}
N -->|No| O[Regenerate with verifier feedback]
O --> M
N -->|Yes| P[Return answer, sources, verification, rewritten query]
X --> Y[Load seed FAQ chunks]
Y --> Z[Embed documents with BGE-small]
Z --> AA[Store vectors and metadata in Qdrant]
-
MCP client sends a request
A client such as Cursor calls one of the MCP tools exposed by
server.py. The main tools aresearch_knowledge,answer_with_rag,web_search, andrebuild_knowledge_index. -
FastMCP routes the tool call
server.pystays intentionally thin. It validates basic input types and forwards the real work toAgenticRagServiceinrag/service.py. -
The query is rewritten
rag/query_rewriter.pyuses Gemini to rewrite the user's question into a standalone retrieval query. If conversation context is provided, it is used only to resolve ambiguity. -
The rewritten query is embedded
rag/embeddings.pyloadsBAAI/bge-small-en-v1.5through Sentence Transformers and creates a normalized 384-dimensional query embedding. -
Qdrant retrieves candidate chunks
rag/vector_store.pysearches the Qdrant collection using cosine similarity. The first retrieval stage is optimized for recall and returns the initial top candidates. -
A cross-encoder reranks the evidence
rag/reranker.pyscores each query-document pair withcross-encoder/ms-marco-MiniLM-L-6-v2. This second stage improves precision and keeps the strongest evidence chunks. -
The service decides whether web search is needed
rag/service.pychecks for freshness hints such aslatest,recent,current,today,2025, or2026. It also falls back to web search if no evidence is found or the best rerank score is below the configured relevance threshold. -
Bright Data adds fresh external evidence when required
rag/web_search.pyperforms a Bright Data-backed Google search and converts useful search results into evidence-like chunks. This keeps web search selective instead of using it for every query. -
Gemini generates a grounded answer
rag/generator.pyasks Gemini to answer using only the supplied evidence. The output includes the final answer and the source chunks that support it. -
Gemini verifies the answer
rag/verifier.pychecks whether the generated answer is supported by the retrieved evidence. It classifies important claims as supported, partially supported, or unsupported. -
Unsupported answers get one repair pass
If verification fails, the service sends the verifier feedback back into the generator and asks Gemini to revise or remove unsupported claims.
-
The final response is returned
The MCP tool returns the answer, source metadata, verification summary, claim-level checks, rewritten query, and evidence count.
.
|-- AGENTS.md # Repository instructions for coding agents
|-- README.md # Project documentation
|-- server.py # FastMCP entry point and public MCP tools
|-- rag_code.py # Experimental or notebook-derived RAG code
|-- notebook.ipynb # Development notebook
|-- requirements.txt # Runtime and test dependencies
|-- .env.example # Safe environment variable template
|-- scripts/
| `-- rebuild_index.py # Recreates Qdrant collection and embeds seed data
|-- rag/
| |-- __init__.py
| |-- config.py # Environment-based settings
| |-- data.py # Demo ML FAQ seed corpus
| |-- embeddings.py # BGE-small embedding wrapper
| |-- generator.py # Gemini grounded answer generation
| |-- llm.py # Gemini client helpers
| |-- query_rewriter.py # Query rewriting stage
| |-- reranker.py # Cross-encoder reranking stage
| |-- schemas.py # Shared evidence data structures
| |-- service.py # Main agentic RAG orchestration
| |-- vector_store.py # Qdrant collection, ingest, and search logic
| `-- web_search.py # Bright Data web fallback
`-- tests/
|-- test_data.py # Seed corpus tests
|-- test_query_rewriter.py # Query rewriter unit tests
|-- test_reranker.py # Reranker unit tests
`-- test_verifier.py # Evidence verifier unit tests
Generated local folders such as hf_cache/, qdrant_storage/, __pycache__/, and .pytest_cache/ should stay out of commits.
| Tool | Purpose |
|---|---|
search_knowledge(query, conversation_context="") |
Rewrites the query, retrieves Qdrant candidates, reranks them, and returns evidence chunks. |
answer_with_rag(query, conversation_context="") |
Runs the full agentic RAG pipeline: rewrite, retrieve, rerank, optionally web search, generate, verify, and repair. |
web_search(query) |
Runs a Bright Data-backed web search for recent or external information. |
rebuild_knowledge_index() |
Recreates the Qdrant collection and indexes the seed knowledge base. |
Create and activate a virtual environment:
python -m venv .venv
source .venv/bin/activate
pip install -r requirements.txtCreate a local environment file:
cp .env.example .envUpdate .env with your local or cloud configuration:
QDRANT_URL=http://localhost:6333
QDRANT_COLLECTION=ml_faq_collection
GEMINI_API_KEY=your_gemini_api_key
GEMINI_MODEL=gemini-2.5-flash-lite
BRIGHT_DATA_USERNAME=your_bright_data_username
BRIGHT_DATA_PASSWORD=your_bright_data_passwordOptional local model cache:
export HF_HOME="$PWD/hf_cache"Start Qdrant:
docker run --name local-qdrant \
-p 6333:6333 -p 6334:6334 \
-v "$(pwd)/qdrant_storage:/qdrant/storage:z" \
qdrant/qdrantBuild the vector index:
python scripts/rebuild_index.pyStart the MCP server:
python server.pyBy default, the MCP endpoint runs at:
http://127.0.0.1:8080/mcp
Create .cursor/mcp.json in your workspace:
{
"mcpServers": {
"mcp-powered-agentic-rag": {
"url": "http://127.0.0.1:8080/mcp"
}
}
}Example prompt in Cursor:
Use answer_with_rag to explain how overfitting can be prevented.
Run the unit test suite:
pytest -qCheck Python syntax:
python -m compileall -q server.py rag scripts testsThe tests are focused on local behavior and use fakes where possible, so the default test run avoids live Gemini, Bright Data, and Qdrant dependencies.
| Variable | Description | Default |
|---|---|---|
QDRANT_URL |
Qdrant endpoint | http://localhost:6333 |
QDRANT_API_KEY |
Qdrant Cloud API key, optional for local Qdrant | Empty |
QDRANT_COLLECTION |
Vector collection name | ml_faq_collection |
GEMINI_API_KEY |
Gemini API key | Required for LLM stages |
GEMINI_MODEL |
Gemini model used for rewrite, generation, and verification | gemini-2.5-flash-lite |
EMBEDDING_MODEL |
Sentence Transformers embedding model | BAAI/bge-small-en-v1.5 |
RERANKER_MODEL |
Cross-encoder reranking model | cross-encoder/ms-marco-MiniLM-L-6-v2 |
RAG_INITIAL_TOP_K |
Number of semantic candidates retrieved from Qdrant | 20 |
RAG_FINAL_TOP_K |
Number of reranked chunks used as evidence | 5 |
RAG_MIN_RELEVANCE_SCORE |
Threshold for triggering low-confidence web fallback | 0.15 |
BRIGHT_DATA_HOST |
Bright Data proxy host | brd.superproxy.io |
BRIGHT_DATA_PORT |
Bright Data proxy port | 33335 |
BRIGHT_DATA_USERNAME |
Bright Data username | Required for web search |
BRIGHT_DATA_PASSWORD |
Bright Data password | Required for web search |
MCP_HOST |
MCP server host | 127.0.0.1 |
MCP_PORT |
MCP server port | 8080 |
This repository shows more than a basic chatbot wrapper. It demonstrates practical backend AI engineering: modular orchestration, retrieval quality improvements, model-based validation, MCP tool exposure, vector database integration, local infrastructure, test coverage, and secure configuration practices.
The most important engineering decision is that the system does not blindly trust the first generated answer. It retrieves evidence, reranks it, generates a grounded response, verifies the claims, and performs a repair pass when the answer is not fully supported.
- Keep
.envout of Git. - Never commit Gemini, Qdrant, or Bright Data credentials.
- Rotate any key exposed in logs, screenshots, commits, or chat.
- Keep web fallback selective so external search is used only when the local knowledge base is insufficient or freshness is required. RAG system with FastMCP, Qdrant, BGE embeddings, cross-encoder reranking, Gemini verification, and Bright Data web fallback.