SmartPark Central MCP Server
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., "@SmartPark Central MCP ServerRecord a reservation: Jane Smith, car ABC123, 2026-07-20 10:00-18:00."
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.
SmartPark Central — MCP Server for Confirmed Reservations (Stage 3)
An intelligent assistant for a parking facility, built with LangChain and LangGraph on a Retrieval-Augmented Generation (RAG) architecture. The bot answers questions about the garage, looks up live prices / opening hours / availability, interactively collects reservation details, and protects personal data with a guardrails layer.
This repository is Stage 3 of the EPAM final project. It builds on the Stage 1
RAG chatbot and the Stage 2 human-in-the-loop approval flow by adding an MCP (Model
Context Protocol) server that records every approved reservation to a text file
in the format Name | Car Number | Reservation Period | Approval Time. The server is
secured (shared-token auth, input sanitisation, path confinement, atomic locked
writes). When the administrator approves a request, the confirmed booking is written
automatically — via the MCP server or an equivalent direct function call.
Features
Requirement (brief) | Where it lives |
RAG chatbot architecture |
|
Vector database for information | Milvus ( |
Static/dynamic data split (optional bonus) | Static → Milvus ( |
Provide information to users | retriever tool + 3 dynamic-data tools ( |
Collect user inputs for reservations |
|
Guardrails against sensitive-data exposure |
|
Evaluation (Recall@K, Precision, latency) |
|
Second agent for the administrator |
|
Escalate reservation to a human |
|
Send request / receive decision |
|
Maintain agent-to-agent communication | reservation lifecycle in |
MCP server to write data to file |
|
Record on approval ( |
|
Secure & resistant to unauthorised access | token auth, input sanitisation, path confinement, file locking |
Related MCP server: MCP Filesystem Server
MCP server (Stage 3)
MCP (Model Context Protocol) is an open standard for exposing tools to AI apps.
Our server (mcp_server.py, built with the official SDK's FastMCP) exposes one tool,
record_reservation, that appends a confirmed booking to a text file. The write logic
(recorder.py) is shared by the MCP path and a direct function-call fallback.
poetry run parking-mcp-server # run the MCP server (stdio transport)Flow: administrator approves a request (Stage 2 API) → the approval hook records it →
a line is appended to data/confirmed_reservations.txt:
Anna Smith | AB12CD | 2026-07-15 09:00 to 18:00 | 2026-07-11T10:00:00+00:00Security measures
Token auth — the recorder rejects writes without the correct
MCP_AUTH_TOKEN.Input sanitisation —
|,\n,\rare stripped so a value can't forge extra columns/rows (format injection).Path confinement — the target file must resolve inside the project
data/dir, blocking path traversal (../../etc/...).Atomic, locked appends — a thread lock plus an OS advisory file lock prevent corrupted/interleaved lines under concurrent approvals.
Set USE_MCP=true to record through the MCP server (client↔server over stdio);
USE_MCP=false (default) uses the equivalent direct call. The full stdio round-trip is
covered by an e2e test (RUN_MCP_E2E=1 pytest).
Human-in-the-loop flow (Stage 2)
user ──▶ chatbot (agent 1) ──collect details──▶ submit_reservation
│
save PENDING record (reservation_store)
│
notify admin (channel: memory/email/REST)
▼
administrator ──▶ Admin REST API (/pending, /decision)
│
AdminAgent (agent 2) interprets the reply
▼
reservation → APPROVED / REFUSED
│
user ──ask status──▶ chatbot ──check_reservation_status──▶ reports outcomeRunning the admin API
poetry run parking-admin-api # serves http://localhost:8001Example (the admin approves a request):
TOKEN=change-me-admin-token # set ADMIN_API_TOKEN in .env for real use
curl -s -H "Authorization: Bearer $TOKEN" http://localhost:8001/pending
curl -s -X POST -H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{"reply":"approve, looks fine","admin":"robert"}' \
http://localhost:8001/reservations/SP-ABC123/decisionThe reply field can be free text ("yes, that's fine" / "no, we're full") — the
AdminAgent interprets it into an approved / refused decision.
Architecture
┌──────────────────────────── LangGraph agent ───────────────────────────┐
user ──▶ query_or_respond ──(tool needed?)──▶ tools ──▶ generate ──▶ answer ──▶ user
│ (LLM decides) │ │ (grounded + PII-redacted)
│ │
└── no tool: answer directly ├─ search_parking_info ─▶ Milvus (static KB)
(e.g. next reservation Q) ├─ get_parking_prices ─┐
├─ get_working_hours ├▶ SQLite (dynamic)
├─ check_availability ─┘
└─ submit_reservation ─▶ validated requestStatic knowledge (general info, location, rules, booking process, FAQ) is embedded with
text-embedding-3-smalland stored in Milvus.Dynamic data (prices, hours, live availability) lives in SQLite and is queried exactly — never embedded, never hallucinated.
The LLM (Azure OpenAI
gpt-4o-mini) chooses which tool to call, then writes a grounded answer. Every retrieved chunk and every final answer passes through the guardrails so personal data cannot leak.
Project structure
Stage1_RAG_Chatbot/
├── src/parking_chatbot/
│ ├── config.py # settings from .env (pydantic-settings)
│ ├── llm.py # Azure chat + embedding model factories
│ ├── knowledge_base.py # load + chunk static markdown docs
│ ├── vector_store.py # Milvus build/load/retriever
│ ├── dynamic_db.py # SQLite schema, seeding, queries
│ ├── guardrails.py # PII detection + redaction (Presidio / regex)
│ ├── reservation.py # validated reservation model + slot-filling
│ ├── tools.py # LangChain tools bound to the agent
│ ├── graph.py # LangGraph agent (query_or_respond→tools→generate)
│ ├── chatbot.py # high-level Chatbot facade
│ └── cli.py # terminal chat REPL
├── data/
│ ├── static/ # knowledge base (markdown) → vector DB
│ └── dynamic/ # SQLite DB is created here
├── evaluation/ # eval dataset + Recall@K / Precision / MRR / latency
├── scripts/ingest.py # build vector store + seed SQL DB
├── tests/ # pytest suite (offline, LLM mocked)
├── docker-compose.yml # optional full Milvus server
└── .github/workflows/ci.ymlSetup
Prerequisites: Python 3.11/3.12, and — for anything that calls the model — an Azure OpenAI resource reachable from the EPAM VPN.
# 1. install dependencies (Poetry)
poetry install
# 2. configure credentials
cp .env.example .env
# then edit .env and fill in AZURE_OPENAI_API_KEY / AZURE_OPENAI_ENDPOINT
# 3. build the knowledge base + dynamic DB (needs VPN for embeddings)
poetry run parking-ingestMILVUS_URI defaults to a local file (./milvus_lite.db) — Milvus Lite, so no
server is needed. To use a full Milvus server instead:
docker compose up -d # starts Milvus on localhost:19530
# set MILVUS_URI=http://localhost:19530 in .env, then re-run parking-ingestUsage
poetry run parking-chatExample conversation:
You: what are your opening hours?
Assistant: SmartPark Central is open 24 hours a day, 7 days a week.
You: how much is daily parking for a normal car?
Assistant: Standard car parking is 24.00 USD per day.
You: I want to book a space
Assistant: Sure! What is your first name?
... (collects first name, last name, car number, period, confirms, submits)
You: what's the manager's phone number?
Assistant: I'm sorry, I can't share staff contact details. Please call our support
hotline on +1-555-0100.Evaluation
poetry run python evaluation/evaluate.py --k 3Produces evaluation/results/report.md and metrics.json with Recall@K,
Precision@K, MRR and latency (mean / p95). See the report for the
per-question breakdown.
Testing
poetry run pytest # 27 tests, fully offline (LLM + Milvus mocked)
poetry run pytest --cov=parking_chatbotThe suite never contacts Azure or a Milvus server, so it runs in CI without a VPN.
Guardrails / data protection
Personal data (staff phones, existing customer records, licence plates) may exist in the knowledge base. The guardrails layer redacts it twice: once when retrieved context is serialised for the model, and again on the final answer. Two backends:
Presidio (default): pretrained spaCy NLP model detects
PERSONetc., plus pattern recognisers for email / phone / credit card and a custom licence-plate recogniser.Regex fallback (
USE_PRESIDIO=false): no model download; covers email, phone, credit card and plates. Used in CI.
Tech choices in one line each
LangChain + LangGraph — required by the brief; LangGraph gives an explicit, inspectable state machine with built-in conversation memory.
Milvus — a production vector DB explicitly recommended by the brief; Milvus Lite makes local dev/testing zero-setup.
SQLite/SQLAlchemy for dynamic data — exact, cheap-to-update structured answers where embeddings would be the wrong tool.
Azure OpenAI
gpt-4o-mini+text-embedding-3-small— the models available through EPAM, matching the course material.Presidio — the open-source standard for PII detection using pretrained NLP.
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.
Latest Blog Posts
- 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/AraksyaG/epam-ai-engineering-stage3'
If you have feedback or need assistance with the MCP directory API, please join our Discord server