Skip to main content
Glama
AraksyaG

SmartPark Central MCP Server

by AraksyaG

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

graph.py (LangGraph agent), vector_store.py, tools.py

Vector database for information

Milvus (vector_store.py; Milvus Lite locally)

Static/dynamic data split (optional bonus)

Static → Milvus (knowledge_base.py); dynamic (prices, hours, availability) → SQLite/SQLAlchemy (dynamic_db.py)

Provide information to users

retriever tool + 3 dynamic-data tools (tools.py)

Collect user inputs for reservations

reservation.py (validated slot-filling) + submit_reservation tool

Guardrails against sensitive-data exposure

guardrails.py (Microsoft Presidio + regex fallback)

Evaluation (Recall@K, Precision, latency)

evaluation/evaluate.py

Second agent for the administrator

admin_agent.py (compose request + interpret reply)

Escalate reservation to a human

tools.py::submit_reservationreservation_store + channels

Send request / receive decision

channels.py (memory/email/REST) + admin_service.py (FastAPI)

Maintain agent-to-agent communication

reservation lifecycle in reservation_store.py, status tool

MCP server to write data to file

mcp_server.py (FastMCP) + recorder.py (secure core)

Record on approval (Name | Car | Period | Time)

admin_service.py approval hook → recorder/mcp_client

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:00

Security measures

  • Token auth — the recorder rejects writes without the correct MCP_AUTH_TOKEN.

  • Input sanitisation|, \n, \r are 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 outcome

Running the admin API

poetry run parking-admin-api          # serves http://localhost:8001

Example (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/decision

The 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 request
  • Static knowledge (general info, location, rules, booking process, FAQ) is embedded with text-embedding-3-small and 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.yml

Setup

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-ingest

MILVUS_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-ingest

Usage

poetry run parking-chat

Example 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 3

Produces 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_chatbot

The 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 PERSON etc., 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.

F
license - not found
-
quality - not tested
C
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

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

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