keplero-hotels
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@keplero-hotelsCerco una struttura pet-friendly vicino al mare."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
HotelAI
RAG-based hotel concierge assistant: turns a hotel catalogue PDF into structured, natural-language-searchable data, with LLM-assisted extraction, hybrid search on ChromaDB, and an MCP server.
PDF -> structured extraction -> CSV/JSONL -> embeddings + ChromaDB -> hybrid search -> RAG answer with page citationsExposed both as a web chat (FastAPI + React) and as an MCP tool for compatible clients (e.g. Claude Desktop).

Live demo
Backend API: https://hotelai-backend-qjwr.onrender.com — try
/api/healthFrontend: https://hotelaibywfr.netlify.app/
Runs on Render's and Netlify's free tiers: the backend spins down after inactivity, so the first request after a while can take up to ~50s to respond.
Related MCP server: Hotels MCP Server
What it includes
PDF -> structured data pipeline: dual parser (PyMuPDF for font-size-aware headers, pdfplumber for segmentation and bounding boxes) with
HotelRecord(Pydantic) as the canonical schema and per-page traceability for every field.LLM-assisted quality review: low-confidence fields are reviewed by Groq (default), with automatic fallback to Gemini; without any API key the pipeline stays fully deterministic and verifiable offline.
Hybrid search: Gemini embeddings on ChromaDB + lexical rerank on structured metadata.
Conversational RAG:
RAGEnginesynthesizes natural-language answers with per-hotel page citations (POST /api/chat).MCP server: the same search engine exposed as a tool (
search_hotels) for any MCP-compatible client.Web app: FastAPI backend + React/Vite frontend (dark theme), with live PDF upload and hot re-indexing.
39 tests, fully mocked (no API calls in the standard suite), plus an offline mode verifiable without any keys.
Tech stack
Python 3.11 · FastAPI · Pydantic v2 · ChromaDB · PyMuPDF · pdfplumber · FastMCP · Groq / Google Gemini · React 19 · Vite. Deploy: Render (backend) + Netlify (frontend).
Architecture
flowchart LR
PDF["Hotel PDF"] --> ING["Ingestion\nPyMuPDF + pdfplumber"]
ING --> REC["HotelRecord\n(Pydantic)"]
REC --> FILES[("CSV / JSONL")]
FILES --> IDX["Gemini embeddings\n+ ChromaDB indexing"]
IDX --> RET["Retriever\nhybrid search"]
RET --> RAG["RAGEngine\nGroq -> Gemini"]
RET --> MCP["MCP Server\nsearch_hotels()"]
RAG --> API["FastAPI\nPOST /api/chat"]
API --> UI["React/Vite chat"]
MCP --> CLIENT["MCP client\n(e.g. Claude Desktop)"]Indexing re-reads the CSV that was just written instead of reusing the records still held in memory: this is the explicit seam between extraction and search. Every vector document includes the record's structured metadata (excluding source/quality, kept for audit only); results are ranked with a hybrid vector + lexical-overlap score (vector_weight/metadata_weight in .env).
Detailed flow docs, covering both triggers (offline batch and live upload) — currently in Italian: user-doc/architecture-flow.md · user-doc/ingestion-flow.md.
Quick start
1. Setup
python -m venv .venv
.\.venv\Scripts\Activate.ps1
pip install -r requirements.txt
Copy-Item .env.example .env
git config core.hooksPath scripts/hooks.env holds real API keys and is gitignored; it must never be committed. core.hooksPath enables scripts/hooks/pre-commit, which refuses a commit that stages .env or that pastes a key-shaped literal into any other file — it's a local git config, so run that line again after any fresh clone. CI runs a second, repo-wide check (gitleaks) as a backstop.
2. Offline verification (no API key, no external calls)
$env:PYTHONPATH = "src"
python scripts/run_pipeline.py "data\raw\FileHotels.pdf" --offline
pytest -qWith the sample PDF: 19 blocks detected, 19 structured records, zero Groq/Gemini calls. Offline mode only produces CSV/JSONL: it doesn't build the Chroma index, which requires a configured embedding provider.
3. Full pipeline (real LLM and embeddings)
Set GOOGLE_API_KEY and/or GROQ_API_KEY in .env, then:
$env:PYTHONPATH = "src"
python scripts/run_pipeline.py "data\raw\FileHotels.pdf"4. Web app (chat)
$env:PYTHONPATH = "src"
python -m uvicorn api.main:app --reload --reload-dir src --port 8000
# --reload-dir src limits the watcher to source code: without it, files written
# by /api/ingest under data/ would restart the server mid-request.cd frontend
npm install
npm run devThe frontend runs on http://localhost:5173 and proxies /api/* to the backend on http://localhost:8000 (vite.config.js); the backend also keeps CORS open to localhost:5173 as a second line of defense. On Windows, double-click start.bat to launch backend and frontend together.
Endpoints: POST /api/chat (RAG answer), GET /api/hotels (canonical catalogue from data/processed/hotels_data.jsonl), POST /api/ingest (PDF upload from the sidebar: regenerates the CSV/index and hot-reloads the retriever), GET /api/health (Chroma connectivity + Groq/Gemini key presence). Assistant replies are rendered as Markdown (react-markdown + remark-gfm, hotel names in bold, lists); page citations [p. x-y] are shown as separate badges and stripped out of the text.
5. MCP server
$env:PYTHONPATH = "src"
python -m mcp_server.serverExposes the search_hotels(query: str) -> str tool, at most five Markdown results. Config for a desktop MCP client (or MCP Inspector):
{
"mcpServers": {
"hotelai": {
"command": "<absolute path to .venv\\Scripts\\python.exe>",
"args": ["-m", "mcp_server.server"],
"cwd": "<absolute path to the repository folder>",
"env": {"PYTHONPATH": "src"}
}
}
}command must point at the project's own .venv Python executable, not a generic python: many desktop clients (e.g. Claude Desktop on Windows) launch the process without inheriting a shell's activated-venv PATH, so "command": "python" can resolve to a system interpreter missing the project's dependencies (fastmcp, chromadb, ...) and silently fail the connection.
Example queries
Looking for a pet-friendly place near the sea.
Show me options with full board and a pool.
Which places suit a family with children best?
Looking for a place with a spa or wellness center.
Find places with family rooms and parking.
LLM providers, quotas and fallback
Groq (openai/gpt-oss-120b) is the default provider for reviewing low-confidence records and for RAG answers, with automatic fallback to Gemini (gemini-flash-latest) when Groq isn't configured or exhausts its retries. Without either key, extraction stays deterministic (local fallback) and RAG answers return a fixed fallback message, with no errors. Embeddings only use Gemini (gemini-embedding-001); without GOOGLE_API_KEY, indexing falls back to a deterministic offline embedder that is not semantically equivalent. Models, rate limits and retries (GOOGLE_MODEL, GROQ_MODEL, EMBEDDING_MODEL, REQUEST_DELAY_SECONDS, GEMINI_REQUESTS_PER_MINUTE, GROQ_REQUESTS_PER_MINUTE, MAX_RETRIES) are configurable in .env; Google 404/429/5xx errors are surfaced explicitly, with retry and backoff on 429 and 5xx.
Card grouping detects headers in the PDF text and associates the following page with them; if a catalogue doesn't preserve the expected headers, a structural "intro + page pairs" fallback kicks in. Hotel names aren't kept in hardcoded lists: they're extracted from the header and normalized only to fix obvious OCR artifacts.
Extracted data and quality
The JSONL file is the canonical, auditable store; the CSV is the interface between extraction and indexing. Each record can carry a numeric category, structured ratings (body, type, score/max), qualifiers, original text, source pages and a per-field confidence; unreadable scores stay null instead of being guessed. Deterministic extraction (PyMuPDF for name/locality, text heuristics/regex for the rest) runs first; text-based Groq (Gemini fallback) reviews low-confidence records, and Gemini Vision reads visual ratings when the text doesn't report them as numeric scores.
Testing
$env:PYTHONPATH = "src"
pytest -qThe sample PDF produces 19 CSV rows; source_pages makes every field traceable back to its original pages. Known limits: PDF text extraction order and some OCR artifacts may need visual review; the deterministic fallback is conservative and doesn't replace the model's semantic validation.
RAG retrieval eval
pytest covers plumbing and the deterministic criteria-reranking logic, but the offline embedder it uses for that is hash-based, not semantic — it can't tell you whether a natural-language query actually finds the right hotel. scripts/eval_rag.py does: it runs a small hand-verified set of queries (scripts/eval_queries.json, 12 cases) against the real committed index with real Gemini embeddings, and reports Recall@5.
$env:PYTHONPATH = "src"
python scripts/eval_rag.pyNeeds GOOGLE_API_KEY and spends real embedding quota, so it's not part of the automated test suite — run it manually when retrieval logic changes. Currently 12/12.
License
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections. Dates show when Glama detected each change.
No tool schema history has been recorded yet.
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Connectors
Hotel booking MCP server. Search, book, and manage reservations across 250K+ properties worldwide.
Remote ChromaDB vector database MCP server with streamable HTTP transport
Flight search MCP server providing search, pagination, and itinerary details for AI assistants.
Related MCP Servers
- FlicenseNot gradedqualityDmaintenanceMCP server that indexes a knowledge base into Chroma and provides search tools for retrieving document fragments via vector embeddings.-
- FlicenseNot gradedqualityDmaintenanceA Model Context Protocol (MCP) server that allows LLMs to search for hotels and destinations using the Booking.com API.28-
- FlicenseNot gradedqualityBmaintenanceLocal MCP server that provides a search_documents tool to query a RAG pipeline built with Ollama embeddings and ChromaDB, enabling Claude Desktop to retrieve relevant document chunks.-
- AlicenseAqualityCmaintenanceMCP server that exposes Cloudbeds occupancy, check-ins/check-outs, and reservations as natural language tools, with read-only access and secure credential storage.1MIT
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/workfromrome/HotelAI'
If you have feedback or need assistance with the MCP directory API, please join our Discord server